akm-cli 0.9.17-alpha.3 → 0.9.17-alpha.4
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 +731 -0
- package/dist/akm +94 -196
- package/dist/cli/shared.js +6 -2
- package/dist/cli.js +22 -9
- 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 +2 -2
- package/dist/commands/health/checks.js +30 -75
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +0 -38
- package/dist/commands/health/improve-metrics.js +123 -562
- 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 +11 -106
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -73
- package/dist/commands/health.js +122 -143
- package/dist/commands/improve/consolidate/chunking.js +25 -100
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +538 -1075
- 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 -1075
- package/dist/commands/improve/eligibility.js +126 -400
- package/dist/commands/improve/execution.js +3 -5
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +29 -166
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +12 -7
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +443 -1063
- package/dist/commands/improve/ledger.js +114 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +459 -1172
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +14 -118
- package/dist/commands/improve/memory/memory-improve.js +4 -3
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -10
- package/dist/commands/improve/preparation.js +851 -2339
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +621 -1367
- package/dist/commands/improve/salience.js +46 -232
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +323 -0
- package/dist/commands/proposal/drain.js +251 -644
- package/dist/commands/proposal/proposal-cli.js +3 -18
- package/dist/commands/proposal/proposal-types.js +20 -41
- package/dist/commands/proposal/proposal.js +1 -2
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +502 -1487
- 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 +13 -89
- package/dist/commands/read/curate.js +63 -413
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +2 -13
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +7 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +2 -11
- 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/stash-cli.js +1 -1
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +9 -8
- package/dist/commands/tasks/tasks.js +326 -930
- package/dist/commands/tasks/validate.js +42 -21
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +0 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +11 -12
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +291 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +1 -33
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +163 -68
- 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 +21 -95
- package/dist/core/config/schema/improve.js +4 -42
- 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-lock.js +76 -173
- package/dist/core/logs-db.js +2 -2
- package/dist/core/paths.js +0 -27
- 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 +108 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +293 -1012
- 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/graph-db.js +106 -46
- package/dist/indexer/ensure-index.js +44 -85
- package/dist/indexer/graph/graph-extraction.js +340 -562
- package/dist/indexer/graph/graph-related.js +130 -0
- 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 +139 -151
- package/dist/indexer/indexer.js +524 -846
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +81 -90
- package/dist/indexer/passes/metadata.js +132 -200
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +1 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +181 -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 +2 -7
- 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/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +10 -15
- package/dist/llm/graph-extract.js +3 -12
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/metadata-enhance.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 +2 -34
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +60 -23
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +1 -2
- 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 +43937 -93313
- package/dist/scripts/akm-migrate.js +43697 -93071
- 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/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 +0 -17
- 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 +168 -0
- package/dist/storage/repositories/index-connection.js +34 -70
- package/dist/storage/repositories/index-entries-repository.js +69 -111
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +83 -269
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +192 -220
- 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 +35 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- 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 +34 -27
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +129 -277
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +125 -745
- package/dist/tasks/backends/schtasks.js +101 -620
- 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/scheduler-binding.js +18 -238
- package/dist/tasks/scheduler-invocation.js +52 -52
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +361 -751
- package/dist/tasks/source/parse-task-source.js +160 -10
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +2 -2
- 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 +41 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
- package/docs/reference/cli.md +182 -125
- package/docs/reference/configuration.md +49 -56
- package/docs/reference/data-and-telemetry.md +19 -20
- package/docs/reference/tasks.md +86 -38
- 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 +87 -406
- 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 -146
- package/dist/commands/improve/distill/promote-memory.js +0 -329
- package/dist/commands/improve/distill/quality-gate.js +0 -500
- 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 -21
- 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/config/retired-experimental-keys-shim.js +0 -62
- 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 -441
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- 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/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/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 -78
- 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,51 @@
|
|
|
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*`, `graph_*`, or
|
|
14
|
+
* `llm_enrichment_cache` to cross a version boundary; the only from-scratch
|
|
15
|
+
* rebuild is the SQLITE_CORRUPT path in `index-connection.ts`. A layout newer
|
|
16
|
+
* than this release's is refused, naming the upgrade
|
|
17
|
+
* ({@link newerIndexLayoutError}).
|
|
12
18
|
*/
|
|
19
|
+
import { createRequire } from "node:module";
|
|
13
20
|
import { ConfigError } from "../../core/errors.js";
|
|
14
21
|
import { warn } from "../../core/warn.js";
|
|
15
|
-
import {
|
|
16
|
-
import { CANONICAL_ENTRY_SCHEMA_SQL, CANONICAL_INDEX_DB_VERSION,
|
|
22
|
+
import { sha256Hex } from "../../runtime.js";
|
|
23
|
+
import { CANONICAL_ENTRY_SCHEMA_SQL, CANONICAL_INDEX_DB_VERSION, entriesFtsDdl, isContentlessFtsDdl, missingEntryColumns, readTableSql, supportsContentlessDelete, tableExists, } from "./index-entry-schema.js";
|
|
24
|
+
import { rebuildFts } from "./index-fts-repository.js";
|
|
17
25
|
import { getMeta, setMeta } from "./index-meta-repository.js";
|
|
18
|
-
import { isVecAvailable, purgeEmbeddings } from "./index-vec-repository.js";
|
|
19
26
|
// ── 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
27
|
export const DB_VERSION = CANONICAL_INDEX_DB_VERSION;
|
|
34
|
-
|
|
28
|
+
/** `index_meta` key set when the writable opener migrated the layout; cleared once `akm index` VACUUMs. */
|
|
29
|
+
export const VACUUM_PENDING_META = "vacuumPending";
|
|
35
30
|
// #624-P1: graph_files is keyed to (stash_root, file_path, body_hash).
|
|
36
31
|
export const GRAPH_SCHEMA_VERSION = 4;
|
|
32
|
+
/**
|
|
33
|
+
* The refusal for an index a newer akm wrote. Readers and the writable opener
|
|
34
|
+
* both raise it: a newer layout may lack tables or columns this release reads
|
|
35
|
+
* (layout 25 dropped `entries.search_text`), and writing it back at this
|
|
36
|
+
* layout would undo the newer release's migration.
|
|
37
|
+
*/
|
|
38
|
+
export function newerIndexLayoutError(storedVersion, dbPath) {
|
|
39
|
+
return new ConfigError(`Index database${dbPath ? ` at ${dbPath}` : ""} was written by a newer akm (layout ${storedVersion}; this akm ` +
|
|
40
|
+
`understands ${DB_VERSION}). Upgrade akm to use this index.`, "INDEX_SCHEMA_INCOMPATIBLE", "Upgrade akm to a version that understands this index layout.");
|
|
41
|
+
}
|
|
37
42
|
// ── Schema ──────────────────────────────────────────────────────────────────
|
|
38
43
|
/**
|
|
39
44
|
* DDL for the `registry_index_cache` table. This table lives in index.db
|
|
40
45
|
* (managed by this module), so its DDL belongs here next to the `ensureSchema`
|
|
41
46
|
* that applies it — not in state-db.ts.
|
|
42
47
|
*
|
|
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;
|
|
48
|
+
* Caches the result of resolving and fetching remote registry stash indexes so
|
|
49
|
+
* `akm search` does not hit the network on every invocation.
|
|
60
50
|
*/
|
|
61
51
|
const REGISTRY_INDEX_CACHE_DDL = `
|
|
62
52
|
CREATE TABLE IF NOT EXISTS registry_index_cache (
|
|
@@ -73,6 +63,11 @@ const REGISTRY_INDEX_CACHE_DDL = `
|
|
|
73
63
|
/**
|
|
74
64
|
* Create the graph-extraction tables (`graph_meta`/`graph_files`/`graph_file_entities`/
|
|
75
65
|
* `graph_file_relations`/`graph_extraction_queue`).
|
|
66
|
+
*
|
|
67
|
+
* graph_files is self-keyed on (stash_root, file_path, body_hash) and is not
|
|
68
|
+
* tied to entries.id (#624-P1): re-upserting an entries row never disturbs the
|
|
69
|
+
* extracted graph, and a content change yields a distinct key. A UNIQUE index
|
|
70
|
+
* on (stash_root, file_path) still enforces one graph_files row per path.
|
|
76
71
|
*/
|
|
77
72
|
function ensureGraphTables(db) {
|
|
78
73
|
db.exec(`
|
|
@@ -150,7 +145,6 @@ function ensureGraphTables(db) {
|
|
|
150
145
|
-- #624-P3: lazy graph-extraction queue. Standalone table (NO FK to
|
|
151
146
|
-- graph_files — a queued file by definition has no graph row yet).
|
|
152
147
|
-- 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
148
|
CREATE TABLE IF NOT EXISTS graph_extraction_queue (
|
|
155
149
|
stash_root TEXT NOT NULL,
|
|
156
150
|
file_path TEXT NOT NULL,
|
|
@@ -165,99 +159,162 @@ function ensureGraphTables(db) {
|
|
|
165
159
|
`);
|
|
166
160
|
}
|
|
167
161
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
162
|
+
* An `entries` table missing a required column cannot be read or written by
|
|
163
|
+
* this release (the last such change was v20→v21, which removed the
|
|
164
|
+
* transitional `entry_key`/`dir_path`/... columns and made `item_ref` the
|
|
165
|
+
* key). Recreate only the tables keyed by `entries.id` — their ids are about
|
|
166
|
+
* to be re-minted, so the rows would dangle anyway. Graph rows (keyed by
|
|
167
|
+
* path) and the LLM enrichment cache (keyed by ref) are kept. The next index
|
|
168
|
+
* run re-walks every source.
|
|
172
169
|
*/
|
|
173
|
-
function
|
|
174
|
-
|
|
175
|
-
const hasEntries = tableExists(db, "entries");
|
|
176
|
-
if (!hasEntries && version === undefined)
|
|
170
|
+
function ensureEntriesLayout(db) {
|
|
171
|
+
if (!tableExists(db, "entries"))
|
|
177
172
|
return;
|
|
178
|
-
|
|
173
|
+
const missing = missingEntryColumns(db);
|
|
174
|
+
if (missing.length === 0)
|
|
175
|
+
return;
|
|
176
|
+
warn(`Index database entries table predates the ${missing.join(", ")} column${missing.length === 1 ? "" : "s"} — ` +
|
|
177
|
+
"recreating the entries-keyed tables (entries, full-text, embeddings, utility scores); graph data and the " +
|
|
178
|
+
"LLM enrichment cache are kept. The next index run re-walks every source.");
|
|
179
|
+
db.transaction(() => {
|
|
180
|
+
for (const table of [
|
|
181
|
+
"entries_fts",
|
|
182
|
+
"entry_fragments",
|
|
183
|
+
"embeddings",
|
|
184
|
+
"utility_scores_scoped",
|
|
185
|
+
"utility_scores",
|
|
186
|
+
"index_dir_state",
|
|
187
|
+
"entries",
|
|
188
|
+
]) {
|
|
189
|
+
db.exec(`DROP TABLE IF EXISTS ${table}`);
|
|
190
|
+
}
|
|
191
|
+
db.exec("DELETE FROM index_meta WHERE key IN ('builtAt', 'hasEmbeddings')");
|
|
192
|
+
})();
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Drop the sqlite-vec mirror of `embeddings` (`entries_vec`, layout 24 and
|
|
196
|
+
* earlier); vectors are searched from `embeddings` alone. Dropping a vec0
|
|
197
|
+
* table needs its module, so an install without sqlite-vec leaves the table
|
|
198
|
+
* in place, unread, and the next writable open that can load it drops it.
|
|
199
|
+
*/
|
|
200
|
+
function dropVecMirror(db) {
|
|
201
|
+
if (!tableExists(db, "entries_vec"))
|
|
179
202
|
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
203
|
try {
|
|
191
|
-
|
|
204
|
+
createRequire(import.meta.url)("sqlite-vec").load(db);
|
|
205
|
+
db.exec("DROP TABLE entries_vec");
|
|
192
206
|
}
|
|
193
207
|
catch {
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
208
|
+
// sqlite-vec is not loadable here.
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Layout 25 keeps a hash of each entry's embedding input (`embed_hash`)
|
|
213
|
+
* instead of the text (`search_text`, layout 24 and earlier); the text is
|
|
214
|
+
* derived from `document_json` when the entry is embedded. The hash is taken
|
|
215
|
+
* from the stored text, so every vector stays valid until its entry's text
|
|
216
|
+
* changes. One transaction: a crash leaves `search_text` for the next
|
|
217
|
+
* writable open.
|
|
218
|
+
*/
|
|
219
|
+
function replaceSearchTextWithHash(db) {
|
|
220
|
+
if (!tableHasColumn(db, "entries", "search_text"))
|
|
221
|
+
return;
|
|
222
|
+
db.transaction(() => {
|
|
223
|
+
ensureColumn(db, "entries", "embed_hash", "TEXT");
|
|
224
|
+
const page = db.prepare("SELECT id, search_text FROM entries WHERE id > ? ORDER BY id LIMIT 500");
|
|
225
|
+
const update = db.prepare("UPDATE entries SET embed_hash = ? WHERE id = ?");
|
|
226
|
+
let afterId = -1;
|
|
227
|
+
for (;;) {
|
|
228
|
+
const rows = page.all(afterId);
|
|
229
|
+
if (rows.length === 0)
|
|
230
|
+
break;
|
|
231
|
+
afterId = rows[rows.length - 1].id;
|
|
232
|
+
for (const row of rows)
|
|
233
|
+
update.run(sha256Hex(row.search_text), row.id);
|
|
234
|
+
}
|
|
235
|
+
db.exec("ALTER TABLE entries DROP COLUMN search_text");
|
|
236
|
+
})();
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Bring `entries_fts` to the contentless layout, rebuilding it from `entries`
|
|
240
|
+
* when it is missing or still carries the content-bearing layout older
|
|
241
|
+
* releases wrote (the one-time v23→v24 migration). One transaction: a crash
|
|
242
|
+
* mid-rebuild leaves the old table in place and the next writable open
|
|
243
|
+
* retries. A SQLite without `contentless_delete` keeps (or gets) the
|
|
244
|
+
* content-bearing layout instead.
|
|
245
|
+
*/
|
|
246
|
+
function ensureFtsLayout(db) {
|
|
247
|
+
const contentless = supportsContentlessDelete(db);
|
|
248
|
+
const sql = readTableSql(db, "entries_fts");
|
|
249
|
+
if (sql !== null && isContentlessFtsDdl(sql) === contentless)
|
|
250
|
+
return;
|
|
251
|
+
const entryCount = Number(db.prepare("SELECT COUNT(*) AS n FROM entries").get().n);
|
|
252
|
+
if (entryCount > 0) {
|
|
253
|
+
warn(`Rebuilding the full-text index for ${entryCount} entr${entryCount === 1 ? "y" : "ies"} ` +
|
|
254
|
+
"(embeddings, utility scores, graph data and the LLM enrichment cache are kept).");
|
|
198
255
|
}
|
|
199
256
|
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
257
|
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.
|
|
258
|
+
db.exec(entriesFtsDdl(contentless));
|
|
259
|
+
rebuildFts(db);
|
|
226
260
|
})();
|
|
227
|
-
if (vecResetPending)
|
|
228
|
-
setMeta(db, "vecResetPending", "1");
|
|
229
261
|
}
|
|
230
|
-
|
|
231
|
-
|
|
262
|
+
function tableHasColumn(db, table, column) {
|
|
263
|
+
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
264
|
+
return columns.some((existing) => existing.name === column);
|
|
265
|
+
}
|
|
266
|
+
/** `ALTER TABLE ... ADD COLUMN` for a column added after the table first shipped. Idempotent. */
|
|
267
|
+
function ensureColumn(db, table, column, type) {
|
|
268
|
+
if (tableHasColumn(db, table, column))
|
|
269
|
+
return false;
|
|
270
|
+
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${type}`);
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
export function ensureSchema(db) {
|
|
232
274
|
db.exec(`
|
|
233
275
|
CREATE TABLE IF NOT EXISTS index_meta (
|
|
234
276
|
key TEXT PRIMARY KEY,
|
|
235
277
|
value TEXT NOT NULL
|
|
236
278
|
);
|
|
237
279
|
`);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
rebuildIncompatibleIndexGeneration(db);
|
|
280
|
+
const storedVersion = Number(getMeta(db, "version") ?? 0);
|
|
281
|
+
if (storedVersion > DB_VERSION)
|
|
282
|
+
throw newerIndexLayoutError(storedVersion);
|
|
283
|
+
ensureEntriesLayout(db);
|
|
284
|
+
const hadFragmentSource = tableExists(db, "entry_fragments");
|
|
244
285
|
db.exec(CANONICAL_ENTRY_SCHEMA_SQL);
|
|
245
|
-
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
286
|
+
replaceSearchTextWithHash(db);
|
|
287
|
+
// Retired derived tables: the workflow IR cache, the pre-v22 FTS dirty
|
|
288
|
+
// queue, the #955 embedding salvage staging table (embeddings now carry
|
|
289
|
+
// their model per row, so nothing is copied aside and reused), and the
|
|
290
|
+
// fragment FTS table search stopped reading (layout 24 and earlier).
|
|
249
291
|
db.exec("DROP TABLE IF EXISTS workflow_documents");
|
|
250
|
-
|
|
292
|
+
db.exec("DROP TABLE IF EXISTS entries_fts_dirty");
|
|
293
|
+
db.exec("DROP TABLE IF EXISTS embedding_salvage");
|
|
294
|
+
db.exec("DROP TABLE IF EXISTS entry_fragments_fts");
|
|
295
|
+
// One float32 BLOB per entry, searched by an exact scan
|
|
296
|
+
// (index-vec-repository.ts). `model` is the provider fingerprint the vector was generated under
|
|
297
|
+
// (`deriveSemanticProviderFingerprint`); the embedding pass re-embeds only
|
|
298
|
+
// rows whose model differs from the configured one. NULL means the row
|
|
299
|
+
// predates model tracking and is trusted as the current model.
|
|
251
300
|
db.exec(`
|
|
252
301
|
CREATE TABLE IF NOT EXISTS embeddings (
|
|
253
302
|
id INTEGER PRIMARY KEY,
|
|
254
303
|
embedding BLOB NOT NULL,
|
|
304
|
+
model TEXT,
|
|
255
305
|
FOREIGN KEY (id) REFERENCES entries(id)
|
|
256
306
|
);
|
|
257
307
|
`);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
308
|
+
if (ensureColumn(db, "embeddings", "model", "TEXT")) {
|
|
309
|
+
// Rows written before model tracking were generated under the fingerprint
|
|
310
|
+
// the last pass recorded; label them so a later model change re-embeds
|
|
311
|
+
// them instead of trusting them forever.
|
|
312
|
+
const fingerprint = getMeta(db, "embeddingFingerprint");
|
|
313
|
+
if (fingerprint)
|
|
314
|
+
db.prepare("UPDATE embeddings SET model = ? WHERE model IS NULL").run(fingerprint);
|
|
315
|
+
}
|
|
316
|
+
// Utility scores (aggregated per-entry utility metrics) — a regenerable
|
|
317
|
+
// cache recomputed from state.db's usage_events on every index run.
|
|
261
318
|
db.exec(`
|
|
262
319
|
CREATE TABLE IF NOT EXISTS utility_scores (
|
|
263
320
|
entry_id INTEGER PRIMARY KEY,
|
|
@@ -272,7 +329,6 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
272
329
|
`);
|
|
273
330
|
// Per-project scoped utility scores — tracks usage per (entry, cwd-anchor)
|
|
274
331
|
// 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
332
|
db.exec(`
|
|
277
333
|
CREATE TABLE IF NOT EXISTS utility_scores_scoped (
|
|
278
334
|
entry_id INTEGER NOT NULL,
|
|
@@ -291,16 +347,18 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
291
347
|
file_mtime_max_ms REAL NOT NULL,
|
|
292
348
|
reason TEXT NOT NULL,
|
|
293
349
|
updated_at TEXT NOT NULL,
|
|
294
|
-
row_count INTEGER
|
|
350
|
+
row_count INTEGER,
|
|
351
|
+
index_variant TEXT
|
|
295
352
|
);
|
|
296
353
|
`);
|
|
297
|
-
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
//
|
|
303
|
-
//
|
|
354
|
+
// #900 (`row_count`) and the adapter variant were added after the table's
|
|
355
|
+
// first release. Pre-existing rows keep NULL until their directory is next
|
|
356
|
+
// drained.
|
|
357
|
+
ensureColumn(db, "index_dir_state", "row_count", "INTEGER");
|
|
358
|
+
ensureColumn(db, "index_dir_state", "index_variant", "TEXT");
|
|
359
|
+
// LLM enrichment result cache, keyed by a stable asset_ref string (the
|
|
360
|
+
// absolute file path for graph/memory passes, `item_ref` for the
|
|
361
|
+
// metadata-enhance pass) plus the body hash the result was produced for.
|
|
304
362
|
db.exec(`
|
|
305
363
|
CREATE TABLE IF NOT EXISTS llm_enrichment_cache (
|
|
306
364
|
asset_ref TEXT NOT NULL,
|
|
@@ -314,110 +372,24 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
314
372
|
CREATE INDEX IF NOT EXISTS idx_llm_cache_updated
|
|
315
373
|
ON llm_enrichment_cache(updated_at);
|
|
316
374
|
`);
|
|
317
|
-
// Graph extraction tables — schema v4 ((stash_root, file_path, body_hash) PK).
|
|
318
|
-
//
|
|
319
|
-
// graph_files is self-keyed on (stash_root, file_path, body_hash) and is NO
|
|
320
|
-
// LONGER tied to entries.id. This is the #624-P1 win: deleting and
|
|
321
|
-
// re-inserting an entries row during a reindex no longer cascade-wipes the
|
|
322
|
-
// extracted graph — as long as the file's body_hash is unchanged, the graph
|
|
323
|
-
// data survives. body_hash is part of the PK so a content change yields a
|
|
324
|
-
// distinct key; a UNIQUE index on (stash_root, file_path) still enforces
|
|
325
|
-
// exactly one graph_files row per path (delete-then-insert on a hash change).
|
|
326
|
-
//
|
|
327
|
-
// graph_file_entities and graph_file_relations carry (stash_root, file_path,
|
|
328
|
-
// body_hash) and declare a composite FK -> graph_files ON DELETE CASCADE so
|
|
329
|
-
// child rows are removed when a graph_files row is replaced.
|
|
330
|
-
//
|
|
331
375
|
ensureGraphTables(db);
|
|
332
|
-
|
|
333
|
-
//
|
|
334
|
-
|
|
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}).`);
|
|
355
|
-
}
|
|
356
|
-
if (isVecAvailable(db)) {
|
|
357
|
-
// Check if stored embedding dimension differs from configured one
|
|
358
|
-
if (dimExplicit) {
|
|
359
|
-
const storedDim = getMeta(db, "embeddingDim");
|
|
360
|
-
if (storedDim && storedDim !== String(effectiveDim)) {
|
|
361
|
-
// Stored vectors are incompatible with the new dimension. Drop the vec
|
|
362
|
-
// table so the block below recreates it at the new width; the BLOB rows
|
|
363
|
-
// go too. Regenerable from markdown — re-embedded by the next index.
|
|
364
|
-
purgeEmbeddings(db, { dropVecTable: true });
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
const vecExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='entries_vec'").get();
|
|
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
|
-
}
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
// Also purge BLOB embeddings on dimension change (JS fallback path).
|
|
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
|
-
}
|
|
393
|
-
}
|
|
394
|
-
// Usage telemetry (usage_events) lives in state.db since Chunk-8 WI-8.3 —
|
|
395
|
-
// no longer created here.
|
|
396
|
-
// Registry index cache table — caches remote registry index documents so
|
|
397
|
-
// `akm search` does not hit the network on every invocation.
|
|
376
|
+
dropVecMirror(db);
|
|
377
|
+
// Meta keys only the sqlite-vec mirror read.
|
|
378
|
+
db.exec("DELETE FROM index_meta WHERE key IN ('embeddingDim', 'vecFastPathReady')");
|
|
398
379
|
db.exec(REGISTRY_INDEX_CACHE_DDL);
|
|
399
|
-
|
|
400
|
-
//
|
|
401
|
-
//
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
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");
|
|
380
|
+
ensureFtsLayout(db);
|
|
381
|
+
// An index that had no fragment source table (v22 and earlier) has no safe
|
|
382
|
+
// Markdown for `akm show` to resolve fragment selectors from until each
|
|
383
|
+
// directory is drained again. Clearing the per-directory cursor makes the
|
|
384
|
+
// next run re-read every source; entry ids, embeddings and utility rows
|
|
385
|
+
// stay put.
|
|
386
|
+
if (!hadFragmentSource && tableExists(db, "entries")) {
|
|
387
|
+
db.exec("DELETE FROM index_dir_state");
|
|
422
388
|
}
|
|
389
|
+
// Migrating an existing layout drops tables and columns; the next `akm index`
|
|
390
|
+
// VACUUMs the pages they leave free (`vacuumIndexDb`, indexer.ts), since a
|
|
391
|
+
// writable open may run inside a caller's transaction, where VACUUM cannot.
|
|
392
|
+
if (storedVersion > 0 && storedVersion < DB_VERSION)
|
|
393
|
+
setMeta(db, VACUUM_PENDING_META, "1");
|
|
394
|
+
setMeta(db, "version", String(DB_VERSION));
|
|
423
395
|
}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* `index.db` utility-score + retrieval-count repository (MemRL signals).
|
|
6
6
|
*
|
|
7
|
-
* Owns the raw SQL for `utility_scores`
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Owns the raw SQL for `utility_scores` and the retrieval-frequency counting
|
|
8
|
+
* over `usage_events`. The bounded-step EMA policy itself lives in
|
|
9
|
+
* `indexer/feedback/utility-policy`; this repo only reads/writes.
|
|
10
10
|
*/
|
|
11
11
|
import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
|
|
12
12
|
import { computeNextUtility } from "../../indexer/feedback/utility-policy.js";
|
|
@@ -31,18 +31,10 @@ export function getUtilityScore(db, entryId) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* Batch-load utility scores for multiple entry IDs
|
|
35
|
-
* Returns a `{ global, scoped }` pair, both Maps keyed by entry_id.
|
|
36
|
-
*
|
|
37
|
-
* When `scopeKey` is provided a second query runs against
|
|
38
|
-
* `utility_scores_scoped` and the result is returned as `scoped`.
|
|
39
|
-
* Both maps are always present; `scoped` is empty when `scopeKey` is absent.
|
|
34
|
+
* Batch-load utility scores for multiple entry IDs, keyed by entry_id.
|
|
40
35
|
*/
|
|
41
|
-
export function getUtilityScoresByIds(db, ids
|
|
42
|
-
const
|
|
43
|
-
const scoped = new Map();
|
|
44
|
-
if (ids.length === 0)
|
|
45
|
-
return { global, scoped };
|
|
36
|
+
export function getUtilityScoresByIds(db, ids) {
|
|
37
|
+
const scores = new Map();
|
|
46
38
|
// Process in chunks to stay within SQLITE_MAX_VARIABLE_NUMBER
|
|
47
39
|
for (let i = 0; i < ids.length; i += SQLITE_CHUNK_SIZE) {
|
|
48
40
|
const chunk = ids.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
@@ -51,7 +43,7 @@ export function getUtilityScoresByIds(db, ids, scopeKey) {
|
|
|
51
43
|
.prepare(`SELECT entry_id, utility, show_count, search_count, select_rate, last_used_at, updated_at FROM utility_scores WHERE entry_id IN (${placeholders})`)
|
|
52
44
|
.all(...chunk);
|
|
53
45
|
for (const row of rows) {
|
|
54
|
-
|
|
46
|
+
scores.set(row.entry_id, {
|
|
55
47
|
entryId: row.entry_id,
|
|
56
48
|
utility: row.utility,
|
|
57
49
|
showCount: row.show_count,
|
|
@@ -61,21 +53,8 @@ export function getUtilityScoresByIds(db, ids, scopeKey) {
|
|
|
61
53
|
updatedAt: row.updated_at,
|
|
62
54
|
});
|
|
63
55
|
}
|
|
64
|
-
if (scopeKey) {
|
|
65
|
-
const scopedRows = db
|
|
66
|
-
.prepare(`SELECT entry_id, scope_key, utility, last_used_at FROM utility_scores_scoped WHERE scope_key = ? AND entry_id IN (${placeholders})`)
|
|
67
|
-
.all(scopeKey, ...chunk);
|
|
68
|
-
for (const row of scopedRows) {
|
|
69
|
-
scoped.set(row.entry_id, {
|
|
70
|
-
entryId: row.entry_id,
|
|
71
|
-
scopeKey: row.scope_key,
|
|
72
|
-
utility: row.utility,
|
|
73
|
-
lastUsedAt: row.last_used_at,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
56
|
}
|
|
78
|
-
return
|
|
57
|
+
return scores;
|
|
79
58
|
}
|
|
80
59
|
/**
|
|
81
60
|
* Insert or update a utility score for an entry.
|