akm-cli 0.9.16 → 0.9.17-alpha.10
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 +2101 -0
- package/STABILITY.md +11 -10
- package/dist/akm +124 -193
- package/dist/akm-migrate +38 -19
- package/dist/assets/hints/cli-hints-full.md +6 -7
- package/dist/assets/improve-strategies/catchup.json +0 -3
- package/dist/assets/improve-strategies/consolidate.json +0 -1
- package/dist/assets/improve-strategies/default.json +1 -2
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
- package/dist/assets/improve-strategies/quick.json +1 -2
- package/dist/assets/improve-strategies/reflect-distill.json +1 -2
- package/dist/assets/improve-strategies/thorough.json +0 -3
- package/dist/assets/prompts/consolidate-pair.md +20 -0
- package/dist/assets/prompts/consolidate-system.md +4 -11
- package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +20 -20
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
- package/dist/assets/templates/html/health.html +3 -5
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +6 -2
- package/dist/cli/unknown-flags.js +24 -1
- package/dist/cli.js +68 -10
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +6 -0
- package/dist/commands/health/archive-usage.js +92 -0
- package/dist/commands/health/checks.js +83 -74
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/data-dir-usage.js +25 -13
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +1 -42
- package/dist/commands/health/improve-metrics.js +136 -591
- package/dist/commands/health/md-report.js +1 -6
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +14 -120
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -74
- package/dist/commands/health.js +145 -143
- package/dist/commands/improve/consolidate/chunking.js +26 -117
- package/dist/commands/improve/consolidate/continuity-check.js +137 -0
- package/dist/commands/improve/consolidate/pair-pass.js +791 -0
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +589 -1127
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1041
- package/dist/commands/improve/eligibility.js +126 -390
- package/dist/commands/improve/execution.js +8 -10
- package/dist/commands/improve/extract-prompt.js +1 -2
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +75 -169
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +52 -4
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +480 -1074
- package/dist/commands/improve/ledger.js +119 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +415 -1073
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +16 -118
- package/dist/commands/improve/memory/memory-improve.js +266 -14
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -15
- package/dist/commands/improve/preparation.js +779 -2319
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +642 -1353
- package/dist/commands/improve/retrieval-gate.js +127 -0
- package/dist/commands/improve/retrieval-scope.js +92 -0
- package/dist/commands/improve/salience.js +41 -240
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +322 -0
- package/dist/commands/lint/base-linter.js +37 -15
- package/dist/commands/proposal/drain.js +261 -578
- package/dist/commands/proposal/proposal-cli.js +19 -20
- package/dist/commands/proposal/proposal-types.js +31 -24
- package/dist/commands/proposal/proposal.js +38 -8
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +1097 -1394
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +22 -89
- package/dist/commands/read/curate.js +105 -462
- package/dist/commands/read/knowledge.js +3 -2
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +57 -108
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +4 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +127 -29
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/source-manage.js +9 -2
- package/dist/commands/sources/stash-cli.js +24 -4
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +12 -13
- package/dist/commands/tasks/tasks.js +350 -936
- package/dist/commands/tasks/validate.js +26 -24
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +2 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +42 -12
- package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/asset-placement.js +4 -13
- package/dist/core/asset/frontmatter.js +106 -1
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +285 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +9 -34
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +184 -111
- package/dist/core/config/engine-semantics.js +0 -2
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +54 -125
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/index-config.js +9 -48
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-change.js +13 -5
- package/dist/core/file-lock.js +76 -173
- package/dist/core/improve-result.js +35 -7
- package/dist/core/improve-types.js +0 -1
- package/dist/core/logs-db.js +2 -2
- package/dist/core/loopback.js +7 -12
- package/dist/core/non-task-input.js +20 -0
- package/dist/core/parse.js +13 -16
- package/dist/core/paths.js +0 -24
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +123 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/time.js +0 -20
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +294 -1005
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/ensure-index.js +77 -73
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +141 -154
- package/dist/indexer/indexer.js +400 -1124
- package/dist/indexer/links/declared-links.js +90 -0
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +96 -90
- package/dist/indexer/passes/metadata.js +132 -219
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +2 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +190 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +36 -7
- package/dist/indexer/walk/walker.js +3 -4
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/client.js +18 -6
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +11 -17
- package/dist/llm/feature-gate.js +0 -8
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +25 -38
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/graph/graph-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +69 -31
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +48 -3
- package/dist/output/text/show-format.js +13 -17
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +42948 -92369
- package/dist/scripts/akm-migrate.js +42935 -92354
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/connection.js +5 -6
- package/dist/setup/steps/platforms.js +2 -2
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +83 -21
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +209 -0
- package/dist/storage/repositories/index-connection.js +39 -72
- package/dist/storage/repositories/index-entries-repository.js +131 -129
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +101 -268
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-links-repository.js +143 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +7 -9
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +257 -325
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +104 -1
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/salience-repository.js +1 -19
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +130 -0
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +191 -302
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +141 -748
- package/dist/tasks/backends/schtasks.js +119 -623
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/run/load-task.js +1 -1
- package/dist/tasks/scheduler-binding.js +20 -238
- package/dist/tasks/scheduler-invocation.js +136 -244
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +368 -679
- package/dist/tasks/source/parse-task-source.js +55 -9
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +464 -88
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +43 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +23 -7
- package/docs/reference/cli.md +232 -135
- package/docs/reference/configuration.md +71 -57
- package/docs/reference/data-and-telemetry.md +20 -21
- package/docs/reference/tasks.md +105 -39
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +115 -738
- package/schemas/akm-workflow.json +1 -0
- package/dist/assets/improve-strategies/graph-refresh.json +0 -15
- package/dist/assets/prompts/contradiction-judge.md +0 -33
- package/dist/assets/prompts/graph-extract-system.md +0 -1
- package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
- package/dist/assets/prompts/metadata-enhance-system.md +0 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -149
- package/dist/commands/improve/distill/promote-memory.js +0 -291
- package/dist/commands/improve/distill/quality-gate.js +0 -337
- package/dist/commands/improve/eval-cases.js +0 -52
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -31
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -427
- package/dist/indexer/db/graph-db.js +0 -444
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/graph/graph-extraction.js +0 -1108
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/search/ranking-types.js +0 -4
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/llm/graph-extract.js +0 -728
- package/dist/llm/metadata-enhance.js +0 -96
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/tasks/source/task-to-v3.js +0 -507
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -77
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -2,61 +2,57 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* index.db schema
|
|
6
|
-
*
|
|
7
|
-
* evolution) from the CRUD/FTS/vector queries.
|
|
5
|
+
* index.db schema, kept in the storage layer so schema evolution stays apart
|
|
6
|
+
* from the CRUD/FTS/vector queries.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
8
|
+
* `ensureSchema` runs on every writable open and brings an older layout up
|
|
9
|
+
* to date in place: `CREATE ... IF NOT EXISTS`, `ALTER TABLE ... ADD COLUMN`
|
|
10
|
+
* for columns added after a table first shipped, drops of retired derived
|
|
11
|
+
* tables and columns, and one in-place rebuild of the (derived, cheap) FTS
|
|
12
|
+
* table when its layout is older than this release's. It never drops
|
|
13
|
+
* `entries`, `embeddings`, `utility_scores`, or `llm_enrichment_cache` to
|
|
14
|
+
* cross a version boundary; the only from-scratch rebuild is the
|
|
15
|
+
* SQLITE_CORRUPT path in `index-connection.ts`. A layout newer than this
|
|
16
|
+
* release's is refused, naming the upgrade ({@link newerIndexLayoutError}).
|
|
17
|
+
* The one exception is the LLM entity graph (`graph_meta`, `graph_files`,
|
|
18
|
+
* `graph_file_*`), retired in 0.9.17-alpha.9: those tables are dropped
|
|
19
|
+
* unconditionally below (index.db is a regenerable cache, and declared links
|
|
20
|
+
* — `asset_links` — now back `akm show`'s `links` field, which replaced the
|
|
21
|
+
* graph's `related` list).
|
|
12
22
|
*/
|
|
23
|
+
import { createRequire } from "node:module";
|
|
24
|
+
import path from "node:path";
|
|
13
25
|
import { ConfigError } from "../../core/errors.js";
|
|
14
26
|
import { warn } from "../../core/warn.js";
|
|
15
|
-
import {
|
|
16
|
-
import { CANONICAL_ENTRY_SCHEMA_SQL, CANONICAL_INDEX_DB_VERSION,
|
|
27
|
+
import { sha256Hex } from "../../runtime.js";
|
|
28
|
+
import { CANONICAL_ENTRY_SCHEMA_SQL, CANONICAL_INDEX_DB_VERSION, entriesFtsDdl, isContentlessFtsDdl, missingEntryColumns, readTableSql, supportsContentlessDelete, tableExists, } from "./index-entry-schema.js";
|
|
29
|
+
import { rebuildFts } from "./index-fts-repository.js";
|
|
30
|
+
import { rebuildAllEntryLinks } from "./index-links-repository.js";
|
|
17
31
|
import { getMeta, setMeta } from "./index-meta-repository.js";
|
|
18
|
-
import { isVecAvailable, purgeEmbeddings } from "./index-vec-repository.js";
|
|
19
32
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
20
|
-
// index.db is a regenerable cache. Incompatible entry-schema changes advance
|
|
21
|
-
// this generation and discard only derived index tables; durable state remains
|
|
22
|
-
// in state.db. Current readers and writers therefore target exactly one schema
|
|
23
|
-
// and never carry live compatibility SQL for previous generations.
|
|
24
|
-
//
|
|
25
|
-
// v20→v21: remove the transitional entry_key/dir_path/stash_dir/entry_json/
|
|
26
|
-
// entry_type columns. item_ref is the sole conflict key; document_json is the
|
|
27
|
-
// sole stored document projection; bundle provenance and file_path provide the
|
|
28
|
-
// current identity and materialized read path.
|
|
29
|
-
//
|
|
30
|
-
// v21→v22: entry mutations publish FTS synchronously and no dirty queue exists.
|
|
31
|
-
// Discard the old derived generation so stale FTS rows and caller-managed dirty
|
|
32
|
-
// state cannot cross the mutation-authority boundary.
|
|
33
33
|
export const DB_VERSION = CANONICAL_INDEX_DB_VERSION;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
/** `index_meta` key set when the writable opener migrated the layout; cleared once `akm index` VACUUMs. */
|
|
35
|
+
export const VACUUM_PENDING_META = "vacuumPending";
|
|
36
|
+
/** The layout that added declared links (`asset_links`, #935). */
|
|
37
|
+
const DECLARED_LINKS_LAYOUT = 26;
|
|
38
|
+
/**
|
|
39
|
+
* The refusal for an index a newer akm wrote. Readers and the writable opener
|
|
40
|
+
* both raise it: a newer layout may lack tables or columns this release reads
|
|
41
|
+
* (layout 25 dropped `entries.search_text`), and writing it back at this
|
|
42
|
+
* layout would undo the newer release's migration.
|
|
43
|
+
*/
|
|
44
|
+
export function newerIndexLayoutError(storedVersion, dbPath) {
|
|
45
|
+
return new ConfigError(`Index database${dbPath ? ` at ${dbPath}` : ""} was written by a newer akm (layout ${storedVersion}; this akm ` +
|
|
46
|
+
`understands ${DB_VERSION}). Upgrade akm to use this index.`, "INDEX_SCHEMA_INCOMPATIBLE", "Upgrade akm to a version that understands this index layout.");
|
|
47
|
+
}
|
|
37
48
|
// ── Schema ──────────────────────────────────────────────────────────────────
|
|
38
49
|
/**
|
|
39
50
|
* DDL for the `registry_index_cache` table. This table lives in index.db
|
|
40
51
|
* (managed by this module), so its DDL belongs here next to the `ensureSchema`
|
|
41
52
|
* that applies it — not in state-db.ts.
|
|
42
53
|
*
|
|
43
|
-
*
|
|
44
|
-
* `
|
|
45
|
-
* stash indexes so `akm search` does not hit the network on every invocation.
|
|
46
|
-
*
|
|
47
|
-
* Indexed (query) columns:
|
|
48
|
-
* registry_url TEXT PK — canonical URL of the registry; cache key.
|
|
49
|
-
* fetched_at TEXT — ISO-8601; used to detect stale entries (TTL).
|
|
50
|
-
* etag TEXT — HTTP ETag for conditional GET (If-None-Match).
|
|
51
|
-
* last_modified TEXT — HTTP Last-Modified for conditional GET.
|
|
52
|
-
*
|
|
53
|
-
* Non-indexed payload:
|
|
54
|
-
* index_json TEXT — JSON blob of the fetched registry index document.
|
|
55
|
-
*
|
|
56
|
-
* ADD COLUMN extension points (future migrations):
|
|
57
|
-
* ALTER TABLE registry_index_cache ADD COLUMN schema_version INTEGER DEFAULT 1;
|
|
58
|
-
* ALTER TABLE registry_index_cache ADD COLUMN kit_count INTEGER DEFAULT NULL;
|
|
59
|
-
* ALTER TABLE registry_index_cache ADD COLUMN error_message TEXT DEFAULT NULL;
|
|
54
|
+
* Caches the result of resolving and fetching remote registry stash indexes so
|
|
55
|
+
* `akm search` does not hit the network on every invocation.
|
|
60
56
|
*/
|
|
61
57
|
const REGISTRY_INDEX_CACHE_DDL = `
|
|
62
58
|
CREATE TABLE IF NOT EXISTS registry_index_cache (
|
|
@@ -71,193 +67,207 @@ const REGISTRY_INDEX_CACHE_DDL = `
|
|
|
71
67
|
ON registry_index_cache(fetched_at);
|
|
72
68
|
`;
|
|
73
69
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
70
|
+
* An `entries` table missing a required column cannot be read or written by
|
|
71
|
+
* this release (the last such change was v20→v21, which removed the
|
|
72
|
+
* transitional `entry_key`/`dir_path`/... columns and made `item_ref` the
|
|
73
|
+
* key). Recreate only the tables keyed by `entries.id` — their ids are about
|
|
74
|
+
* to be re-minted, so the rows would dangle anyway. The LLM enrichment cache
|
|
75
|
+
* (keyed by ref) is kept. The LLM entity-graph tables are unconditionally
|
|
76
|
+
* dropped elsewhere in this file regardless of this recreation (retired
|
|
77
|
+
* 0.9.17-alpha.9), not kept. The next index run re-walks every source.
|
|
76
78
|
*/
|
|
77
|
-
function
|
|
78
|
-
db
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
stash_root TEXT NOT NULL,
|
|
102
|
-
file_path TEXT NOT NULL,
|
|
103
|
-
file_order INTEGER NOT NULL,
|
|
104
|
-
file_type TEXT NOT NULL,
|
|
105
|
-
body_hash TEXT NOT NULL,
|
|
106
|
-
confidence REAL,
|
|
107
|
-
status TEXT NOT NULL DEFAULT 'extracted',
|
|
108
|
-
reason TEXT,
|
|
109
|
-
extraction_run_id TEXT,
|
|
110
|
-
PRIMARY KEY (stash_root, file_path, body_hash)
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
CREATE UNIQUE INDEX IF NOT EXISTS idx_graph_files_path
|
|
114
|
-
ON graph_files(stash_root, file_path);
|
|
115
|
-
|
|
116
|
-
CREATE INDEX IF NOT EXISTS idx_graph_files_stash_order
|
|
117
|
-
ON graph_files(stash_root, file_order);
|
|
118
|
-
|
|
119
|
-
CREATE TABLE IF NOT EXISTS graph_file_entities (
|
|
120
|
-
stash_root TEXT NOT NULL,
|
|
121
|
-
file_path TEXT NOT NULL,
|
|
122
|
-
body_hash TEXT NOT NULL,
|
|
123
|
-
entity_order INTEGER NOT NULL,
|
|
124
|
-
entity_norm TEXT NOT NULL,
|
|
125
|
-
entity TEXT NOT NULL,
|
|
126
|
-
PRIMARY KEY (stash_root, file_path, body_hash, entity_order),
|
|
127
|
-
FOREIGN KEY (stash_root, file_path, body_hash)
|
|
128
|
-
REFERENCES graph_files(stash_root, file_path, body_hash) ON DELETE CASCADE
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
CREATE INDEX IF NOT EXISTS idx_graph_file_entities_entity_norm
|
|
132
|
-
ON graph_file_entities(stash_root, entity_norm);
|
|
133
|
-
|
|
134
|
-
CREATE TABLE IF NOT EXISTS graph_file_relations (
|
|
135
|
-
stash_root TEXT NOT NULL,
|
|
136
|
-
file_path TEXT NOT NULL,
|
|
137
|
-
body_hash TEXT NOT NULL,
|
|
138
|
-
relation_order INTEGER NOT NULL,
|
|
139
|
-
from_entity_norm TEXT NOT NULL,
|
|
140
|
-
from_entity TEXT NOT NULL,
|
|
141
|
-
to_entity_norm TEXT NOT NULL,
|
|
142
|
-
to_entity TEXT NOT NULL,
|
|
143
|
-
relation_type TEXT,
|
|
144
|
-
confidence REAL,
|
|
145
|
-
PRIMARY KEY (stash_root, file_path, body_hash, relation_order),
|
|
146
|
-
FOREIGN KEY (stash_root, file_path, body_hash)
|
|
147
|
-
REFERENCES graph_files(stash_root, file_path, body_hash) ON DELETE CASCADE
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
-- #624-P3: lazy graph-extraction queue. Standalone table (NO FK to
|
|
151
|
-
-- graph_files — a queued file by definition has no graph row yet).
|
|
152
|
-
-- Idempotent on (stash_root, file_path); drained highest-priority-first.
|
|
153
|
-
-- CREATE TABLE IF NOT EXISTS is the forward migration (no DB_VERSION bump).
|
|
154
|
-
CREATE TABLE IF NOT EXISTS graph_extraction_queue (
|
|
155
|
-
stash_root TEXT NOT NULL,
|
|
156
|
-
file_path TEXT NOT NULL,
|
|
157
|
-
body_hash TEXT NOT NULL,
|
|
158
|
-
queued_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
159
|
-
priority INTEGER NOT NULL DEFAULT 0,
|
|
160
|
-
PRIMARY KEY (stash_root, file_path)
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
CREATE INDEX IF NOT EXISTS idx_graph_extraction_queue_drain
|
|
164
|
-
ON graph_extraction_queue(stash_root, priority DESC, queued_at);
|
|
165
|
-
`);
|
|
79
|
+
function ensureEntriesLayout(db) {
|
|
80
|
+
if (!tableExists(db, "entries"))
|
|
81
|
+
return;
|
|
82
|
+
const missing = missingEntryColumns(db);
|
|
83
|
+
if (missing.length === 0)
|
|
84
|
+
return;
|
|
85
|
+
warn(`Index database entries table predates the ${missing.join(", ")} column${missing.length === 1 ? "" : "s"} — ` +
|
|
86
|
+
"recreating the entries-keyed tables (entries, full-text, embeddings, utility scores); the " +
|
|
87
|
+
"LLM enrichment cache is kept. The next index run re-walks every source.");
|
|
88
|
+
db.transaction(() => {
|
|
89
|
+
for (const table of [
|
|
90
|
+
"entries_fts",
|
|
91
|
+
"entry_fragments",
|
|
92
|
+
"asset_links",
|
|
93
|
+
"embeddings",
|
|
94
|
+
"utility_scores_scoped",
|
|
95
|
+
"utility_scores",
|
|
96
|
+
"index_dir_state",
|
|
97
|
+
"entries",
|
|
98
|
+
]) {
|
|
99
|
+
db.exec(`DROP TABLE IF EXISTS ${table}`);
|
|
100
|
+
}
|
|
101
|
+
db.exec("DELETE FROM index_meta WHERE key IN ('builtAt', 'hasEmbeddings')");
|
|
102
|
+
})();
|
|
166
103
|
}
|
|
167
104
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
105
|
+
* Drop the sqlite-vec mirror of `embeddings` (`entries_vec`, layout 24 and
|
|
106
|
+
* earlier); vectors are searched from `embeddings` alone. Dropping a vec0
|
|
107
|
+
* table needs its module, so an install without sqlite-vec leaves the table
|
|
108
|
+
* in place, unread, and the next writable open that can load it drops it.
|
|
172
109
|
*/
|
|
173
|
-
function
|
|
174
|
-
|
|
175
|
-
const hasEntries = tableExists(db, "entries");
|
|
176
|
-
if (!hasEntries && version === undefined)
|
|
177
|
-
return;
|
|
178
|
-
if (isCanonicalIndexGeneration(db))
|
|
110
|
+
function dropVecMirror(db) {
|
|
111
|
+
if (!tableExists(db, "entries_vec"))
|
|
179
112
|
return;
|
|
180
|
-
const classification = classifyIndexGeneration(db);
|
|
181
|
-
if (classification.status === "newer") {
|
|
182
|
-
throw new ConfigError(`Index database was built by a newer akm (stored generation ${classification.storedVersion ?? "unknown"}; ` +
|
|
183
|
-
`this binary understands generation ${CANONICAL_INDEX_DB_VERSION}). Refusing to modify it — upgrade akm ` +
|
|
184
|
-
"to use this index.", "INDEX_SCHEMA_INCOMPATIBLE", "Upgrade akm to a version that understands this index generation.");
|
|
185
|
-
}
|
|
186
|
-
warn(`Index database generation ${classification.storedVersion ?? "unknown"} is older than this akm's generation ` +
|
|
187
|
-
`${CANONICAL_INDEX_DB_VERSION} — rebuilding the derived index (entries, FTS, embeddings, graph tables, ` +
|
|
188
|
-
"utility scores, and the LLM enrichment cache). This re-walks and re-indexes every source on the next run.");
|
|
189
|
-
let vecResetPending = false;
|
|
190
113
|
try {
|
|
191
|
-
|
|
114
|
+
createRequire(import.meta.url)("sqlite-vec").load(db);
|
|
115
|
+
db.exec("DROP TABLE entries_vec");
|
|
192
116
|
}
|
|
193
117
|
catch {
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
118
|
+
// sqlite-vec is not loadable here.
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Layout 25 keeps a hash of each entry's embedding input (`embed_hash`)
|
|
123
|
+
* instead of the text (`search_text`, layout 24 and earlier); the text is
|
|
124
|
+
* derived from `document_json` when the entry is embedded. The hash is taken
|
|
125
|
+
* from the stored text, so every vector stays valid until its entry's text
|
|
126
|
+
* changes. One transaction: a crash leaves `search_text` for the next
|
|
127
|
+
* writable open.
|
|
128
|
+
*/
|
|
129
|
+
function replaceSearchTextWithHash(db) {
|
|
130
|
+
if (!tableHasColumn(db, "entries", "search_text"))
|
|
131
|
+
return;
|
|
132
|
+
db.transaction(() => {
|
|
133
|
+
ensureColumn(db, "entries", "embed_hash", "TEXT");
|
|
134
|
+
const page = db.prepare("SELECT id, search_text FROM entries WHERE id > ? ORDER BY id LIMIT 500");
|
|
135
|
+
const update = db.prepare("UPDATE entries SET embed_hash = ? WHERE id = ?");
|
|
136
|
+
let afterId = -1;
|
|
137
|
+
for (;;) {
|
|
138
|
+
const rows = page.all(afterId);
|
|
139
|
+
if (rows.length === 0)
|
|
140
|
+
break;
|
|
141
|
+
afterId = rows[rows.length - 1].id;
|
|
142
|
+
for (const row of rows)
|
|
143
|
+
update.run(sha256Hex(row.search_text), row.id);
|
|
144
|
+
}
|
|
145
|
+
db.exec("ALTER TABLE entries DROP COLUMN search_text");
|
|
146
|
+
})();
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Bring `entries_fts` to the contentless layout, rebuilding it from `entries`
|
|
150
|
+
* when it is missing or still carries the content-bearing layout older
|
|
151
|
+
* releases wrote (the one-time v23→v24 migration). One transaction: a crash
|
|
152
|
+
* mid-rebuild leaves the old table in place and the next writable open
|
|
153
|
+
* retries. A SQLite without `contentless_delete` keeps (or gets) the
|
|
154
|
+
* content-bearing layout instead.
|
|
155
|
+
*/
|
|
156
|
+
function ensureFtsLayout(db) {
|
|
157
|
+
const contentless = supportsContentlessDelete(db);
|
|
158
|
+
const sql = readTableSql(db, "entries_fts");
|
|
159
|
+
if (sql !== null && isContentlessFtsDdl(sql) === contentless)
|
|
160
|
+
return;
|
|
161
|
+
const entryCount = Number(db.prepare("SELECT COUNT(*) AS n FROM entries").get().n);
|
|
162
|
+
if (entryCount > 0) {
|
|
163
|
+
warn(`Rebuilding the full-text index for ${entryCount} entr${entryCount === 1 ? "y" : "ies"} ` +
|
|
164
|
+
"(embeddings, utility scores, and the LLM enrichment cache are kept).");
|
|
198
165
|
}
|
|
199
166
|
db.transaction(() => {
|
|
200
|
-
// #955: copy embeddings about to be discarded wholesale into
|
|
201
|
-
// `embedding_salvage` (keyed by content hash + the fingerprint they were
|
|
202
|
-
// generated under) BEFORE dropping `embeddings`, in the same transaction
|
|
203
|
-
// as the drop, so the copy and the discard commit or roll back together.
|
|
204
|
-
// The next embedding pass hands salvaged vectors back to unchanged
|
|
205
|
-
// content instead of re-embedding the whole corpus after this bump.
|
|
206
|
-
salvageEmbeddingsBeforeDiscard(db);
|
|
207
|
-
db.exec("DROP TABLE IF EXISTS graph_file_relations");
|
|
208
|
-
db.exec("DROP TABLE IF EXISTS graph_file_entities");
|
|
209
|
-
db.exec("DROP TABLE IF EXISTS graph_files");
|
|
210
|
-
db.exec("DROP TABLE IF EXISTS graph_extraction_queue");
|
|
211
|
-
db.exec("DROP TABLE IF EXISTS graph_meta");
|
|
212
|
-
db.exec("DROP TABLE IF EXISTS entries_fts_dirty");
|
|
213
|
-
db.exec("DROP TABLE IF EXISTS entry_fragments_fts");
|
|
214
|
-
db.exec("DROP TABLE IF EXISTS entry_fragments");
|
|
215
167
|
db.exec("DROP TABLE IF EXISTS entries_fts");
|
|
216
|
-
db.exec(
|
|
217
|
-
db
|
|
218
|
-
db.exec("DROP TABLE IF EXISTS utility_scores");
|
|
219
|
-
db.exec("DROP TABLE IF EXISTS llm_enrichment_cache");
|
|
220
|
-
db.exec("DROP TABLE IF EXISTS index_dir_state");
|
|
221
|
-
db.exec("DROP TABLE IF EXISTS entries");
|
|
222
|
-
db.exec("DELETE FROM index_meta");
|
|
223
|
-
// embedding_salvage is deliberately absent from the drop list above —
|
|
224
|
-
// it is the ONE piece of derived state a generation rebuild must not
|
|
225
|
-
// discard.
|
|
168
|
+
db.exec(entriesFtsDdl(contentless));
|
|
169
|
+
rebuildFts(db);
|
|
226
170
|
})();
|
|
227
|
-
if (vecResetPending)
|
|
228
|
-
setMeta(db, "vecResetPending", "1");
|
|
229
171
|
}
|
|
230
|
-
|
|
231
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Layout 26 stores declared links (#935). Every relation an older layout
|
|
174
|
+
* indexed already sits in `document_json`, so the links are derived from there
|
|
175
|
+
* in place, with no file read. The exception is a workflow's step targets and
|
|
176
|
+
* a task's target, which no earlier layout stored: the directories holding
|
|
177
|
+
* workflows and tasks lose their incremental cursor, so the next `akm index`
|
|
178
|
+
* re-reads those and nothing else. One transaction.
|
|
179
|
+
*/
|
|
180
|
+
function migrateToDeclaredLinks(db) {
|
|
181
|
+
db.transaction(() => {
|
|
182
|
+
rebuildAllEntryLinks(db);
|
|
183
|
+
const rows = db
|
|
184
|
+
.prepare("SELECT DISTINCT file_path FROM entries WHERE type IN ('workflow', 'task')")
|
|
185
|
+
.all();
|
|
186
|
+
const forget = db.prepare("DELETE FROM index_dir_state WHERE dir_path = ?");
|
|
187
|
+
for (const dir of new Set(rows.map((row) => path.dirname(row.file_path))))
|
|
188
|
+
forget.run(dir);
|
|
189
|
+
})();
|
|
190
|
+
}
|
|
191
|
+
function tableHasColumn(db, table, column) {
|
|
192
|
+
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
193
|
+
return columns.some((existing) => existing.name === column);
|
|
194
|
+
}
|
|
195
|
+
/** `ALTER TABLE ... ADD COLUMN` for a column added after the table first shipped. Idempotent. */
|
|
196
|
+
function ensureColumn(db, table, column, type) {
|
|
197
|
+
if (tableHasColumn(db, table, column))
|
|
198
|
+
return false;
|
|
199
|
+
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${type}`);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
export function ensureSchema(db) {
|
|
232
203
|
db.exec(`
|
|
233
204
|
CREATE TABLE IF NOT EXISTS index_meta (
|
|
234
205
|
key TEXT PRIMARY KEY,
|
|
235
206
|
value TEXT NOT NULL
|
|
236
207
|
);
|
|
237
208
|
`);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
rebuildIncompatibleIndexGeneration(db);
|
|
209
|
+
const storedVersion = Number(getMeta(db, "version") ?? 0);
|
|
210
|
+
if (storedVersion > DB_VERSION)
|
|
211
|
+
throw newerIndexLayoutError(storedVersion);
|
|
212
|
+
ensureEntriesLayout(db);
|
|
213
|
+
const hadFragmentSource = tableExists(db, "entry_fragments");
|
|
244
214
|
db.exec(CANONICAL_ENTRY_SCHEMA_SQL);
|
|
245
|
-
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
215
|
+
replaceSearchTextWithHash(db);
|
|
216
|
+
// Retired derived tables: the workflow IR cache, the pre-v22 FTS dirty
|
|
217
|
+
// queue, the #955 embedding salvage staging table (embeddings now carry
|
|
218
|
+
// their model per row, so nothing is copied aside and reused), the
|
|
219
|
+
// fragment FTS table search stopped reading (layout 24 and earlier), the
|
|
220
|
+
// per-project scoped utility table (IR-7a: it shipped, but no code ever read
|
|
221
|
+
// or wrote a row), and the lazy graph-extraction queue (extraction runs only
|
|
222
|
+
// in improve).
|
|
249
223
|
db.exec("DROP TABLE IF EXISTS workflow_documents");
|
|
250
|
-
|
|
224
|
+
db.exec("DROP TABLE IF EXISTS entries_fts_dirty");
|
|
225
|
+
db.exec("DROP TABLE IF EXISTS embedding_salvage");
|
|
226
|
+
db.exec("DROP TABLE IF EXISTS entry_fragments_fts");
|
|
227
|
+
db.exec("DROP TABLE IF EXISTS utility_scores_scoped");
|
|
228
|
+
db.exec("DROP TABLE IF EXISTS graph_extraction_queue");
|
|
229
|
+
// The LLM entity graph, retired in 0.9.17-alpha.9: declared links
|
|
230
|
+
// (`asset_links`) now back `akm show`'s `links` field (which replaced the
|
|
231
|
+
// graph's `related` list) and curate's support refs (#935), and the
|
|
232
|
+
// navigation eval measured vector kNN beating the graph's `related` list
|
|
233
|
+
// by 0.157 P@5. `graph_files` stands in for the whole set — all four
|
|
234
|
+
// tables are only ever created and dropped together. Gated on it (rather
|
|
235
|
+
// than the unconditional `DROP TABLE IF EXISTS` pattern used above) so
|
|
236
|
+
// this reclaim runs once: after the first writable open drops these
|
|
237
|
+
// tables, every later open finds `graph_files` already gone and skips the
|
|
238
|
+
// no-op DROPs and the repeat VACUUM flag below. An older release's
|
|
239
|
+
// `CREATE TABLE IF NOT EXISTS` still recreates them (empty) if it ever
|
|
240
|
+
// opens this index again — a later open here would then drop them again.
|
|
241
|
+
const hadGraphTables = tableExists(db, "graph_files");
|
|
242
|
+
if (hadGraphTables) {
|
|
243
|
+
db.exec("DROP TABLE IF EXISTS graph_meta");
|
|
244
|
+
db.exec("DROP TABLE IF EXISTS graph_files");
|
|
245
|
+
db.exec("DROP TABLE IF EXISTS graph_file_entities");
|
|
246
|
+
db.exec("DROP TABLE IF EXISTS graph_file_relations");
|
|
247
|
+
}
|
|
248
|
+
// One float32 BLOB per entry, searched by an exact scan
|
|
249
|
+
// (index-vec-repository.ts). `model` is the provider fingerprint the vector was generated under
|
|
250
|
+
// (`deriveSemanticProviderFingerprint`); the embedding pass re-embeds only
|
|
251
|
+
// rows whose model differs from the configured one. NULL means the row
|
|
252
|
+
// predates model tracking and is trusted as the current model.
|
|
251
253
|
db.exec(`
|
|
252
254
|
CREATE TABLE IF NOT EXISTS embeddings (
|
|
253
255
|
id INTEGER PRIMARY KEY,
|
|
254
256
|
embedding BLOB NOT NULL,
|
|
257
|
+
model TEXT,
|
|
255
258
|
FOREIGN KEY (id) REFERENCES entries(id)
|
|
256
259
|
);
|
|
257
260
|
`);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
+
if (ensureColumn(db, "embeddings", "model", "TEXT")) {
|
|
262
|
+
// Rows written before model tracking were generated under the fingerprint
|
|
263
|
+
// the last pass recorded; label them so a later model change re-embeds
|
|
264
|
+
// them instead of trusting them forever.
|
|
265
|
+
const fingerprint = getMeta(db, "embeddingFingerprint");
|
|
266
|
+
if (fingerprint)
|
|
267
|
+
db.prepare("UPDATE embeddings SET model = ? WHERE model IS NULL").run(fingerprint);
|
|
268
|
+
}
|
|
269
|
+
// Utility scores (aggregated per-entry utility metrics) — a regenerable
|
|
270
|
+
// cache recomputed from state.db's usage_events on every index run.
|
|
261
271
|
db.exec(`
|
|
262
272
|
CREATE TABLE IF NOT EXISTS utility_scores (
|
|
263
273
|
entry_id INTEGER PRIMARY KEY,
|
|
@@ -269,20 +279,6 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
269
279
|
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
270
280
|
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
271
281
|
);
|
|
272
|
-
`);
|
|
273
|
-
// Per-project scoped utility scores — tracks usage per (entry, cwd-anchor)
|
|
274
|
-
// so assets useful in project A don't pollute rankings in project B.
|
|
275
|
-
// The global utility_scores table is preserved as a fallback / cold-start aid.
|
|
276
|
-
db.exec(`
|
|
277
|
-
CREATE TABLE IF NOT EXISTS utility_scores_scoped (
|
|
278
|
-
entry_id INTEGER NOT NULL,
|
|
279
|
-
scope_key TEXT NOT NULL,
|
|
280
|
-
utility REAL NOT NULL DEFAULT 0,
|
|
281
|
-
last_used_at INTEGER NOT NULL,
|
|
282
|
-
PRIMARY KEY (entry_id, scope_key)
|
|
283
|
-
);
|
|
284
|
-
CREATE INDEX IF NOT EXISTS idx_utility_scores_scoped_entry_id
|
|
285
|
-
ON utility_scores_scoped(entry_id);
|
|
286
282
|
`);
|
|
287
283
|
db.exec(`
|
|
288
284
|
CREATE TABLE IF NOT EXISTS index_dir_state (
|
|
@@ -291,16 +287,18 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
291
287
|
file_mtime_max_ms REAL NOT NULL,
|
|
292
288
|
reason TEXT NOT NULL,
|
|
293
289
|
updated_at TEXT NOT NULL,
|
|
294
|
-
row_count INTEGER
|
|
290
|
+
row_count INTEGER,
|
|
291
|
+
index_variant TEXT
|
|
295
292
|
);
|
|
296
293
|
`);
|
|
297
|
-
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
//
|
|
303
|
-
//
|
|
294
|
+
// #900 (`row_count`) and the adapter variant were added after the table's
|
|
295
|
+
// first release. Pre-existing rows keep NULL until their directory is next
|
|
296
|
+
// drained.
|
|
297
|
+
ensureColumn(db, "index_dir_state", "row_count", "INTEGER");
|
|
298
|
+
ensureColumn(db, "index_dir_state", "index_variant", "TEXT");
|
|
299
|
+
// LLM enrichment result cache, keyed by a stable asset_ref string (the
|
|
300
|
+
// absolute file path of the memory-inference pass) plus the body hash the
|
|
301
|
+
// result was produced for.
|
|
304
302
|
db.exec(`
|
|
305
303
|
CREATE TABLE IF NOT EXISTS llm_enrichment_cache (
|
|
306
304
|
asset_ref TEXT NOT NULL,
|
|
@@ -314,110 +312,44 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
314
312
|
CREATE INDEX IF NOT EXISTS idx_llm_cache_updated
|
|
315
313
|
ON llm_enrichment_cache(updated_at);
|
|
316
314
|
`);
|
|
317
|
-
//
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (isVecAvailable(db) && getMeta(db, "vecResetPending") === "1") {
|
|
335
|
-
db.exec("DROP TABLE IF EXISTS entries_vec");
|
|
336
|
-
setMeta(db, "vecResetPending", "0");
|
|
337
|
-
}
|
|
338
|
-
// sqlite-vec table
|
|
339
|
-
//
|
|
340
|
-
// Dimension contract:
|
|
341
|
-
// - When `embeddingDim` is `undefined`, the caller did NOT request a
|
|
342
|
-
// specific dim. Do not touch `index_meta.embeddingDim` and do not run
|
|
343
|
-
// the dim-change wipe — fall back to the stored dim (or the static
|
|
344
|
-
// default) only when we have to materialise the vec table for the
|
|
345
|
-
// first time. Without this guard, registry-side and other dim-unaware
|
|
346
|
-
// `openDatabase()` callers would silently overwrite the dim-aware
|
|
347
|
-
// improve/index value and oscillate the stored dim.
|
|
348
|
-
// - When `embeddingDim` is a number, the caller explicitly asked for
|
|
349
|
-
// that dim and owns the dim-change/backup/wipe semantics.
|
|
350
|
-
const dimExplicit = embeddingDim !== undefined;
|
|
351
|
-
const requestedDim = embeddingDim ?? (Number(getMeta(db, "embeddingDim")) || EMBEDDING_DIM);
|
|
352
|
-
const effectiveDim = Number.isInteger(requestedDim) && requestedDim > 0 ? requestedDim : EMBEDDING_DIM;
|
|
353
|
-
if (effectiveDim !== requestedDim) {
|
|
354
|
-
warn(`Invalid embedding dimension ${requestedDim} — falling back to the default (${EMBEDDING_DIM}).`);
|
|
315
|
+
// Metadata-enhance retired (RS-D, 0.9.17-alpha.9): its rows were the only
|
|
316
|
+
// ones keyed by the default empty cache_variant (memory inference writes
|
|
317
|
+
// `memory-inference-v2`), so this is safe to run unconditionally on every
|
|
318
|
+
// writable open. The table
|
|
319
|
+
// itself stays — memory inference still reads it.
|
|
320
|
+
db.exec("DELETE FROM llm_enrichment_cache WHERE cache_variant = ''");
|
|
321
|
+
// The graph-extraction cache variant is retired along with the tables
|
|
322
|
+
// above; its rows would otherwise sit unread forever. Gated the same way,
|
|
323
|
+
// on the same one-time flag, so a rerun does not re-scan the cache table
|
|
324
|
+
// for rows that are already gone.
|
|
325
|
+
if (hadGraphTables) {
|
|
326
|
+
db.exec("DELETE FROM llm_enrichment_cache WHERE cache_variant LIKE 'graph-extraction:%'");
|
|
327
|
+
// The drops and delete above freed real space (measured ~68MB on a
|
|
328
|
+
// representative index): flag it the same way a version-gated layout
|
|
329
|
+
// migration does, since this reclaim is unconditional-on-version but
|
|
330
|
+
// still one-time-per-index (guarded by hadGraphTables above).
|
|
331
|
+
setMeta(db, VACUUM_PENDING_META, "1");
|
|
355
332
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (!vecExists) {
|
|
369
|
-
db.exec(`
|
|
370
|
-
CREATE VIRTUAL TABLE entries_vec USING vec0(
|
|
371
|
-
id INTEGER PRIMARY KEY,
|
|
372
|
-
embedding FLOAT[${effectiveDim}]
|
|
373
|
-
);
|
|
374
|
-
`);
|
|
375
|
-
}
|
|
376
|
-
if (dimExplicit) {
|
|
377
|
-
setMeta(db, "embeddingDim", String(effectiveDim));
|
|
378
|
-
}
|
|
333
|
+
dropVecMirror(db);
|
|
334
|
+
// Meta keys only the sqlite-vec mirror read.
|
|
335
|
+
db.exec("DELETE FROM index_meta WHERE key IN ('embeddingDim', 'vecFastPathReady')");
|
|
336
|
+
db.exec(REGISTRY_INDEX_CACHE_DDL);
|
|
337
|
+
ensureFtsLayout(db);
|
|
338
|
+
// An index that had no fragment source table (v22 and earlier) has no safe
|
|
339
|
+
// Markdown for `akm show` to resolve fragment selectors from until each
|
|
340
|
+
// directory is drained again. Clearing the per-directory cursor makes the
|
|
341
|
+
// next run re-read every source; entry ids, embeddings and utility rows
|
|
342
|
+
// stay put.
|
|
343
|
+
if (!hadFragmentSource && tableExists(db, "entries")) {
|
|
344
|
+
db.exec("DELETE FROM index_dir_state");
|
|
379
345
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
// When sqlite-vec is unavailable, entries_vec doesn't exist but the BLOB
|
|
383
|
-
// embeddings table still stores vectors. If the configured dimension
|
|
384
|
-
// changes, those stored BLOBs become silently incompatible.
|
|
385
|
-
if (dimExplicit) {
|
|
386
|
-
const storedDim = getMeta(db, "embeddingDim");
|
|
387
|
-
if (storedDim && storedDim !== String(effectiveDim)) {
|
|
388
|
-
// JS-fallback path: no vec table, just clear the stale BLOB vectors.
|
|
389
|
-
purgeEmbeddings(db);
|
|
390
|
-
}
|
|
391
|
-
setMeta(db, "embeddingDim", String(effectiveDim));
|
|
392
|
-
}
|
|
346
|
+
if (storedVersion > 0 && storedVersion < DECLARED_LINKS_LAYOUT && tableExists(db, "entries")) {
|
|
347
|
+
migrateToDeclaredLinks(db);
|
|
393
348
|
}
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
// Write the generation stamp only after every required DDL surface exists.
|
|
400
|
-
// A crash before this point leaves an unversioned generation that the next
|
|
401
|
-
// writable open safely rebuilds instead of admitting a partial v23 index.
|
|
349
|
+
// Migrating an existing layout drops tables and columns; the next `akm index`
|
|
350
|
+
// VACUUMs the pages they leave free (`vacuumIndexDb`, indexer.ts), since a
|
|
351
|
+
// writable open may run inside a caller's transaction, where VACUUM cannot.
|
|
352
|
+
if (storedVersion > 0 && storedVersion < DB_VERSION)
|
|
353
|
+
setMeta(db, VACUUM_PENDING_META, "1");
|
|
402
354
|
setMeta(db, "version", String(DB_VERSION));
|
|
403
355
|
}
|
|
404
|
-
/**
|
|
405
|
-
* Returns true when a table exists in the current database.
|
|
406
|
-
*/
|
|
407
|
-
function tableExists(db, name) {
|
|
408
|
-
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name=? LIMIT 1").get(name);
|
|
409
|
-
return row !== undefined && row !== null;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* #900: `row_count` was added after the table's first release, so a database
|
|
413
|
-
* created before it needs an `ALTER TABLE` (`CREATE TABLE IF NOT EXISTS` only
|
|
414
|
-
* shapes a fresh table). Idempotent. Pre-existing rows keep NULL until their
|
|
415
|
-
* directory is next drained; index.db is a regenerable cache, so nothing is
|
|
416
|
-
* backfilled.
|
|
417
|
-
*/
|
|
418
|
-
function ensureIndexDirStateRowCountColumn(db) {
|
|
419
|
-
const columns = db.prepare("PRAGMA table_info(index_dir_state)").all();
|
|
420
|
-
if (!columns.some((column) => column.name === "row_count")) {
|
|
421
|
-
db.exec("ALTER TABLE index_dir_state ADD COLUMN row_count INTEGER");
|
|
422
|
-
}
|
|
423
|
-
}
|