akm-cli 0.9.0-rc.8 → 0.9.0
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 +1063 -44
- package/README.md +51 -25
- package/SECURITY.md +14 -1
- package/STABILITY.md +497 -0
- package/dist/akm +148 -35
- package/dist/{akm-migrate-storage → akm-migrate} +6 -9
- package/dist/assets/hints/cli-hints-full.md +223 -95
- package/dist/assets/hints/cli-hints-short.md +85 -22
- package/dist/assets/improve-strategies/default.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/stash-skeleton/README.md +6 -5
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
- package/dist/assets/tasks/core/extract.yml +1 -1
- package/dist/assets/tasks/core/version-check.yml +1 -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 +1 -3
- package/dist/assets/workflows/workflow-template.md +32 -15
- package/dist/cli/invocation.js +40 -15
- package/dist/cli/parse-args.js +0 -22
- package/dist/cli/retired-commands.js +121 -0
- package/dist/cli/shared.js +154 -22
- package/dist/cli/unknown-flags.js +236 -0
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +696 -258
- package/dist/commands/agent/agent-dispatch.js +14 -3
- package/dist/commands/agent/contribute-cli.js +73 -88
- package/dist/commands/completions.js +79 -22
- package/dist/commands/config-cli.js +17 -150
- package/dist/commands/env/env-cli.js +59 -143
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +36 -66
- package/dist/commands/env/secret.js +24 -57
- package/dist/commands/feedback-cli.js +141 -87
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +3 -4
- package/dist/commands/health/checks.js +85 -23
- package/dist/commands/health/html-report.js +7 -10
- package/dist/commands/health/improve-metrics.js +25 -83
- package/dist/commands/health/md-report.js +5 -9
- package/dist/commands/health/metrics.js +62 -20
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +4 -5
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +3 -48
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/commands/health/types-improve.js +7 -0
- package/dist/commands/health.js +99 -28
- package/dist/commands/improve/anti-collapse.js +2 -2
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +41 -40
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +140 -1000
- package/dist/commands/improve/distill/promote-memory.js +12 -12
- package/dist/commands/improve/distill/quality-gate.js +6 -6
- package/dist/commands/improve/distill.js +58 -69
- package/dist/commands/improve/eligibility.js +105 -57
- package/dist/commands/improve/extract-cli.js +14 -133
- package/dist/commands/improve/improve-cli.js +98 -114
- package/dist/commands/improve/improve-result-file.js +1 -28
- package/dist/commands/improve/improve-strategies.js +8 -5
- package/dist/commands/improve/improve.js +128 -91
- package/dist/commands/improve/loop-stages.js +182 -20
- package/dist/commands/improve/memory/derived-ref.js +45 -43
- package/dist/commands/improve/memory/memory-belief.js +1 -1
- package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
- package/dist/commands/improve/memory/memory-improve.js +6 -5
- package/dist/commands/improve/outcome-loop.js +22 -65
- package/dist/commands/improve/preparation.js +114 -123
- package/dist/commands/improve/proactive-maintenance.js +2 -5
- package/dist/commands/improve/reflect.js +56 -160
- package/dist/commands/improve/salience.js +11 -122
- package/dist/commands/improve/source-identity.js +10 -38
- package/dist/commands/lint/base-linter.js +20 -124
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +249 -43
- package/dist/commands/{events.js → log.js} +33 -38
- package/dist/commands/migrate-cli.js +92 -12
- package/dist/commands/migration-tool.js +46 -0
- package/dist/commands/observability-cli.js +70 -209
- package/dist/commands/proposal/drain.js +101 -29
- package/dist/commands/proposal/proposal-cli.js +76 -48
- package/dist/commands/proposal/proposal.js +54 -18
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +23 -15
- package/dist/commands/proposal/repository.js +701 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
- package/dist/commands/proposal/validators/proposal-validators.js +55 -7
- package/dist/commands/proposal/validators/proposals.js +4 -7
- package/dist/commands/read/curate.js +34 -53
- package/dist/commands/read/knowledge.js +150 -95
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +42 -15
- package/dist/commands/read/search-cli.js +180 -78
- package/dist/commands/read/search.js +58 -43
- package/dist/commands/read/show.js +197 -141
- package/dist/commands/registry-cli.js +12 -51
- package/dist/commands/remember.js +14 -57
- package/dist/commands/sources/add-cli.js +100 -31
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +7 -2
- package/dist/commands/sources/info.js +18 -5
- package/dist/commands/sources/init.js +12 -12
- package/dist/commands/sources/installed-stashes.js +382 -98
- package/dist/commands/sources/schema-repair.js +3 -2
- package/dist/commands/sources/self-update.js +131 -38
- package/dist/commands/sources/source-add.js +72 -17
- package/dist/commands/sources/source-clone.js +129 -45
- package/dist/commands/sources/source-manage.js +43 -23
- package/dist/commands/sources/sources-cli.js +57 -208
- package/dist/commands/sources/stash-cli.js +46 -53
- package/dist/commands/tasks/tasks-cli.js +91 -97
- package/dist/commands/tasks/tasks.js +276 -421
- package/dist/commands/workflow-cli.js +175 -450
- package/dist/core/adapter/adapters/akm-adapter.js +47 -28
- package/dist/core/adapter/adapters/akm-lint.js +42 -27
- package/dist/core/adapter/adapters/akm-metadata.js +15 -44
- package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
- package/dist/core/adapter/adapters/index.js +6 -6
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
- package/dist/core/adapter/adapters/okf-adapter.js +187 -19
- package/dist/core/adapter/adapters/shared.js +3 -19
- package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +6 -4
- package/dist/core/adapter/validate-context.js +214 -0
- package/dist/core/asset/akm-markdown.js +63 -0
- package/dist/core/asset/asset-placement.js +20 -6
- package/dist/core/asset/asset-ref.js +11 -9
- package/dist/core/asset/frontmatter-lint.js +30 -0
- package/dist/core/asset/frontmatter.js +37 -9
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +89 -18
- package/dist/core/asset/stash-meta.js +1 -1
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +152 -38
- package/dist/core/config/config-io.js +12 -1
- package/dist/core/config/config-schema.js +35 -8
- package/dist/core/config/config-sources.js +55 -11
- package/dist/core/config/config-walker.js +25 -9
- package/dist/core/config/config.js +9 -48
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +5 -1
- package/dist/core/config/schema/experimental.js +30 -0
- package/dist/core/config/schema/improve-processes.js +0 -6
- package/dist/core/config/schema/improve.js +21 -3
- package/dist/core/config/schema/index-config.js +8 -15
- package/dist/core/config/schema/output.js +4 -1
- package/dist/core/config/schema/setup.js +9 -18
- package/dist/core/config/schema/sources-bundles.js +49 -33
- package/dist/core/config/schema/workflow.js +3 -3
- package/dist/core/env-secret-ref.js +76 -46
- package/dist/core/errors.js +18 -12
- package/dist/core/events.js +46 -128
- package/dist/core/file-change.js +6 -5
- package/dist/core/fs-txn.js +83 -7
- package/dist/core/git-message.js +2 -2
- package/dist/core/improve-result.js +1 -100
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +2 -1
- package/dist/core/migration-operation.js +16 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/parse.js +4 -1
- package/dist/core/paths.js +17 -20
- package/dist/core/recognition-util.js +12 -14
- package/dist/core/redaction.js +34 -0
- package/dist/core/standards/resolve-standards-context.js +2 -14
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +2 -2
- package/dist/core/state/migrations.js +41 -18
- package/dist/core/state-db.js +5 -14
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +6 -4
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/type-presentation.js +3 -3
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +771 -95
- package/dist/indexer/bundle-identity-guard.js +3 -2
- package/dist/indexer/db/graph-db.js +0 -24
- package/dist/indexer/ensure-index.js +1 -0
- package/dist/indexer/graph/graph-boost.js +9 -34
- package/dist/indexer/graph/graph-extraction.js +8 -5
- package/dist/indexer/index-writer-lock.js +53 -17
- package/dist/indexer/index-written-assets.js +16 -22
- package/dist/indexer/indexer.js +497 -239
- package/dist/indexer/installations.js +14 -96
- package/dist/indexer/passes/dir-staleness.js +16 -9
- package/dist/indexer/passes/memory-inference.js +11 -9
- package/dist/indexer/passes/metadata.js +113 -47
- package/dist/indexer/scan/doc-to-entry.js +38 -1
- package/dist/indexer/scan/drain-dir.js +13 -23
- package/dist/indexer/search/db-search.js +99 -54
- package/dist/indexer/search/fts-query.js +47 -24
- package/dist/indexer/search/ranking-contributors.js +42 -20
- package/dist/indexer/search/ranking.js +18 -99
- package/dist/indexer/search/search-fields.js +7 -2
- package/dist/indexer/search/search-source.js +82 -93
- package/dist/indexer/usage/usage-events.js +0 -89
- package/dist/indexer/walk/file-context.js +2 -1
- package/dist/indexer/walk/matchers.js +30 -43
- package/dist/indexer/walk/path-resolver.js +7 -2
- package/dist/indexer/walk/walker.js +38 -12
- package/dist/integrations/agent/builders.js +0 -6
- package/dist/integrations/agent/config.js +2 -2
- package/dist/integrations/agent/detect.js +49 -19
- package/dist/integrations/agent/engine-fallback.js +76 -0
- package/dist/integrations/agent/profiles.js +14 -0
- package/dist/integrations/agent/prompts.js +12 -8
- package/dist/integrations/agent/runner-dispatch.js +4 -2
- package/dist/integrations/agent/runner.js +0 -1
- package/dist/integrations/agent/spawn.js +5 -6
- package/dist/integrations/github.js +1 -1
- package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
- package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
- package/dist/integrations/harnesses/claude/session-log.js +0 -10
- package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
- package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
- package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
- package/dist/integrations/harnesses/index.js +3 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
- package/dist/integrations/harnesses/opencode/session-log.js +0 -15
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
- package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
- package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
- package/dist/integrations/lockfile.js +101 -6
- package/dist/integrations/session-logs/index.js +3 -28
- package/dist/llm/client.js +136 -100
- package/dist/llm/embedders/remote.js +13 -5
- package/dist/llm/feature-gate.js +4 -12
- package/dist/llm/graph-extract.js +5 -11
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +5 -7
- package/dist/llm/structured-call.js +1 -1
- package/dist/llm/usage-persist.js +26 -5
- package/dist/llm/usage-telemetry.js +25 -2
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +259 -0
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +14 -36
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +56 -83
- package/dist/output/shapes/migrate.js +8 -0
- package/dist/output/shapes/passthrough.js +7 -41
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes.js +2 -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 +164 -96
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/health-format.js +103 -0
- package/dist/output/text/health.js +7 -0
- package/dist/output/text/helpers.js +10 -8
- package/dist/output/text/lint-format.js +43 -0
- package/dist/output/text/{save.js → lint.js} +2 -2
- package/dist/output/text/migrate.js +88 -0
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +44 -72
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/show-directives.js +15 -7
- package/dist/output/text/status-list.js +32 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +24 -203
- package/dist/output/text/workflow.js +1 -7
- package/dist/output/text.js +16 -17
- 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 +13 -23
- package/dist/registry/resolve.js +42 -7
- package/dist/registry/semver.js +34 -84
- package/dist/runtime.js +2 -23
- package/dist/scripts/akm-migrate-node.js +60290 -0
- package/dist/scripts/akm-migrate.js +59628 -0
- package/dist/setup/detect.js +42 -15
- package/dist/setup/registry-stash-loader.js +2 -2
- package/dist/setup/setup.js +236 -136
- package/dist/setup/steps/connection.js +7 -9
- package/dist/setup/steps/platforms.js +9 -9
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +12 -13
- package/dist/setup/steps/stashdir.js +2 -3
- package/dist/setup/steps/tasks.js +237 -120
- package/dist/sources/freshness.js +1 -1
- 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 +25 -23
- package/dist/sources/providers/git-stash.js +395 -106
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +7 -4
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +6 -1
- package/dist/sources/resolve.js +6 -5
- package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
- package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
- package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
- package/dist/sources/snapshot-fetchers/github.js +100 -0
- package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
- package/dist/sources/snapshot-fetchers/registry.js +17 -1
- package/dist/sources/snapshot-fetchers/robots.js +348 -0
- package/dist/sources/snapshot-fetchers/rss.js +282 -0
- package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
- package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
- package/dist/sources/snapshot-fetchers/x.js +910 -0
- package/dist/storage/database.js +7 -0
- package/dist/storage/engines/sqlite-migrations.js +23 -111
- package/dist/storage/managed-db.js +2 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +27 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -12
- package/dist/storage/repositories/index-connection.js +17 -6
- package/dist/storage/repositories/index-entries-repository.js +151 -240
- package/dist/storage/repositories/index-entry-mapper.js +15 -11
- package/dist/storage/repositories/index-fts-repository.js +5 -2
- package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
- package/dist/storage/repositories/index-meta-repository.js +2 -3
- package/dist/storage/repositories/index-schema.js +10 -25
- package/dist/storage/repositories/index-utility-repository.js +15 -28
- package/dist/storage/repositories/index-vec-repository.js +6 -1
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +296 -59
- package/dist/storage/repositories/registry-cache.js +19 -0
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +15 -13
- package/dist/storage/repositories/workflow-runs-repository.js +52 -40
- package/dist/tasks/backends/cron.js +105 -15
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +85 -38
- package/dist/tasks/backends/schtasks.js +135 -15
- package/dist/tasks/embedded.js +56 -40
- package/dist/tasks/parser.js +7 -157
- package/dist/tasks/resolve-akm-bin.js +137 -59
- package/dist/tasks/runner.js +79 -42
- package/dist/tasks/scheduler-invocation.js +220 -10
- package/dist/tasks/schema.js +24 -1
- package/dist/tasks/task-id.js +1 -3
- package/dist/tasks/validator.js +20 -6
- package/dist/workflows/authoring/authoring.js +94 -143
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/exec/frozen-judge.js +28 -2
- package/dist/workflows/exec/native-executor.js +77 -57
- package/dist/workflows/exec/param-secrets.js +9 -9
- package/dist/workflows/exec/run-workflow.js +133 -79
- package/dist/workflows/exec/step-work.js +219 -346
- package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
- package/dist/workflows/ir/compile.js +141 -270
- package/dist/workflows/ir/freeze.js +40 -30
- package/dist/workflows/ir/params.js +135 -11
- package/dist/workflows/ir/plan-hash.js +1 -1
- package/dist/workflows/ir/schema.js +25 -26
- package/dist/workflows/parser.js +872 -307
- package/dist/workflows/program/expressions.js +20 -208
- package/dist/workflows/program/schema.js +7 -10
- package/dist/workflows/renderer.js +95 -68
- package/dist/workflows/resource-limits.js +2 -0
- package/dist/workflows/runtime/checkin.js +3 -3
- package/dist/workflows/runtime/plan-classifier.js +16 -75
- package/dist/workflows/runtime/runs.js +186 -127
- package/dist/workflows/runtime/unit-checkin.js +1 -1
- package/dist/workflows/runtime/unit-phases.js +2 -2
- package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +30 -36
- package/dist/workflows/validator.js +21 -62
- package/docs/README.md +68 -0
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.7.0.md +11 -11
- package/docs/migration/release-notes/0.9.0.md +208 -27
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +564 -208
- package/docs/migration/v0.9.0-troubleshooting.md +561 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/cli.md +2253 -0
- package/docs/reference/configuration.md +358 -0
- package/docs/reference/data-and-telemetry.md +105 -42
- package/docs/reference/workflows.md +647 -0
- package/package.json +22 -11
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +81 -128
- package/schemas/akm-workflow.json +74 -73
- package/dist/assets/tasks/core/backup.yml +0 -5
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/cli/config-migrate.js +0 -1806
- package/dist/cli/config-validate.js +0 -41
- package/dist/commands/backup-cli.js +0 -56
- package/dist/commands/bundle/bundle-cli.js +0 -68
- package/dist/commands/bundle/bundle.js +0 -219
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -489
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/mv-cli.js +0 -1221
- package/dist/commands/sources/history.js +0 -201
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/core/migration-backup.js +0 -1234
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/migrate/legacy/config-source-migration.js +0 -223
- package/dist/migrate/legacy/content-migration.js +0 -305
- package/dist/migrate/legacy/legacy-layout.js +0 -779
- package/dist/migrate/legacy/legacy-paths.js +0 -25
- package/dist/migrate/legacy/legacy-stash-json.js +0 -72
- package/dist/migrate/legacy/proposal-fs-import.js +0 -168
- package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
- package/dist/migrate/legacy/three-db-cutover.js +0 -841
- package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
- package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
- package/dist/migrate/legacy-ref-grammar.js +0 -214
- 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/registry/build-index.js +0 -382
- package/dist/schemas/akm-config.json +0 -4704
- package/dist/schemas/akm-task.json +0 -87
- package/dist/schemas/akm-workflow.json +0 -372
- package/dist/scripts/migrate-storage.js +0 -3816
- package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
- package/dist/workflows/cli.js +0 -53
- package/dist/workflows/exec/brief.js +0 -481
- package/dist/workflows/exec/report.js +0 -1460
- package/dist/workflows/exec/watch.js +0 -116
- package/dist/workflows/program/parser.js +0 -813
- package/dist/workflows/program/project.js +0 -104
|
@@ -15,29 +15,24 @@
|
|
|
15
15
|
* via the renderer contributor's throw → metadata-pass skip-with-warning; the
|
|
16
16
|
* `akm` adapter's synchronous `foldRecognizedMetadata` SWALLOWS the parse
|
|
17
17
|
* error, so a broken workflow would otherwise silently index. We re-run
|
|
18
|
-
* `parseWorkflow`
|
|
18
|
+
* `parseWorkflow` on drained workflow docs and DROP
|
|
19
19
|
* the entry with the same `Skipped workflow …` warning
|
|
20
20
|
* ({@link buildMetadataSkipWarning}), so the workflow-skip summary counts it.
|
|
21
21
|
* - **Workflow-document side-table (workflow-md only).** The valid parsed
|
|
22
22
|
* `WorkflowDocument` is handed to the persist layer through the same
|
|
23
23
|
* `document-cache` side channel the live renderer contributor used, keyed by
|
|
24
24
|
* the reconstructed entry — so `takeWorkflowDocument(entry)` in the persist
|
|
25
|
-
* loop writes the `workflow_documents` row exactly as before.
|
|
26
|
-
* are re-parsed from disk by the runtime loader, so they carry no cache row
|
|
27
|
-
* (mirrors the live path).
|
|
25
|
+
* loop writes the `workflow_documents` row exactly as before.
|
|
28
26
|
*
|
|
29
27
|
* `doc.hash` (= sha256 of the file content) is surfaced per recognized file so
|
|
30
28
|
* the persist layer can populate the `content_hash` column (item 2). It is keyed
|
|
31
|
-
* by the file's absolute path
|
|
32
|
-
* which rebuilds entry objects) rather than by the entry object.
|
|
29
|
+
* by the file's absolute path rather than by the entry object.
|
|
33
30
|
*
|
|
34
31
|
* Pure of DB/global state beyond the workflow-document side channel; a new leaf
|
|
35
32
|
* (nothing imports it back), so it joins no import cycle.
|
|
36
33
|
*/
|
|
37
34
|
import { akmAdapter } from "../../core/adapter/adapters/akm-adapter.js";
|
|
38
35
|
import { parseWorkflow } from "../../workflows/parser.js";
|
|
39
|
-
import { parseWorkflowProgram } from "../../workflows/program/parser.js";
|
|
40
|
-
import { WORKFLOW_PROGRAM_RENDERER_NAME } from "../../workflows/program/project.js";
|
|
41
36
|
import { cacheWorkflowDocument } from "../../workflows/runtime/document-cache.js";
|
|
42
37
|
import { buildMetadataSkipWarning } from "../passes/metadata.js";
|
|
43
38
|
import { buildFileContext } from "../walk/file-context.js";
|
|
@@ -62,6 +57,10 @@ export function drainDirDocuments(adapter, component, fileContexts) {
|
|
|
62
57
|
const doc = adapter.recognize(component, file);
|
|
63
58
|
if (doc === null)
|
|
64
59
|
continue;
|
|
60
|
+
if (!doc.conceptId) {
|
|
61
|
+
warnings.push(`Skipped ${file.absPath}: adapter "${adapter.id}" returned no conceptId.`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
65
64
|
const entry = indexDocumentToStashEntry(doc);
|
|
66
65
|
// Workflow docs: drop-with-warning if broken; otherwise cache the parsed
|
|
67
66
|
// markdown document for the persist-time `workflow_documents` write.
|
|
@@ -72,8 +71,7 @@ export function drainDirDocuments(adapter, component, fileContexts) {
|
|
|
72
71
|
}
|
|
73
72
|
if (doc.hash !== undefined)
|
|
74
73
|
hashByFile.set(file.absPath, doc.hash);
|
|
75
|
-
|
|
76
|
-
conceptIdByFile.set(file.absPath, doc.conceptId);
|
|
74
|
+
conceptIdByFile.set(file.absPath, doc.conceptId);
|
|
77
75
|
entries.push(entry);
|
|
78
76
|
}
|
|
79
77
|
return { entries, warnings, hashByFile, conceptIdByFile };
|
|
@@ -106,20 +104,12 @@ export function recognizeStashEntries(stashRoot, files) {
|
|
|
106
104
|
* `null` immediately.
|
|
107
105
|
*/
|
|
108
106
|
function handleWorkflowDoc(doc, entry, file) {
|
|
109
|
-
|
|
110
|
-
if (renderer === WORKFLOW_MD_RENDERER) {
|
|
111
|
-
const result = parseWorkflow(file.content(), { path: file.relPath });
|
|
112
|
-
if (!result.ok)
|
|
113
|
-
return workflowDropWarning(file, result.errors);
|
|
114
|
-
cacheWorkflowDocument(entry, result.document);
|
|
107
|
+
if (docRenderer(doc) !== WORKFLOW_MD_RENDERER)
|
|
115
108
|
return null;
|
|
116
|
-
}
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return workflowDropWarning(file, result.errors);
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
109
|
+
const result = parseWorkflow(file.content(), { path: file.relPath });
|
|
110
|
+
if (!result.ok)
|
|
111
|
+
return workflowDropWarning(file, result.errors);
|
|
112
|
+
cacheWorkflowDocument(entry, result.document);
|
|
123
113
|
return null;
|
|
124
114
|
}
|
|
125
115
|
/** The winning renderer name the `akm` adapter carries on `documentJson.renderer`, or `undefined`. */
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
* implementation, not a "local vs. remote" distinction.
|
|
15
15
|
*/
|
|
16
16
|
import fs from "node:fs";
|
|
17
|
+
import path from "node:path";
|
|
17
18
|
import { buildActionFromContributors, defaultActionContributors } from "../../core/action-contributors.js";
|
|
18
|
-
import {
|
|
19
|
+
import { stashDirFor } from "../../core/asset/asset-placement.js";
|
|
19
20
|
import { displayRef } from "../../core/asset/resolve-ref.js";
|
|
20
21
|
import { getDbPath } from "../../core/paths.js";
|
|
21
22
|
import { defaultRendererRegistry } from "../../core/type-presentation.js";
|
|
@@ -30,7 +31,7 @@ import { ensureIndex } from "../ensure-index.js";
|
|
|
30
31
|
import { collectGraphRelatedHit, loadGraphBoostContext } from "../graph/graph-boost.js";
|
|
31
32
|
import { isProposedQuality } from "../passes/metadata.js";
|
|
32
33
|
import { resolveProjectContext } from "../walk/project-context.js";
|
|
33
|
-
import { parseRefPrefixQuery, sanitizeFtsQuery } from "./fts-query.js";
|
|
34
|
+
import { parseRefPrefixQuery, parseRetiredTypePrefixQuery, sanitizeFtsQuery } from "./fts-query.js";
|
|
34
35
|
import { applyRankingRules, combineSearchScores, normalizeFtsScores } from "./ranking.js";
|
|
35
36
|
import { attachSearchHitAttribution, copySearchHitAttribution, getSearchHitAttribution } from "./search-attribution.js";
|
|
36
37
|
import { enrichSearchHit } from "./search-hit-enrichers.js";
|
|
@@ -44,6 +45,9 @@ import { deriveSemanticProviderFingerprint, getEffectiveSemanticStatus, isSemant
|
|
|
44
45
|
* actionable without re-introducing read-triggered reindexing.
|
|
45
46
|
*/
|
|
46
47
|
const STALE_INDEX_HINT_MS = 7 * 24 * 60 * 60 * 1000;
|
|
48
|
+
function hasIndexedProvenance(entry) {
|
|
49
|
+
return Boolean(entry.itemRef && entry.bundleId && entry.conceptId);
|
|
50
|
+
}
|
|
47
51
|
function buildStaleIndexHint(db) {
|
|
48
52
|
try {
|
|
49
53
|
const builtAt = getMeta(db, "builtAt");
|
|
@@ -59,21 +63,19 @@ function buildStaleIndexHint(db) {
|
|
|
59
63
|
return undefined;
|
|
60
64
|
}
|
|
61
65
|
}
|
|
66
|
+
function indexedProvenance(entry) {
|
|
67
|
+
return { itemRef: entry.itemRef, bundleId: entry.bundleId, conceptId: entry.conceptId };
|
|
68
|
+
}
|
|
62
69
|
export function buildLocalAction(type, ref, registry = defaultRendererRegistry) {
|
|
63
70
|
return buildActionFromContributors({ type, ref }, defaultActionContributors(registry)) ?? `akm show ${ref}`;
|
|
64
71
|
}
|
|
65
|
-
function resolveSearchHitRef(entry,
|
|
66
|
-
// F4b output-spelling flip: emit the 0.9.0 conceptId grammar for the hit's
|
|
67
|
-
// user-facing ref (short conceptId in the primary bundle, `bundle//conceptId`
|
|
68
|
-
// for a slug-clean non-default source). `displayRef` prefers the row's stored
|
|
69
|
-
// conceptId and derives `stashDir/name` (== the old `stashDir/name` body) when it
|
|
70
|
-
// is absent, so this is a pure ref-spelling change over the old output.
|
|
72
|
+
function resolveSearchHitRef(entry, provenance, defaultBundleId) {
|
|
71
73
|
return displayRef({
|
|
72
74
|
type: entry.type,
|
|
73
|
-
name:
|
|
74
|
-
conceptId:
|
|
75
|
-
bundleId:
|
|
76
|
-
});
|
|
75
|
+
name: entry.name,
|
|
76
|
+
conceptId: provenance.conceptId,
|
|
77
|
+
bundleId: provenance.bundleId,
|
|
78
|
+
}, defaultBundleId);
|
|
77
79
|
}
|
|
78
80
|
function resolveSearchHitOrigin(source) {
|
|
79
81
|
return source?.registryId ?? null;
|
|
@@ -130,7 +132,26 @@ export async function searchLocal(input) {
|
|
|
130
132
|
}
|
|
131
133
|
}
|
|
132
134
|
if (config.semanticSearchMode === "auto" && semanticStatus === "blocked") {
|
|
133
|
-
|
|
135
|
+
if (!config.embedding?.endpoint || !config.embedding?.model) {
|
|
136
|
+
// F7/A2: same predicate as the `pending` branch above (#480) — a
|
|
137
|
+
// `blocked` status can outlive the provider config that produced it
|
|
138
|
+
// (e.g. the embedding config was later unset). This is not a fault;
|
|
139
|
+
// there is simply nothing configured to use.
|
|
140
|
+
warnings.push("Semantic search is enabled (semanticSearchMode='auto') but no embedding provider is configured. " +
|
|
141
|
+
'Either: (a) `akm config set embedding \'{"endpoint":"...","model":"..."}\'`, or ' +
|
|
142
|
+
"(b) `akm config set semanticSearchMode off` to use keyword-only search.");
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// F7/A2: surface the ACTUAL diagnostic instead of one fixed generic
|
|
146
|
+
// string. `rawStatus.reason`/`rawStatus.message` record why the
|
|
147
|
+
// semantic backend failed (auth, network, a stuck local-model
|
|
148
|
+
// download, …) — read at `readSemanticStatus()` above and, before
|
|
149
|
+
// this fix, discarded here in favor of a message that never varied.
|
|
150
|
+
const detail = rawStatus?.message ?? (rawStatus?.reason ? `reason: ${rawStatus.reason}` : undefined);
|
|
151
|
+
warnings.push(`Semantic search is blocked${detail ? ` (${detail})` : ""}. Using keyword search until the semantic ` +
|
|
152
|
+
"backend is healthy again. Run 'akm index --full' to retry, or " +
|
|
153
|
+
"`akm config set semanticSearchMode off` to silence this warning.");
|
|
154
|
+
}
|
|
134
155
|
}
|
|
135
156
|
// Bootstrap-only: builds the index inline when it cannot serve this stash.
|
|
136
157
|
// Content freshness is the writers' job (indexWrittenAssets + full runs);
|
|
@@ -162,9 +183,7 @@ export async function searchLocal(input) {
|
|
|
162
183
|
const { hits, embedMs, rankMs, usedSemantic } = await searchDatabase(db, query, searchType, limit, stashDir, allSourceDirs, config, sources, rendererRegistry, filters, includeProposed, beliefFilter, restrictToSources, includeExcludedTypes, disableProjectContext, disableScopedUtility);
|
|
163
184
|
return {
|
|
164
185
|
hits,
|
|
165
|
-
tip: hits.length === 0
|
|
166
|
-
? "No matching stash assets were found. Try a different query or run 'akm index' to rebuild."
|
|
167
|
-
: undefined,
|
|
186
|
+
tip: hits.length === 0 ? emptyResultTip(query) : undefined,
|
|
168
187
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
169
188
|
embedMs,
|
|
170
189
|
rankMs,
|
|
@@ -185,14 +204,15 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
|
|
|
185
204
|
// `includeExcludedTypes`. When the config key is ABSENT a built-in default of
|
|
186
205
|
// ['session'] is applied; an explicit empty list disables exclusion.
|
|
187
206
|
const defaultExcludes = searchType === "any" && !includeExcludedTypes ? (config.search?.defaultExcludeTypes ?? ["session"]) : [];
|
|
188
|
-
//
|
|
189
|
-
// a
|
|
190
|
-
// the AND-token FTS query their
|
|
191
|
-
// projecta" — noise). The branch
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
// `
|
|
195
|
-
|
|
207
|
+
// D4 — conceptId-prefix queries (`memories/projecta/`, `bundle//`,
|
|
208
|
+
// `bundle//skills/`) translate to a deterministic enumeration narrowed by
|
|
209
|
+
// conceptId, instead of degenerating into the AND-token FTS query their
|
|
210
|
+
// sanitized form would produce ("memories projecta" — noise). The branch
|
|
211
|
+
// fires only on the untyped path: an explicit `--type` flag expresses
|
|
212
|
+
// stronger intent and wins. The PREFIX is itself explicit intent, so
|
|
213
|
+
// `defaultExcludeTypes` does not apply — `sessions/` enumerates sessions
|
|
214
|
+
// exactly like `--type session` does, and `bundle//` means the whole bundle.
|
|
215
|
+
const refPrefix = searchType === "any" ? parseRefPrefixQuery(query) : null;
|
|
196
216
|
// Shared args for the two browse paths below; browse never runs semantic
|
|
197
217
|
// ranking, so both return usedSemantic: false.
|
|
198
218
|
const browseArgs = {
|
|
@@ -210,13 +230,13 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
|
|
|
210
230
|
restrictToSources,
|
|
211
231
|
};
|
|
212
232
|
if (refPrefix) {
|
|
213
|
-
// Browse path (
|
|
233
|
+
// Browse path (conceptId-prefix enumeration).
|
|
214
234
|
return {
|
|
215
235
|
...(await enumerateEntries({
|
|
216
236
|
...browseArgs,
|
|
217
|
-
typeFilter: refPrefix.type,
|
|
218
237
|
excludeTypes: [],
|
|
219
|
-
|
|
238
|
+
conceptIdPrefix: refPrefix.conceptIdPrefix,
|
|
239
|
+
...(refPrefix.bundle !== undefined ? { bundle: refPrefix.bundle } : {}),
|
|
220
240
|
})),
|
|
221
241
|
usedSemantic: false,
|
|
222
242
|
};
|
|
@@ -272,7 +292,7 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
|
|
|
272
292
|
// not leak into default ('any') results. defaultExcludes is already []
|
|
273
293
|
// unless this is the untyped path without includeExcludedTypes.
|
|
274
294
|
excludeTypes: defaultExcludes,
|
|
275
|
-
});
|
|
295
|
+
}).filter(hasIndexedProvenance);
|
|
276
296
|
// ── Scoring Phase ──────────────────────────────────────────────────────
|
|
277
297
|
// Apply boosts as multiplicative factors (all boosts in a single phase
|
|
278
298
|
// so that sort order and displayed scores are always consistent).
|
|
@@ -298,7 +318,7 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
|
|
|
298
318
|
})();
|
|
299
319
|
// Resolve project-context tokens from the current working directory once
|
|
300
320
|
// per search invocation. Returns null when running from home dir / /tmp,
|
|
301
|
-
// or when the caller
|
|
321
|
+
// or when the caller passed `--no-project-context` (disableProjectContext).
|
|
302
322
|
const projectContext = disableProjectContext ? null : resolveProjectContext(process.cwd());
|
|
303
323
|
// Phase 2A / Rec 5: resolve forgetting-curve config and skip the feedback
|
|
304
324
|
// count query when the boost cannot make a difference (default ≤ 1.0 means
|
|
@@ -316,7 +336,8 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
|
|
|
316
336
|
? getPositiveFeedbackCountsByIds(scored.map((item) => item.id))
|
|
317
337
|
: undefined;
|
|
318
338
|
// Resolve per-project scope key for scoped utility scoring.
|
|
319
|
-
//
|
|
339
|
+
// `disableScopedUtility` (wired from `akm search --no-project-context`)
|
|
340
|
+
// opts out (e.g. for registry searches or tests).
|
|
320
341
|
let scopeKey;
|
|
321
342
|
try {
|
|
322
343
|
scopeKey = disableScopedUtility ? undefined : getCurrentWorkflowScopeKey();
|
|
@@ -365,9 +386,6 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
|
|
|
365
386
|
const displayScore = (s) => Math.round(Math.min(1, Math.max(0, s)) * 10000) / 10000;
|
|
366
387
|
preFilter.sort((a, b) => displayScore(b.score) - displayScore(a.score) || a.entry.name.localeCompare(b.entry.name));
|
|
367
388
|
// Deduplicate by file path — keep only the highest-scored entry per file.
|
|
368
|
-
// Multiple legacy-sidecar entries can map to the same file (e.g. entries without
|
|
369
|
-
// a filename field all collapse to files[0]). Showing the same path/ref
|
|
370
|
-
// multiple times clutters results.
|
|
371
389
|
const deduped = deduplicateByPath(preFilter);
|
|
372
390
|
// Source → scope → proposed-quality → derived-twin belief inheritance →
|
|
373
391
|
// belief: the post-candidate filter chain shared with enumerateEntries (see
|
|
@@ -396,7 +414,7 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
|
|
|
396
414
|
return buildDbHit({
|
|
397
415
|
entry,
|
|
398
416
|
path: filePath,
|
|
399
|
-
|
|
417
|
+
...indexedProvenance(ranked),
|
|
400
418
|
score: Math.round(finalScore * 10000) / 10000,
|
|
401
419
|
query,
|
|
402
420
|
rankingMode,
|
|
@@ -413,18 +431,33 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
|
|
|
413
431
|
}));
|
|
414
432
|
return { embedMs, rankMs, hits, usedSemantic };
|
|
415
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* The no-hits tip. A query in the retired `<type>:` / `<type>:<prefix>/` browse
|
|
436
|
+
* grammar gets the conceptId spelling that replaces it: without this it comes
|
|
437
|
+
* back empty and silent, which is the failure D4 removed the grammar to avoid.
|
|
438
|
+
*/
|
|
439
|
+
function emptyResultTip(query) {
|
|
440
|
+
const generic = "No matching stash assets were found. Try a different query or run 'akm index' to rebuild.";
|
|
441
|
+
const retired = parseRetiredTypePrefixQuery(query);
|
|
442
|
+
if (!retired)
|
|
443
|
+
return generic;
|
|
444
|
+
const root = stashDirFor(retired.type);
|
|
445
|
+
if (!root)
|
|
446
|
+
return generic;
|
|
447
|
+
return `No matching stash assets were found. The '<type>:' browse grammar was removed in 0.9.0 — use the conceptId spelling: 'akm search "${root}/${retired.rest}"'.`;
|
|
448
|
+
}
|
|
416
449
|
// ── Enumeration (browse) path ────────────────────────────────────────────────
|
|
417
450
|
/**
|
|
418
451
|
* Enumerate index entries without FTS scoring — the browse path shared by
|
|
419
|
-
* empty/unsearchable queries and
|
|
420
|
-
*
|
|
452
|
+
* empty/unsearchable queries and D4 conceptId-prefix queries (`memories/`,
|
|
453
|
+
* `bundle//`, `bundle//skills/`). Applies the same post-ranking filters as the scored
|
|
421
454
|
* path (source narrowing, scope, proposed-quality, belief) before the limit
|
|
422
455
|
* slice. Hits carry the fixed browse score 1 in type-then-name order — this is
|
|
423
456
|
* a deterministic listing, not a relevance ranking.
|
|
424
457
|
*/
|
|
425
458
|
async function enumerateEntries(opts) {
|
|
426
459
|
const { db, query, sources, config, rendererRegistry, filters, beliefFilter } = opts;
|
|
427
|
-
const allEntries = getAllEntries(db, opts.typeFilter, opts.excludeTypes);
|
|
460
|
+
const allEntries = getAllEntries(db, opts.typeFilter, opts.excludeTypes).filter(hasIndexedProvenance);
|
|
428
461
|
// Explicit listing order: type, then name, then filePath. The underlying
|
|
429
462
|
// SELECT carries no ORDER BY, so its row order tracks the query plan and the
|
|
430
463
|
// index-insertion (file-walk) order — both machine-dependent. A browse
|
|
@@ -432,11 +465,17 @@ async function enumerateEntries(opts) {
|
|
|
432
465
|
allEntries.sort((a, b) => a.entry.type.localeCompare(b.entry.type) ||
|
|
433
466
|
a.entry.name.localeCompare(b.entry.name) ||
|
|
434
467
|
a.filePath.localeCompare(b.filePath));
|
|
435
|
-
//
|
|
436
|
-
//
|
|
437
|
-
//
|
|
438
|
-
|
|
439
|
-
|
|
468
|
+
// D4: narrow to the requested bundle and subtree. Matching is against the
|
|
469
|
+
// conceptId — the spelling every emitted `ref` carries — so a ref copied out
|
|
470
|
+
// of search output round-trips back in. `startsWith` on the full
|
|
471
|
+
// slash-retaining prefix is exact: "memories/projecta/" cannot match a
|
|
472
|
+
// sibling "memories/projectalpha/…" scope.
|
|
473
|
+
const bundle = opts.bundle?.toLowerCase();
|
|
474
|
+
const bundleFiltered = bundle === undefined ? allEntries : allEntries.filter((ie) => ie.bundleId.toLowerCase() === bundle);
|
|
475
|
+
const conceptIdPrefix = opts.conceptIdPrefix?.toLowerCase() ?? "";
|
|
476
|
+
const prefixFiltered = conceptIdPrefix.length > 0
|
|
477
|
+
? bundleFiltered.filter((ie) => ie.conceptId.toLowerCase().startsWith(conceptIdPrefix))
|
|
478
|
+
: bundleFiltered;
|
|
440
479
|
// Deduplicate by file path — multiple entries can share the same file
|
|
441
480
|
const seenFilePaths = new Set();
|
|
442
481
|
const uniqueEntries = prefixFiltered.filter((ie) => {
|
|
@@ -464,6 +503,9 @@ async function enumerateEntries(opts) {
|
|
|
464
503
|
const hits = await Promise.all(selected.map((ie) => buildDbHit({
|
|
465
504
|
entry: ie.entry,
|
|
466
505
|
path: ie.filePath,
|
|
506
|
+
itemRef: ie.itemRef,
|
|
507
|
+
bundleId: ie.bundleId,
|
|
508
|
+
conceptId: ie.conceptId,
|
|
467
509
|
score: 1,
|
|
468
510
|
query,
|
|
469
511
|
rankingMode: "fts",
|
|
@@ -502,10 +544,10 @@ async function enumerateEntries(opts) {
|
|
|
502
544
|
*/
|
|
503
545
|
function applyEntryFilters(items, opts) {
|
|
504
546
|
const { filters } = opts;
|
|
505
|
-
// Source filter: when the caller narrowed `sources` via `--
|
|
547
|
+
// Source filter: when the caller narrowed `sources` via `--from <name>`,
|
|
506
548
|
// drop entries whose filePath does not live under any requested source. The
|
|
507
549
|
// FTS/enumerate index spans every configured source, so without this filter a
|
|
508
|
-
// narrowed --
|
|
550
|
+
// narrowed --from request would still leak results from other sources.
|
|
509
551
|
const sourceFiltered = opts.restrictToSources
|
|
510
552
|
? items.filter((item) => findSourceForPath(item.filePath, opts.sources) !== undefined)
|
|
511
553
|
: items;
|
|
@@ -598,7 +640,8 @@ async function tryVecScores(db, query, k, config) {
|
|
|
598
640
|
// ── Hit building ────────────────────────────────────────────────────────────
|
|
599
641
|
export async function buildDbHit(input) {
|
|
600
642
|
const rendererRegistry = input.rendererRegistry ?? defaultRendererRegistry;
|
|
601
|
-
const
|
|
643
|
+
const absolutePath = path.resolve(input.path);
|
|
644
|
+
const entryStashDir = findSourceForPath(absolutePath, input.sources)?.path ?? input.defaultStashDir;
|
|
602
645
|
// Quality and confidence boosts are now applied in the main scoring
|
|
603
646
|
// phase (searchDatabase). buildDbHit receives the already-final score and
|
|
604
647
|
// passes it through without further multiplication. We still compute the
|
|
@@ -611,21 +654,23 @@ export async function buildDbHit(input) {
|
|
|
611
654
|
const score = Math.round(input.score * 10000) / 10000;
|
|
612
655
|
const graphBoost = getSearchHitAttribution(input.attributionSource ?? {})?.graphExtraction?.boost ?? 0;
|
|
613
656
|
const whyMatched = buildWhyMatched(input.entry, input.query, input.rankingMode, qualityBoost, confidenceBoost, input.utilityBoosted, graphBoost);
|
|
614
|
-
const graphHit = input.graphContext ? collectGraphRelatedHit(input.graphContext,
|
|
615
|
-
const source = findSourceForPath(
|
|
616
|
-
const
|
|
617
|
-
|
|
657
|
+
const graphHit = input.graphContext ? collectGraphRelatedHit(input.graphContext, absolutePath) : null;
|
|
658
|
+
const source = findSourceForPath(absolutePath, input.sources);
|
|
659
|
+
const defaultBundleId = input.config?.defaultBundle ??
|
|
660
|
+
(source && path.resolve(source.path) === path.resolve(input.defaultStashDir)
|
|
661
|
+
? (input.bundleId ?? undefined)
|
|
662
|
+
: undefined);
|
|
663
|
+
const ref = resolveSearchHitRef(input.entry, input, defaultBundleId);
|
|
664
|
+
const editable = isEditable(absolutePath, input.config, input.sources);
|
|
618
665
|
const estimatedTokens = typeof input.entry.fileSize === "number" ? Math.round(input.entry.fileSize / 4) : undefined;
|
|
619
666
|
const hit = {
|
|
620
667
|
type: input.entry.type,
|
|
621
668
|
name: input.entry.name,
|
|
622
|
-
path:
|
|
669
|
+
path: absolutePath,
|
|
623
670
|
ref,
|
|
624
671
|
origin: resolveSearchHitOrigin(source),
|
|
625
672
|
editable,
|
|
626
|
-
...(!editable
|
|
627
|
-
? { editHint: buildEditHint(input.path, input.entry.type, input.entry.name, source?.registryId) }
|
|
628
|
-
: {}),
|
|
673
|
+
...(!editable ? { editHint: buildEditHint(ref) } : {}),
|
|
629
674
|
description: input.entry.description,
|
|
630
675
|
tags: input.entry.tags,
|
|
631
676
|
size: deriveSize(input.entry.fileSize),
|
|
@@ -744,7 +789,7 @@ function deduplicateByPath(items) {
|
|
|
744
789
|
});
|
|
745
790
|
}
|
|
746
791
|
/**
|
|
747
|
-
* Exact-match scope filter check.
|
|
792
|
+
* Exact-match scope filter check. Entries without a `scope` object only
|
|
748
793
|
* match when no filter is supplied — which is what the caller guards on
|
|
749
794
|
* before invoking this helper.
|
|
750
795
|
*/
|
|
@@ -52,41 +52,64 @@ export function buildPrefixQuery(ftsQuery) {
|
|
|
52
52
|
return prefixTokens.join(" ");
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
55
|
+
* D4 — parse a conceptId-prefix browse query.
|
|
56
56
|
*
|
|
57
|
-
* Decides whether a raw query is a
|
|
58
|
-
*
|
|
59
|
-
*
|
|
57
|
+
* Decides whether a raw query is a subtree-enumeration request rather than an
|
|
58
|
+
* ordinary keyword search. Matching is deliberately conservative: the trimmed
|
|
59
|
+
* query must be EXACTLY
|
|
60
60
|
*
|
|
61
|
-
* - `<
|
|
62
|
-
* - `<
|
|
61
|
+
* - `<conceptId prefix>/` → that subtree in any bundle,
|
|
62
|
+
* - `<bundle>//` → one bundle entirely,
|
|
63
|
+
* - `<bundle>//<conceptId prefix>/` → that subtree of that bundle.
|
|
63
64
|
*
|
|
64
|
-
* The trailing slash is REQUIRED
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
65
|
+
* The trailing slash is REQUIRED — and is RETAINED in `conceptIdPrefix` — so a
|
|
66
|
+
* plain `conceptId.startsWith(conceptIdPrefix)` check gives exact `/`-boundary
|
|
67
|
+
* subtree semantics (`"projecta/"` cannot match a sibling `projectalpha/…`
|
|
68
|
+
* scope). Bare refs like `memories/a/b` therefore stay ordinary searches
|
|
69
|
+
* (resolving one ref is `akm show` territory), and any interior whitespace
|
|
70
|
+
* disqualifies (prose mentioning a ref is still prose).
|
|
70
71
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
72
|
+
* The prefix matches the conceptId — the same string every emitted `ref`
|
|
73
|
+
* carries — so a ref copied out of search output round-trips back in as a
|
|
74
|
+
* prefix. Nothing here consults a type list: enumeration covers every
|
|
75
|
+
* adapter's items uniformly, which the retired `<type>:` grammar could not do.
|
|
73
76
|
*
|
|
74
|
-
* Returns `null` when the query is not a
|
|
77
|
+
* Returns `null` when the query is not a browse request.
|
|
75
78
|
*/
|
|
76
|
-
export function parseRefPrefixQuery(query
|
|
79
|
+
export function parseRefPrefixQuery(query) {
|
|
77
80
|
const trimmed = query.trim();
|
|
78
81
|
if (trimmed.length === 0 || /\s/.test(trimmed))
|
|
79
82
|
return null;
|
|
83
|
+
const separator = trimmed.indexOf("//");
|
|
84
|
+
if (separator < 0) {
|
|
85
|
+
return trimmed.endsWith("/") ? { conceptIdPrefix: trimmed } : null;
|
|
86
|
+
}
|
|
87
|
+
const bundle = trimmed.slice(0, separator);
|
|
88
|
+
if (bundle.length === 0)
|
|
89
|
+
return null;
|
|
90
|
+
const rest = trimmed.slice(separator + 2);
|
|
91
|
+
if (rest === "")
|
|
92
|
+
return { bundle, conceptIdPrefix: "" };
|
|
93
|
+
if (rest.endsWith("/") && !rest.includes("//"))
|
|
94
|
+
return { bundle, conceptIdPrefix: rest };
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Recognize the retired `<type>:` / `<type>:<prefix>/` browse grammar so the
|
|
99
|
+
* caller can name the replacement spelling rather than letting the query
|
|
100
|
+
* degrade silently into a keyword search — the exact silent failure D4 removes.
|
|
101
|
+
* Shape recognition only; mapping the type to its conceptId root belongs to the
|
|
102
|
+
* caller, which keeps this module dependency-free.
|
|
103
|
+
*/
|
|
104
|
+
export function parseRetiredTypePrefixQuery(query) {
|
|
105
|
+
const trimmed = query.trim();
|
|
106
|
+
if (trimmed.length === 0 || /\s/.test(trimmed) || trimmed.includes("//"))
|
|
107
|
+
return null;
|
|
80
108
|
const colon = trimmed.indexOf(":");
|
|
81
109
|
if (colon <= 0)
|
|
82
110
|
return null;
|
|
83
|
-
const type = trimmed.slice(0, colon);
|
|
84
|
-
if (!knownTypes.includes(type))
|
|
85
|
-
return null;
|
|
86
111
|
const rest = trimmed.slice(colon + 1);
|
|
87
|
-
if (rest
|
|
88
|
-
return
|
|
89
|
-
|
|
90
|
-
return { type, namePrefix: rest };
|
|
91
|
-
return null;
|
|
112
|
+
if (rest !== "" && !rest.endsWith("/"))
|
|
113
|
+
return null;
|
|
114
|
+
return { type: trimmed.slice(0, colon), rest };
|
|
92
115
|
}
|
|
@@ -51,13 +51,19 @@ const MAX_BOOST_SUM = 3.0;
|
|
|
51
51
|
const UTILITY_WEIGHT = 0.5;
|
|
52
52
|
const UTILITY_MAX_BOOST = 1.5;
|
|
53
53
|
/**
|
|
54
|
-
* R2 — weight of the improve
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
54
|
+
* R2 / #692 — weight of the improve loop's `asset_salience.rank_score`.
|
|
55
|
+
* rank_score ∈ [0,1] → boost ∈ [1, 1.2]. Bounded well below the utility boost
|
|
56
|
+
* so the composed signal would refine, never dominate, lexical/semantic
|
|
57
|
+
* relevance.
|
|
58
|
+
*
|
|
59
|
+
* As of #692 this is NOT wired into default user-facing ranking — see
|
|
60
|
+
* {@link salienceRankingContributor}'s doc comment. Kept exported (with the
|
|
61
|
+
* contributor) for a future gated experiment; do not reintroduce it into
|
|
62
|
+
* {@link defaultUtilityRankingContributors} without a measured
|
|
63
|
+
* curate-golden-bench delta and an explicit config gate.
|
|
58
64
|
*/
|
|
59
|
-
const SALIENCE_WEIGHT = 0.2;
|
|
60
|
-
const SALIENCE_MAX_BOOST = 1.2;
|
|
65
|
+
export const SALIENCE_WEIGHT = 0.2;
|
|
66
|
+
export const SALIENCE_MAX_BOOST = 1.2;
|
|
61
67
|
/**
|
|
62
68
|
* Phase 2A / Rec 5: default recency half-life (days) used when no
|
|
63
69
|
* `utilityDecayConfig` is supplied to the ranking pipeline. Matches the
|
|
@@ -113,7 +119,7 @@ function beliefStateBoost(item) {
|
|
|
113
119
|
* a ceilinged one; demoted entries still list (belief FILTERING stays a
|
|
114
120
|
* separate opt-in axis, `--belief`), and scores already below a ceiling keep
|
|
115
121
|
* their relative ordering. Ceiling order mirrors the additive-penalty
|
|
116
|
-
* severity order pinned in tests/belief-state-phase1a.test.ts:
|
|
122
|
+
* severity order pinned in tests/integration/belief-state-phase1a.test.ts:
|
|
117
123
|
* deprecated (mildest) > superseded > contradicted > archived.
|
|
118
124
|
*/
|
|
119
125
|
const BELIEF_STATE_SCORE_CEILINGS = {
|
|
@@ -290,7 +296,7 @@ const graphRankingContributor = {
|
|
|
290
296
|
*
|
|
291
297
|
* Memories captured via the hot path (`akm remember`) get a modest additive
|
|
292
298
|
* boost so they outrank otherwise-equal background-derived memories. Memories
|
|
293
|
-
* without `captureMode`
|
|
299
|
+
* without `captureMode` return 0.
|
|
294
300
|
*/
|
|
295
301
|
const captureModeRankingContributor = {
|
|
296
302
|
name: "capture-mode-ranking",
|
|
@@ -404,7 +410,7 @@ const utilityRankingContributor = {
|
|
|
404
410
|
*
|
|
405
411
|
* Skipped entirely when `projectContext` is absent or has no tokens (e.g.
|
|
406
412
|
* when running from home dir, /tmp, or when disabled via
|
|
407
|
-
* `--no-project-context`
|
|
413
|
+
* `--no-project-context`).
|
|
408
414
|
*/
|
|
409
415
|
const projectContextRankingContributor = {
|
|
410
416
|
name: "project-context-ranking",
|
|
@@ -444,15 +450,31 @@ export const defaultRankingContributors = [
|
|
|
444
450
|
projectContextRankingContributor,
|
|
445
451
|
];
|
|
446
452
|
/**
|
|
447
|
-
* R2 —
|
|
453
|
+
* R2 — the improve loop's salience core, as a bounded multiplicative ranking
|
|
454
|
+
* boost. `asset_salience.rank_score` (encoding + outcome + retrieval
|
|
455
|
+
* projection, maintained every improve run) otherwise drives only improve's
|
|
456
|
+
* INTERNAL maintenance selection.
|
|
457
|
+
*
|
|
458
|
+
* **#692 — NOT in {@link defaultUtilityRankingContributors}.** Removed from
|
|
459
|
+
* default user-facing ranking (search/curate): the boost was
|
|
460
|
+
* retrieval-dominated (`w_r = 0.60` in salience.ts, with no source filter, so
|
|
461
|
+
* it double-counted the same `usage_events` the utility EMA contributor
|
|
462
|
+
* already reinforces), warm-started non-zero with no outcome evidence, had
|
|
463
|
+
* zero pack coverage (favoring only self-generated personal assets), and
|
|
464
|
+
* measured as noise on live data (max observed multiplier ×1.071). Removing
|
|
465
|
+
* its default state.db load also deleted a confirmed hot-path defect — see
|
|
466
|
+
* the now-deleted `loadSalienceRankScores` in `ranking.ts` git history.
|
|
448
467
|
*
|
|
449
|
-
* `
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
468
|
+
* `rank_score` itself is UNCHANGED as improve's internal selection signal.
|
|
469
|
+
* This contributor, and its weight/cap constants, stay exported so a FUTURE
|
|
470
|
+
* gated experiment (config-gated, outcome-gated) can wire it back in
|
|
471
|
+
* explicitly — see `RankEntriesOptions.salienceRankScores`'s doc comment in
|
|
472
|
+
* `ranking.ts`. Reachable today only via explicit contributor-list injection
|
|
473
|
+
* (tests / eval harnesses calling `applyUtilityContributors` directly with a
|
|
474
|
+
* list that includes it) — never through `applyRankingRules` / `akm search` /
|
|
475
|
+
* `akm curate`.
|
|
454
476
|
*/
|
|
455
|
-
const salienceRankingContributor = {
|
|
477
|
+
export const salienceRankingContributor = {
|
|
456
478
|
name: "salience-ranking",
|
|
457
479
|
appliesTo(item, ctx) {
|
|
458
480
|
const rank = ctx.salienceRankScores?.get(item.id);
|
|
@@ -464,10 +486,10 @@ const salienceRankingContributor = {
|
|
|
464
486
|
item.score *= Math.min(rawBoost, SALIENCE_MAX_BOOST);
|
|
465
487
|
},
|
|
466
488
|
};
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
];
|
|
489
|
+
// #692 — salienceRankingContributor deliberately excluded; see its doc
|
|
490
|
+
// comment. Do not add it back here without a config gate + a measured
|
|
491
|
+
// curate-golden-bench delta justifying it.
|
|
492
|
+
export const defaultUtilityRankingContributors = [utilityRankingContributor];
|
|
471
493
|
/**
|
|
472
494
|
* EVAL/DEBUG ONLY — remove named ranking contributors from a list.
|
|
473
495
|
*
|