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
|
@@ -3,15 +3,12 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import {
|
|
6
|
+
import { parseBundleRef } from "../../core/asset/asset-ref.js";
|
|
7
7
|
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
8
|
-
import { asNonEmptyString
|
|
8
|
+
import { asNonEmptyString } from "../../core/common.js";
|
|
9
|
+
import { loadUserConfig } from "../../core/config/config.js";
|
|
9
10
|
import { isVerbose, warn } from "../../core/warn.js";
|
|
10
|
-
import { buildFileContext, buildRenderContext, getRenderer, runMatchers } from "../walk/file-context.js";
|
|
11
|
-
import { applyMetadataContributors } from "./metadata-contributors.js";
|
|
12
11
|
export const SCOPE_KEYS = ["user", "agent", "run", "channel"];
|
|
13
|
-
// ── Load / Write ────────────────────────────────────────────────────────────
|
|
14
|
-
const STASH_FILENAME = ".stash.json";
|
|
15
12
|
// ── Quality semantics (v1 spec §4.2) ────────────────────────────────────────
|
|
16
13
|
/**
|
|
17
14
|
* Well-known quality values. `generated`, `curated`, and `enriched` are included in
|
|
@@ -50,49 +47,12 @@ export function _resetUnknownQualityWarnings() {
|
|
|
50
47
|
export function isProposedQuality(quality) {
|
|
51
48
|
return quality === "proposed";
|
|
52
49
|
}
|
|
53
|
-
export function stashFilePath(dirPath) {
|
|
54
|
-
return path.join(dirPath, STASH_FILENAME);
|
|
55
|
-
}
|
|
56
|
-
export function loadStashFile(dirPath, options) {
|
|
57
|
-
const filePath = stashFilePath(dirPath);
|
|
58
|
-
if (!fs.existsSync(filePath))
|
|
59
|
-
return null;
|
|
60
|
-
try {
|
|
61
|
-
const raw = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
62
|
-
if (!raw || !Array.isArray(raw.entries))
|
|
63
|
-
return null;
|
|
64
|
-
const entries = [];
|
|
65
|
-
for (const e of raw.entries) {
|
|
66
|
-
const validated = validateStashEntry(e);
|
|
67
|
-
if (validated) {
|
|
68
|
-
if (options?.requireFilename && !validated.filename)
|
|
69
|
-
continue;
|
|
70
|
-
entries.push(validated);
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
const name = typeof e === "object" && e !== null && typeof e.name === "string"
|
|
74
|
-
? e.name
|
|
75
|
-
: "(unknown)";
|
|
76
|
-
warn(`Warning: Skipping invalid entry "${name}" in ${filePath}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return entries.length > 0 ? { entries } : null;
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
export function writeStashFile(dirPath, stash) {
|
|
86
|
-
const filePath = stashFilePath(dirPath);
|
|
87
|
-
writeFileAtomic(filePath, `${JSON.stringify(stash, null, 2)}\n`);
|
|
88
|
-
}
|
|
89
50
|
/**
|
|
90
|
-
* Validate and normalize a raw object into a `
|
|
51
|
+
* Validate and normalize a raw object into a `IndexDocument`.
|
|
91
52
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* rejected as invalid.
|
|
53
|
+
* Open type token: `entry.type` accepts any non-empty string. Type ownership
|
|
54
|
+
* and capability decisions belong to the adapter; this format-neutral
|
|
55
|
+
* projection must not reject a value merely because AKM does not own it.
|
|
96
56
|
*/
|
|
97
57
|
export function validateStashEntry(entry) {
|
|
98
58
|
if (typeof entry !== "object" || entry === null)
|
|
@@ -100,7 +60,7 @@ export function validateStashEntry(entry) {
|
|
|
100
60
|
const e = entry;
|
|
101
61
|
if (typeof e.name !== "string" || !e.name)
|
|
102
62
|
return null;
|
|
103
|
-
if (typeof e.type !== "string" || !
|
|
63
|
+
if (typeof e.type !== "string" || !e.type)
|
|
104
64
|
return null;
|
|
105
65
|
const result = {
|
|
106
66
|
name: e.name,
|
|
@@ -182,6 +142,11 @@ export function validateStashEntry(entry) {
|
|
|
182
142
|
const sources = normalizeNonEmptyStringList(e.sources);
|
|
183
143
|
if (sources)
|
|
184
144
|
result.sources = sources;
|
|
145
|
+
// SPEC-6: `category` must survive the projection. Non-string values are
|
|
146
|
+
// dropped, not coerced.
|
|
147
|
+
if (typeof e.category === "string" && e.category.trim().length > 0) {
|
|
148
|
+
result.category = e.category.trim();
|
|
149
|
+
}
|
|
185
150
|
if (typeof e.beliefState === "string" && e.beliefState.trim().length > 0) {
|
|
186
151
|
result.beliefState = e.beliefState.trim();
|
|
187
152
|
}
|
|
@@ -197,9 +162,6 @@ export function validateStashEntry(entry) {
|
|
|
197
162
|
if (typeof e.generation === "number" && Number.isFinite(e.generation) && e.generation > 0) {
|
|
198
163
|
result.generation = Math.floor(e.generation);
|
|
199
164
|
}
|
|
200
|
-
const sourceRefs = normalizeNonEmptyStringList(e.sourceRefs);
|
|
201
|
-
if (sourceRefs)
|
|
202
|
-
result.sourceRefs = sourceRefs;
|
|
203
165
|
const currentBeliefRefs = normalizeNonEmptyStringList(e.currentBeliefRefs);
|
|
204
166
|
if (currentBeliefRefs)
|
|
205
167
|
result.currentBeliefRefs = currentBeliefRefs;
|
|
@@ -218,6 +180,11 @@ export function validateStashEntry(entry) {
|
|
|
218
180
|
if (typeof e.derivedFrom === "string" && e.derivedFrom.trim().length > 0) {
|
|
219
181
|
result.derivedFrom = e.derivedFrom.trim();
|
|
220
182
|
}
|
|
183
|
+
// SPEC-8: `bodyOpening` must survive the projection. The extractor already
|
|
184
|
+
// trimmed and capped it at capture time.
|
|
185
|
+
if (typeof e.bodyOpening === "string" && e.bodyOpening.trim().length > 0) {
|
|
186
|
+
result.bodyOpening = e.bodyOpening;
|
|
187
|
+
}
|
|
221
188
|
if (typeof e.scope === "object" && e.scope !== null && !Array.isArray(e.scope)) {
|
|
222
189
|
const scope = normalizeScopeObject(e.scope);
|
|
223
190
|
if (scope)
|
|
@@ -308,6 +275,45 @@ function normalizeIntent(value) {
|
|
|
308
275
|
function normalizeStringListOrUndefined(value) {
|
|
309
276
|
return normalizeNonEmptyStringList(value);
|
|
310
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Normalize a current derived-memory parent ref to its `memories/<name>`
|
|
280
|
+
* conceptId for the `derived_from` column. Returns `undefined` for a non-memory
|
|
281
|
+
* or bare value so the caller can inspect the current `derivedFrom` key.
|
|
282
|
+
*/
|
|
283
|
+
function normalizeMemoryBackref(value) {
|
|
284
|
+
if (!value)
|
|
285
|
+
return undefined;
|
|
286
|
+
try {
|
|
287
|
+
const parsed = parseBundleRef(value);
|
|
288
|
+
return parsed.fragment === undefined && parsed.conceptId.startsWith("memories/") ? parsed.conceptId : undefined;
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Resolve a derived memory's parent conceptId from its current `source:` backref
|
|
296
|
+
* or, failing that, its bare `derivedFrom: <name>` frontmatter key.
|
|
297
|
+
*/
|
|
298
|
+
function derivedFromConceptId(source, derivedFrom) {
|
|
299
|
+
const fromSource = normalizeMemoryBackref(source);
|
|
300
|
+
if (fromSource)
|
|
301
|
+
return fromSource;
|
|
302
|
+
const rawDerivedFrom = derivedFrom?.trim();
|
|
303
|
+
if (!rawDerivedFrom)
|
|
304
|
+
return undefined;
|
|
305
|
+
const qualified = normalizeMemoryBackref(rawDerivedFrom);
|
|
306
|
+
if (qualified)
|
|
307
|
+
return qualified;
|
|
308
|
+
if (rawDerivedFrom.includes(":") || rawDerivedFrom.includes("//"))
|
|
309
|
+
return undefined;
|
|
310
|
+
try {
|
|
311
|
+
return parseBundleRef(`memories/${rawDerivedFrom}`).conceptId;
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
311
317
|
export function applyCuratedFrontmatter(entry, fmData) {
|
|
312
318
|
const description = asNonEmptyString(fmData.description);
|
|
313
319
|
if (description) {
|
|
@@ -342,6 +348,12 @@ export function applyCuratedFrontmatter(entry, fmData) {
|
|
|
342
348
|
const quality = asNonEmptyString(fmData.quality);
|
|
343
349
|
if (quality)
|
|
344
350
|
entry.quality = normalizeQuality(quality);
|
|
351
|
+
// SPEC-6 capture step: the `category:` frontmatter key (e.g. `convention`,
|
|
352
|
+
// `meta` on facts) must land on the indexed entry so category-keyed
|
|
353
|
+
// policies can see it. Trimmed; blank/non-string values are ignored.
|
|
354
|
+
const category = asNonEmptyString(fmData.category);
|
|
355
|
+
if (category)
|
|
356
|
+
entry.category = category;
|
|
345
357
|
const beliefState = asNonEmptyString(fmData.beliefState);
|
|
346
358
|
if (beliefState)
|
|
347
359
|
entry.beliefState = beliefState;
|
|
@@ -351,17 +363,12 @@ export function applyCuratedFrontmatter(entry, fmData) {
|
|
|
351
363
|
const contradictedBy = normalizeStringListOrUndefined(fmData.contradictedBy);
|
|
352
364
|
if (contradictedBy)
|
|
353
365
|
entry.contradictedBy = contradictedBy;
|
|
354
|
-
// R5 — consolidation
|
|
355
|
-
//
|
|
356
|
-
// improve pipeline; captured into the index so the collapse detector can
|
|
357
|
-
// count over-generation assets and follow merges without filesystem reads.
|
|
366
|
+
// R5 — consolidation generation depth is captured so the collapse detector
|
|
367
|
+
// can count over-generation assets without filesystem reads.
|
|
358
368
|
const generation = fmData.generation;
|
|
359
369
|
if (typeof generation === "number" && Number.isFinite(generation) && generation > 0) {
|
|
360
370
|
entry.generation = Math.floor(generation);
|
|
361
371
|
}
|
|
362
|
-
const sourceRefs = normalizeStringListOrUndefined(fmData.source_refs);
|
|
363
|
-
if (sourceRefs)
|
|
364
|
-
entry.sourceRefs = sourceRefs;
|
|
365
372
|
const currentBeliefRefs = normalizeStringListOrUndefined(fmData.currentBeliefRefs);
|
|
366
373
|
if (currentBeliefRefs)
|
|
367
374
|
entry.currentBeliefRefs = currentBeliefRefs;
|
|
@@ -384,27 +391,20 @@ export function applyCuratedFrontmatter(entry, fmData) {
|
|
|
384
391
|
if (evidenceSources)
|
|
385
392
|
entry.evidenceSources = evidenceSources;
|
|
386
393
|
// Phase 5A / Advantage D5: capture parent ref for derived memories.
|
|
387
|
-
// Memory-inference writes `source: "
|
|
388
|
-
// (and a derived child name suffix `.derived`). We mirror that source ref
|
|
389
|
-
//
|
|
390
|
-
//
|
|
394
|
+
// Memory-inference writes `source: "memories/<parent>"` and `inferred: true`
|
|
395
|
+
// (and a derived child name suffix `.derived`). We mirror that source ref into
|
|
396
|
+
// `entry.derivedFrom` so the indexer can populate the dedicated `derived_from`
|
|
397
|
+
// column. Group-C item 2: the column is stored in the 0.9.0 `memories/<name>`
|
|
398
|
+
// conceptId grammar — moving in lockstep with the `getDerivedForParent` lookup
|
|
399
|
+
// key (search-hit-enrichers) so producer + consumer speak one grammar.
|
|
400
|
+
// Non-derived entries leave this field unset.
|
|
391
401
|
if (entry.type === "memory") {
|
|
392
402
|
const isDerivedByName = entry.name.toLowerCase().endsWith(".derived");
|
|
393
403
|
const isDerivedByFm = fmData.inferred === true;
|
|
394
404
|
if (isDerivedByName || isDerivedByFm) {
|
|
395
|
-
const
|
|
396
|
-
if (
|
|
397
|
-
entry.derivedFrom =
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
// Fallback: some legacy renderings store only `derivedFrom: <name>`
|
|
401
|
-
// (a bare parent name). Promote it to a `memory:` ref so the lookup
|
|
402
|
-
// column stays consistent.
|
|
403
|
-
const derivedFromName = asNonEmptyString(fmData.derivedFrom);
|
|
404
|
-
if (derivedFromName) {
|
|
405
|
-
entry.derivedFrom = derivedFromName.includes(":") ? derivedFromName : `memory:${derivedFromName}`;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
405
|
+
const parent = derivedFromConceptId(asNonEmptyString(fmData.source), asNonEmptyString(fmData.derivedFrom));
|
|
406
|
+
if (parent)
|
|
407
|
+
entry.derivedFrom = parent;
|
|
408
408
|
}
|
|
409
409
|
}
|
|
410
410
|
const intent = normalizeIntent(fmData.intent);
|
|
@@ -484,53 +484,84 @@ export function applyWikiFrontmatter(entry, fmData) {
|
|
|
484
484
|
entry.sources = filtered;
|
|
485
485
|
}
|
|
486
486
|
}
|
|
487
|
-
const WIKI_INFRA_FILES = new Set(["schema.md", "index.md", "log.md"]);
|
|
488
487
|
/**
|
|
489
|
-
*
|
|
490
|
-
*
|
|
488
|
+
* Parse one `verified:` family value into the `IndexDocument.provenance` shape.
|
|
489
|
+
* Accepts OKF v0.2's list form and its documented single-mapping shorthand
|
|
490
|
+
* ("consumers MUST treat a bare mapping as a one-element list", SPEC §5.2).
|
|
491
|
+
* Tolerant: an entry without a usable `by` is dropped individually.
|
|
492
|
+
*/
|
|
493
|
+
function parseVerifiedFamily(value) {
|
|
494
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
495
|
+
return entries
|
|
496
|
+
.filter((v) => v !== null && typeof v === "object" && !Array.isArray(v))
|
|
497
|
+
.map((v) => {
|
|
498
|
+
const by = asNonEmptyString(v.by);
|
|
499
|
+
if (!by)
|
|
500
|
+
return undefined;
|
|
501
|
+
const at = asNonEmptyString(v.at);
|
|
502
|
+
return at ? { by, at } : { by };
|
|
503
|
+
})
|
|
504
|
+
.filter((v) => v !== undefined);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Extract the OKF v0.2 provenance families that `promoteProposal` stamps onto
|
|
508
|
+
* accepted AKM-native proposals (D2, #730), and apply them to the entry.
|
|
509
|
+
*
|
|
510
|
+
* The on-disk shape is deliberately **hybrid** (owner decision, #730 review):
|
|
511
|
+
* `generated:` and `verified:` are stamped BARE at the top level, exactly as
|
|
512
|
+
* OKF v0.2 spells them, because neither has any pre-existing AKM consumer — so
|
|
513
|
+
* a third-party OKF v0.2 reader treating an AKM stash as an OKF bundle sees
|
|
514
|
+
* spec-conformant trust metadata, which is what `okf-support.md`'s
|
|
515
|
+
* "AKM Markdown is an OKF-compatible superset" positioning promises. Only
|
|
516
|
+
* `sources` stays namespaced under `provenance:`, because a bare top-level
|
|
517
|
+
* `sources:` genuinely collides with {@link applyWikiFrontmatter}'s
|
|
518
|
+
* pre-existing citation-**string** convention (which silently drops
|
|
519
|
+
* non-strings).
|
|
491
520
|
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
521
|
+
* The nested `provenance.generatedBy` / `.generatedAt` / `.verified` spellings
|
|
522
|
+
* are still read as a fallback so assets stamped by an earlier build of this
|
|
523
|
+
* branch keep resolving. Tolerant throughout: any malformed sub-field is
|
|
524
|
+
* dropped individually rather than rejecting the whole block.
|
|
495
525
|
*/
|
|
496
|
-
export function
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
//
|
|
517
|
-
if (
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
526
|
+
export function applyProvenanceFrontmatter(entry, fmData) {
|
|
527
|
+
const provenance = fmData.provenance;
|
|
528
|
+
const nested = provenance !== null && typeof provenance === "object" && !Array.isArray(provenance)
|
|
529
|
+
? provenance
|
|
530
|
+
: {};
|
|
531
|
+
const result = {};
|
|
532
|
+
// Bare `generated: {by, at}` (OKF v0.2 §5.3) wins; nested is the fallback.
|
|
533
|
+
const generatedMapping = fmData.generated !== null && typeof fmData.generated === "object" && !Array.isArray(fmData.generated)
|
|
534
|
+
? fmData.generated
|
|
535
|
+
: undefined;
|
|
536
|
+
const generatedBy = asNonEmptyString(generatedMapping?.by) ?? asNonEmptyString(nested.generatedBy);
|
|
537
|
+
if (generatedBy)
|
|
538
|
+
result.generatedBy = generatedBy;
|
|
539
|
+
const generatedAt = asNonEmptyString(generatedMapping?.at) ?? asNonEmptyString(nested.generatedAt);
|
|
540
|
+
if (generatedAt)
|
|
541
|
+
result.generatedAt = generatedAt;
|
|
542
|
+
// Bare `verified:` (list or single mapping) wins; nested is the fallback.
|
|
543
|
+
const verified = fmData.verified !== undefined ? parseVerifiedFamily(fmData.verified) : parseVerifiedFamily(nested.verified);
|
|
544
|
+
if (verified.length > 0)
|
|
545
|
+
result.verified = verified;
|
|
546
|
+
// `sources` is namespaced-only — see the collision note above.
|
|
547
|
+
if (Array.isArray(nested.sources)) {
|
|
548
|
+
const sources = nested.sources
|
|
549
|
+
.filter((s) => s !== null && typeof s === "object" && !Array.isArray(s))
|
|
550
|
+
.map((s) => {
|
|
551
|
+
const resource = asNonEmptyString(s.resource);
|
|
552
|
+
return resource ? { resource } : undefined;
|
|
553
|
+
})
|
|
554
|
+
.filter((s) => s !== undefined);
|
|
555
|
+
if (sources.length > 0)
|
|
556
|
+
result.sources = sources;
|
|
525
557
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
return true;
|
|
529
|
-
const wikiRelativeSegments = segments.slice(wikisIdx + 2);
|
|
530
|
-
if (wikiRelativeSegments.length === 0)
|
|
531
|
-
return true;
|
|
532
|
-
return !(wikiRelativeSegments.length === 1 && WIKI_INFRA_FILES.has(wikiRelativeSegments[0]));
|
|
558
|
+
if (Object.keys(result).length > 0)
|
|
559
|
+
entry.provenance = result;
|
|
533
560
|
}
|
|
561
|
+
// AKM-stash indexing policy (env/vaults/secrets sensitive-marker + wiki-infra
|
|
562
|
+
// exclusions) moved to the `akm` adapter's `recognize` as path/stat-based
|
|
563
|
+
// abstention (owner ruling 2026-07-21 — adapter-owned filtering). See
|
|
564
|
+
// `akmStashAbstains` in `src/core/adapter/adapters/akm-adapter.ts`.
|
|
534
565
|
/**
|
|
535
566
|
* Extract `@param` JSDoc tags from a script file's leading comment block.
|
|
536
567
|
*
|
|
@@ -797,7 +828,6 @@ function mergeAliases(existing, generated) {
|
|
|
797
828
|
*
|
|
798
829
|
* This predicate is used by `enhanceDirsWithLlm` to skip the LLM call for
|
|
799
830
|
* entries that were previously enriched and already carry all three fields.
|
|
800
|
-
* Pass `reEnrich = true` in the caller to bypass this check.
|
|
801
831
|
*/
|
|
802
832
|
export function isEnrichmentComplete(entry) {
|
|
803
833
|
const hasDescription = typeof entry.description === "string" && entry.description.trim().length > 0;
|
|
@@ -805,39 +835,206 @@ export function isEnrichmentComplete(entry) {
|
|
|
805
835
|
const hasSearchHints = Array.isArray(entry.searchHints) && entry.searchHints.length > 0;
|
|
806
836
|
return hasDescription && hasTags && hasSearchHints;
|
|
807
837
|
}
|
|
808
|
-
// ──
|
|
838
|
+
// ── Body-opening extraction (stash-conventions SPEC-8) ──────────────────────
|
|
809
839
|
/**
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
840
|
+
* Maximum length of a captured self-situating body opening. Bounds index-size
|
|
841
|
+
* growth and keeps a single verbose opening from dominating the low-weight
|
|
842
|
+
* `content` FTS column.
|
|
843
|
+
*/
|
|
844
|
+
export const BODY_OPENING_MAX_CHARS = 280;
|
|
845
|
+
/**
|
|
846
|
+
* Minimum characters retained when the cap truncates at a word boundary. A
|
|
847
|
+
* boundary cut that would retain less than this falls back to a hard cut, so
|
|
848
|
+
* one pathological long token cannot gut the capture.
|
|
849
|
+
*/
|
|
850
|
+
const BODY_OPENING_MIN_RETAINED_CHARS = 250;
|
|
851
|
+
/**
|
|
852
|
+
* True when `index.indexBodyOpening` is enabled in the user config.
|
|
819
853
|
*
|
|
820
|
-
*
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
*
|
|
824
|
-
*
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
854
|
+
* The gate is the GLOBAL user config, read directly by the metadata pass so
|
|
855
|
+
* every indexing entry point (stash walk, flat walk, write-path indexing)
|
|
856
|
+
* honors the flag without parameter plumbing. Fail-open: an unreadable or
|
|
857
|
+
* invalid config must never break indexing (CLI entry points surface config
|
|
858
|
+
* errors loudly on their own), so any load failure reads as "off".
|
|
859
|
+
*/
|
|
860
|
+
function isBodyOpeningIndexingEnabled() {
|
|
861
|
+
try {
|
|
862
|
+
return loadUserConfig().index?.indexBodyOpening === true;
|
|
863
|
+
}
|
|
864
|
+
catch {
|
|
865
|
+
return false;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Locate a leading nested frontmatter block in a body: up to three blank
|
|
870
|
+
* lines, then a `---` line, closed by a later `---` line. Mirrors the
|
|
871
|
+
* base-linter's `parseInnerFrontmatterBlock` recognition — when `akm
|
|
872
|
+
* remember` wraps a session-capture hook's file in its own frontmatter, the
|
|
873
|
+
* hook's `---\nakm_memory_kind: …\n---` block survives at the top of the
|
|
874
|
+
* body. Returns the open/close line indexes, or `null` when no block opens.
|
|
875
|
+
* Location only — callers apply their own interior checks (marker scan in
|
|
876
|
+
* {@link hasSessionMemoryMarker}, shape test in {@link isFrontmatterShaped}).
|
|
877
|
+
*/
|
|
878
|
+
function findInnerFrontmatterBlock(lines) {
|
|
879
|
+
let i = 0;
|
|
880
|
+
while (i < lines.length && i < 3 && lines[i].trim() === "")
|
|
881
|
+
i += 1;
|
|
882
|
+
if (lines[i] !== "---")
|
|
883
|
+
return null;
|
|
884
|
+
for (let j = i + 1; j < lines.length; j += 1) {
|
|
885
|
+
if (lines[j] === "---")
|
|
886
|
+
return { open: i, close: j };
|
|
887
|
+
}
|
|
888
|
+
return null;
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* True when the document carries the session-capture `akm_memory_kind`
|
|
892
|
+
* marker — in the outer frontmatter data OR in a nested inner block at the
|
|
893
|
+
* top of the body (both producer layouts exist; see base-linter's
|
|
894
|
+
* `extractFrontmatterRefs`). Session bodies are raw transcripts, never a
|
|
895
|
+
* self-situating opening.
|
|
830
896
|
*/
|
|
831
|
-
|
|
897
|
+
function hasSessionMemoryMarker(fmData, body) {
|
|
898
|
+
if (typeof fmData.akm_memory_kind === "string")
|
|
899
|
+
return true;
|
|
900
|
+
const lines = body.split(/\r?\n/);
|
|
901
|
+
const block = findInnerFrontmatterBlock(lines);
|
|
902
|
+
if (!block)
|
|
903
|
+
return false;
|
|
904
|
+
for (let i = block.open + 1; i < block.close; i += 1) {
|
|
905
|
+
if (/^akm_memory_kind:\s*\S/.test(lines[i]))
|
|
906
|
+
return true;
|
|
907
|
+
}
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* True when the interior of a candidate inner block (located by
|
|
912
|
+
* {@link findInnerFrontmatterBlock}) actually reads as YAML frontmatter:
|
|
913
|
+
* every line is blank, indented (a continuation or nested value), or shaped
|
|
914
|
+
* like a top-level `key:` mapping entry. Ordinary prose bracketed by two
|
|
915
|
+
* thematic-break `---` lines fails this test, so a decorative opening
|
|
916
|
+
* callout is treated as the paragraph it is instead of being discarded
|
|
917
|
+
* (review finding on SPEC-8 — the block finder alone accepts ANY content up
|
|
918
|
+
* to an arbitrarily distant closing `---`).
|
|
919
|
+
*/
|
|
920
|
+
function isFrontmatterShaped(lines, block) {
|
|
921
|
+
for (let i = block.open + 1; i < block.close; i += 1) {
|
|
922
|
+
const line = lines[i];
|
|
923
|
+
if (line.trim() === "")
|
|
924
|
+
continue;
|
|
925
|
+
if (/^\s/.test(line))
|
|
926
|
+
continue; // indented continuation / nested value
|
|
927
|
+
if (/^[A-Za-z0-9_.-]+:(\s|$)/.test(line))
|
|
928
|
+
continue; // top-level key
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Extract the first prose paragraph of a markdown body (frontmatter already
|
|
935
|
+
* stripped by the caller): skip blank lines, ATX headings, setext `=`
|
|
936
|
+
* underlines (discarding the heading text above them), thematic breaks,
|
|
937
|
+
* fenced code blocks (``` or ~~~, including their contents), and a leading
|
|
938
|
+
* nested frontmatter block — skipped only when its interior is actually
|
|
939
|
+
* frontmatter-shaped, so prose wrapped in decorative `---` lines is still
|
|
940
|
+
* captured; then collect consecutive non-blank lines until the paragraph
|
|
941
|
+
* ends. Deliberate asymmetry: a `---` row after captured prose ENDS the
|
|
942
|
+
* paragraph and keeps it (favoring the callout/thematic-break reading over
|
|
943
|
+
* CommonMark's setext-H2), while a `=+` row can only be a setext underline
|
|
944
|
+
* and so discards the pending lines as heading text. The result is capped at
|
|
945
|
+
* {@link BODY_OPENING_MAX_CHARS} chars — truncated at the last word boundary
|
|
946
|
+
* that still retains a substantial prefix, with a trailing ellipsis. Returns
|
|
947
|
+
* `undefined` when the body has no prose (frontmatter-only files,
|
|
948
|
+
* headings/fences-only bodies).
|
|
949
|
+
*/
|
|
950
|
+
export function extractBodyOpening(body) {
|
|
951
|
+
const lines = body.split(/\r?\n/);
|
|
952
|
+
const innerBlock = findInnerFrontmatterBlock(lines);
|
|
953
|
+
const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
|
|
954
|
+
const paragraph = [];
|
|
955
|
+
let inFence = false;
|
|
956
|
+
let fenceChar = "";
|
|
957
|
+
let inHtmlComment = false;
|
|
958
|
+
for (let i = start; i < lines.length; i += 1) {
|
|
959
|
+
const trimmed = lines[i].trim();
|
|
960
|
+
const fenceMatch = trimmed.match(/^(`{3,}|~{3,})/);
|
|
961
|
+
if (inFence) {
|
|
962
|
+
// Fence interiors are never prose (and may be secrets-adjacent command
|
|
963
|
+
// text); skip until the matching closing marker.
|
|
964
|
+
if (fenceMatch && fenceMatch[1].charAt(0) === fenceChar)
|
|
965
|
+
inFence = false;
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
if (inHtmlComment) {
|
|
969
|
+
// Comment interiors are machinery (the skeleton convention facts open
|
|
970
|
+
// with a <!-- SOFT guidance --> block), never orientation prose.
|
|
971
|
+
if (trimmed.includes("-->"))
|
|
972
|
+
inHtmlComment = false;
|
|
973
|
+
continue;
|
|
974
|
+
}
|
|
975
|
+
if (fenceMatch) {
|
|
976
|
+
if (paragraph.length > 0)
|
|
977
|
+
break; // a fence ends an open paragraph
|
|
978
|
+
inFence = true;
|
|
979
|
+
fenceChar = fenceMatch[1].charAt(0);
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
if (trimmed.startsWith("<!--")) {
|
|
983
|
+
if (paragraph.length > 0)
|
|
984
|
+
break; // a comment ends an open paragraph
|
|
985
|
+
if (!trimmed.includes("-->"))
|
|
986
|
+
inHtmlComment = true;
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
if (/^=+$/.test(trimmed)) {
|
|
990
|
+
// A row of `=` is a setext H1 underline: the pending lines are heading
|
|
991
|
+
// text, not prose — discard them and keep searching. (A bare `=` row
|
|
992
|
+
// with nothing pending is skipped like any other non-prose divider.)
|
|
993
|
+
paragraph.length = 0;
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
const isBlank = trimmed === "";
|
|
997
|
+
const isHeading = /^#{1,6}(\s|$)/.test(trimmed);
|
|
998
|
+
const isThematicBreak = /^(-{3,}|\*{3,}|_{3,})$/.test(trimmed);
|
|
999
|
+
if (isBlank || isHeading || isThematicBreak) {
|
|
1000
|
+
if (paragraph.length > 0)
|
|
1001
|
+
break; // paragraph complete
|
|
1002
|
+
continue; // still searching for the first prose line
|
|
1003
|
+
}
|
|
1004
|
+
paragraph.push(trimmed);
|
|
1005
|
+
}
|
|
1006
|
+
const text = paragraph.join("\n");
|
|
1007
|
+
if (!text)
|
|
1008
|
+
return undefined;
|
|
1009
|
+
if (text.length <= BODY_OPENING_MAX_CHARS)
|
|
1010
|
+
return text;
|
|
1011
|
+
// Cap: prefer a word-boundary cut (never mid-token), but only when it keeps
|
|
1012
|
+
// a substantial prefix; append a one-char ellipsis inside the budget.
|
|
1013
|
+
const slice = text.slice(0, BODY_OPENING_MAX_CHARS - 1);
|
|
1014
|
+
const lastBoundary = Math.max(slice.lastIndexOf(" "), slice.lastIndexOf("\n"), slice.lastIndexOf("\t"));
|
|
1015
|
+
let cut = lastBoundary >= BODY_OPENING_MIN_RETAINED_CHARS ? slice.slice(0, lastBoundary) : slice;
|
|
1016
|
+
// slice() counts UTF-16 code units, so the no-boundary fallback can end on
|
|
1017
|
+
// the high half of a surrogate pair — a lone surrogate that corrupts the
|
|
1018
|
+
// FTS/embedding text. Drop it rather than emit invalid UTF-16.
|
|
1019
|
+
const lastCode = cut.charCodeAt(cut.length - 1);
|
|
1020
|
+
if (lastCode >= 0xd800 && lastCode <= 0xdbff)
|
|
1021
|
+
cut = cut.slice(0, -1);
|
|
1022
|
+
return `${cut.trimEnd()}…`;
|
|
1023
|
+
}
|
|
1024
|
+
// ── Metadata Generation ─────────────────────────────────────────────────────
|
|
1025
|
+
/**
|
|
1026
|
+
* Priorities 1-2 of the metadata pipeline — package.json (P1), `.md`
|
|
1027
|
+
* frontmatter (P2), and script `@param`/comment metadata (P2b) — everything
|
|
1028
|
+
* that runs BEFORE the renderer-contributor step (P3). Extracted (Chunk 5 M-b)
|
|
1029
|
+
* so the `akm` adapter's synchronous `recognize` shares this exact assembly
|
|
1030
|
+
* with the live index-drain path; the two differ ONLY in how they obtain the
|
|
1031
|
+
* P3 renderer metadata (the adapter uses the synchronous
|
|
1032
|
+
* `foldRecognizedMetadata`), guaranteeing P1/P2/P4 parity by construction.
|
|
1033
|
+
* Behavior-preserving: this is a verbatim lift of the former inline P1/P2/P2b
|
|
1034
|
+
* block. Mutates `entry` in place.
|
|
1035
|
+
*/
|
|
1036
|
+
export function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
832
1037
|
const ext = path.extname(file).toLowerCase();
|
|
833
|
-
const baseName = path.basename(file, ext);
|
|
834
|
-
const entry = {
|
|
835
|
-
name: canonicalName,
|
|
836
|
-
type: assetType,
|
|
837
|
-
quality: "generated",
|
|
838
|
-
confidence: 0.55,
|
|
839
|
-
source: "filename",
|
|
840
|
-
};
|
|
841
1038
|
// Priority 1: Package.json metadata
|
|
842
1039
|
if (pkgMeta) {
|
|
843
1040
|
if (pkgMeta.description && !entry.description) {
|
|
@@ -851,7 +1048,7 @@ async function buildEntryFromFile(file, assetType, canonicalName, dirPath, pkgMe
|
|
|
851
1048
|
// Priority 2: Frontmatter (for .md files -- overrides package.json description)
|
|
852
1049
|
// Secrets are excluded even when the file happens to be `.md`: the whole file
|
|
853
1050
|
// is the secret value and must never be read for frontmatter or any metadata.
|
|
854
|
-
if (ext === ".md" &&
|
|
1051
|
+
if (ext === ".md" && entry.type !== "secret") {
|
|
855
1052
|
const content = ctx.content();
|
|
856
1053
|
const parsed = parseFrontmatter(content);
|
|
857
1054
|
applyCuratedFrontmatter(entry, parsed.data);
|
|
@@ -861,6 +1058,19 @@ async function buildEntryFromFile(file, assetType, canonicalName, dirPath, pkgMe
|
|
|
861
1058
|
entry.parameters = fmParams;
|
|
862
1059
|
// Pass wiki-pattern frontmatter through onto the entry
|
|
863
1060
|
applyWikiFrontmatter(entry, parsed.data);
|
|
1061
|
+
// D2 (#730): reread the namespaced `provenance:` block promoteProposal stamps.
|
|
1062
|
+
applyProvenanceFrontmatter(entry, parsed.data);
|
|
1063
|
+
// Stash-organization conventions (SPEC-8): config-gated capture of the
|
|
1064
|
+
// self-situating body opening. Default off — enabling it changes indexed
|
|
1065
|
+
// text (collapse-detector canary baselines shift, and embeddings for
|
|
1066
|
+
// already-embedded entries are NOT regenerated; see docs/reference/configuration.md).
|
|
1067
|
+
// Session-kind memories are raw transcripts and are never captured;
|
|
1068
|
+
// secrets never reach this branch (guard above) and env files are not .md.
|
|
1069
|
+
if (isBodyOpeningIndexingEnabled() && !hasSessionMemoryMarker(parsed.data, parsed.content)) {
|
|
1070
|
+
const bodyOpening = extractBodyOpening(parsed.content);
|
|
1071
|
+
if (bodyOpening)
|
|
1072
|
+
entry.bodyOpening = bodyOpening;
|
|
1073
|
+
}
|
|
864
1074
|
// Extract parameters from template placeholders ($1, $ARGUMENTS, {{named}})
|
|
865
1075
|
if (entry.type === "command") {
|
|
866
1076
|
const cmdParams = extractCommandParameters(parsed.content);
|
|
@@ -873,35 +1083,24 @@ async function buildEntryFromFile(file, assetType, canonicalName, dirPath, pkgMe
|
|
|
873
1083
|
// Env files (.env) and secret files (whole-file secrets) are deliberately
|
|
874
1084
|
// excluded — their contents are secrets and must never be parsed for @param
|
|
875
1085
|
// or any other metadata that could embed a value into the entry.
|
|
876
|
-
if (ext !== ".md" &&
|
|
1086
|
+
if (ext !== ".md" && entry.type !== "env" && entry.type !== "secret") {
|
|
877
1087
|
const content = ctx.content();
|
|
878
1088
|
const scriptParams = extractScriptParameters(file, content);
|
|
879
1089
|
if (scriptParams)
|
|
880
1090
|
entry.parameters = scriptParams;
|
|
881
1091
|
applyCommentMetadata(entry, extractCommentMetadata(file, content));
|
|
882
1092
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
renderContext: renderCtx,
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
catch (error) {
|
|
898
|
-
return {
|
|
899
|
-
skip: true,
|
|
900
|
-
warning: buildMetadataSkipWarning(file, assetType, error),
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
}
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Priority 4 of the metadata pipeline — filename-heuristic fallbacks (P4) that
|
|
1096
|
+
* run AFTER the renderer-contributor step (P3): a filename description when none
|
|
1097
|
+
* was set, path/dir-derived tags, tag normalization, and alias generation.
|
|
1098
|
+
* Extracted (Chunk 5 M-b) alongside {@link applyPreContributorFields} so both
|
|
1099
|
+
* pipeline paths share it. Behavior-preserving verbatim lift. Mutates `entry`.
|
|
1100
|
+
*/
|
|
1101
|
+
export function applyPostContributorFields(entry, file, canonicalName, dirPath) {
|
|
1102
|
+
const ext = path.extname(file).toLowerCase();
|
|
1103
|
+
const baseName = path.basename(file, ext);
|
|
905
1104
|
// Priority 4: Filename heuristics (fallback)
|
|
906
1105
|
if (!entry.description) {
|
|
907
1106
|
entry.description = fileNameToDescription(baseName);
|
|
@@ -911,84 +1110,31 @@ async function buildEntryFromFile(file, assetType, canonicalName, dirPath, pkgMe
|
|
|
911
1110
|
if (!entry.tags || entry.tags.length === 0) {
|
|
912
1111
|
entry.tags = extractTagsFromPath(file, dirPath);
|
|
913
1112
|
}
|
|
1113
|
+
// Stash-organization conventions (SPEC-2): directory (scope/domain) tokens
|
|
1114
|
+
// always reach the tags column, even when the author set explicit tags, so
|
|
1115
|
+
// nested assets keep the exact-tag ranking boost for their scope token.
|
|
1116
|
+
// Derived from canonicalName (the ref subpath) rather than the filesystem
|
|
1117
|
+
// path so the stash-walk and flat-walk indexing paths agree (the flat walk
|
|
1118
|
+
// passes `path.dirname(file)` as dirPath, which strips directory segments
|
|
1119
|
+
// from the fallback above). Filename tokens are deliberately NOT merged when
|
|
1120
|
+
// explicit tags exist — they already live in the FTS name column and in
|
|
1121
|
+
// aliases, and merging them would inflate exact-tag matches for every
|
|
1122
|
+
// filename word. `normalizeTerms` below dedupes author-restated tokens.
|
|
1123
|
+
entry.tags = [...(entry.tags ?? []), ...extractDirTagsFromName(canonicalName)];
|
|
914
1124
|
entry.tags = normalizeTerms(entry.tags ?? []);
|
|
915
1125
|
entry.aliases = mergeAliases(entry.aliases, buildAliases(canonicalName, entry.tags));
|
|
916
1126
|
// Search hints are only generated when LLM is configured (via enhanceStashWithLlm)
|
|
917
1127
|
// Heuristic search hints are too noisy to be useful for search quality
|
|
918
1128
|
entry.filename = path.basename(file);
|
|
919
|
-
return entry;
|
|
920
|
-
}
|
|
921
|
-
export async function generateMetadata(dirPath, assetType, files, typeRoot = dirPath) {
|
|
922
|
-
const entries = [];
|
|
923
|
-
const warnings = [];
|
|
924
|
-
const pkgMeta = extractPackageMetadata(dirPath);
|
|
925
|
-
for (const file of files) {
|
|
926
|
-
const ext = path.extname(file).toLowerCase();
|
|
927
|
-
const baseName = path.basename(file, ext);
|
|
928
|
-
const fileName = path.basename(file);
|
|
929
|
-
// Skip non-relevant files
|
|
930
|
-
if (!isRelevantAssetFile(assetType, fileName))
|
|
931
|
-
continue;
|
|
932
|
-
const canonicalName = deriveCanonicalAssetName(assetType, typeRoot, file) ?? baseName;
|
|
933
|
-
// Build file context with typeRoot as the stash root so renderer context
|
|
934
|
-
// and search hints are scoped to the type directory.
|
|
935
|
-
const fileCtx = buildFileContext(typeRoot, file);
|
|
936
|
-
// Step 1: type is explicit; delegate steps 2-6 to the shared pipeline.
|
|
937
|
-
const result = await buildEntryFromFile(file, assetType, canonicalName, dirPath, pkgMeta, typeRoot, fileCtx, null);
|
|
938
|
-
if ("skip" in result) {
|
|
939
|
-
warnings.push(result.warning);
|
|
940
|
-
continue;
|
|
941
|
-
}
|
|
942
|
-
entries.push(result);
|
|
943
|
-
}
|
|
944
|
-
return warnings.length > 0 ? { entries, warnings } : { entries };
|
|
945
|
-
}
|
|
946
|
-
/**
|
|
947
|
-
* Generate metadata for files using the matcher system instead of a fixed asset type.
|
|
948
|
-
*
|
|
949
|
-
* This is the flat-walk counterpart of `generateMetadata`. It classifies each
|
|
950
|
-
* file via `runMatchers()` and uses the matched type for canonical naming.
|
|
951
|
-
* Files that no matcher claims are silently skipped.
|
|
952
|
-
*/
|
|
953
|
-
export async function generateMetadataFlat(stashRoot, files) {
|
|
954
|
-
const entries = [];
|
|
955
|
-
const warnings = [];
|
|
956
|
-
const pkgMetaCache = new Map();
|
|
957
|
-
for (const file of files) {
|
|
958
|
-
if (!shouldIndexStashFile(stashRoot, file))
|
|
959
|
-
continue;
|
|
960
|
-
// Step 1: determine type and canonical name via the matcher system.
|
|
961
|
-
const ctx = buildFileContext(stashRoot, file);
|
|
962
|
-
const match = await runMatchers(ctx);
|
|
963
|
-
if (!match)
|
|
964
|
-
continue;
|
|
965
|
-
const assetType = match.type;
|
|
966
|
-
if (!isAssetType(assetType))
|
|
967
|
-
continue;
|
|
968
|
-
// If the file lives under a known type directory, use that as the root
|
|
969
|
-
// for canonical naming so names don't include the type prefix.
|
|
970
|
-
// e.g. scripts/deploy.sh → "deploy.sh" not "scripts/deploy.sh"
|
|
971
|
-
const ext = path.extname(file).toLowerCase();
|
|
972
|
-
const baseName = path.basename(file, ext);
|
|
973
|
-
const canonicalName = deriveCanonicalAssetNameFromStashRoot(assetType, stashRoot, file) ?? baseName;
|
|
974
|
-
// Resolve package.json metadata with a per-directory cache.
|
|
975
|
-
const dirPath = path.dirname(file);
|
|
976
|
-
if (!pkgMetaCache.has(dirPath)) {
|
|
977
|
-
pkgMetaCache.set(dirPath, extractPackageMetadata(dirPath));
|
|
978
|
-
}
|
|
979
|
-
const pkgMeta = pkgMetaCache.get(dirPath);
|
|
980
|
-
// Steps 2-6: delegate to the shared pipeline; pass the pre-resolved match
|
|
981
|
-
// so we don't run matchers a second time.
|
|
982
|
-
const result = await buildEntryFromFile(file, assetType, canonicalName, dirPath, pkgMeta, stashRoot, ctx, match);
|
|
983
|
-
if ("skip" in result) {
|
|
984
|
-
warnings.push(result.warning);
|
|
985
|
-
continue;
|
|
986
|
-
}
|
|
987
|
-
entries.push(result);
|
|
988
|
-
}
|
|
989
|
-
return warnings.length > 0 ? { entries, warnings } : { entries };
|
|
990
1129
|
}
|
|
991
|
-
|
|
1130
|
+
// The pre-0.9.0 flat-walk matcher-pass metadata source was DELETED in Chunk 5
|
|
1131
|
+
// F4a M-core-3. Its role (recognize a stash root's files into durable entries)
|
|
1132
|
+
// is now the `akm` adapter's `recognize`, drained by `indexer/scan/drain-dir.ts`
|
|
1133
|
+
// (`drainDirDocuments` for the live indexer, `recognizeStashEntries` for the
|
|
1134
|
+
// `manifest` fallback / `registry` index builder / metadata unit tests). The
|
|
1135
|
+
// flip is the F4 engine swap; the shadow-parity gate proved recognize produced
|
|
1136
|
+
// the identical entries before the old pass was removed.
|
|
1137
|
+
export function buildMetadataSkipWarning(filePath, assetType, error) {
|
|
992
1138
|
const detail = error instanceof Error ? error.message : String(error);
|
|
993
1139
|
// Workflow errors are already multi-line `path:line — message` blocks; print
|
|
994
1140
|
// them as-is so the author sees a flat list without a redundant prefix.
|
|
@@ -1127,3 +1273,26 @@ export function extractTagsFromPath(filePath, rootDir) {
|
|
|
1127
1273
|
}
|
|
1128
1274
|
return Array.from(tags);
|
|
1129
1275
|
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Extract scope/domain tags from the DIRECTORY segments of a canonical asset
|
|
1278
|
+
* name (the ref subpath — e.g. `"projectA/auth-tip"` → `["projecta"]`).
|
|
1279
|
+
*
|
|
1280
|
+
* Unlike {@link extractTagsFromPath} this never tokenizes the filename
|
|
1281
|
+
* segment: it exists so a nested asset's directory (scope/domain) tokens can
|
|
1282
|
+
* be merged into explicit author tags without dragging every filename word
|
|
1283
|
+
* into exact-tag matching (SPEC-2, docs/architecture/specs/stash-conventions-code-spec.md).
|
|
1284
|
+
* Tokenization mirrors `extractTagsFromPath`: each segment splits on `-`/`_`/
|
|
1285
|
+
* `.`, lowercased, single-character tokens dropped. A name with no directory
|
|
1286
|
+
* segments yields no tags.
|
|
1287
|
+
*/
|
|
1288
|
+
export function extractDirTagsFromName(name) {
|
|
1289
|
+
const tags = new Set();
|
|
1290
|
+
for (const segment of name.split("/").slice(0, -1)) {
|
|
1291
|
+
for (const token of segment.split(/[-_.]+/)) {
|
|
1292
|
+
const clean = token.toLowerCase().trim();
|
|
1293
|
+
if (clean && clean.length > 1)
|
|
1294
|
+
tags.add(clean);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
return Array.from(tags);
|
|
1298
|
+
}
|