akm-cli 0.9.1 → 0.9.2-alpha.1
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 +88 -0
- package/README.md +3 -1
- package/SECURITY.md +1 -1
- package/STABILITY.md +1 -1
- package/dist/akm +2 -2
- package/dist/akm-migrate +2 -2
- package/dist/assets/hints/cli-hints-full.md +14 -9
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/models.json +35 -0
- package/dist/assets/tasks/core/extract.yml +6 -5
- package/dist/assets/tasks/core/improve.yml +6 -5
- package/dist/assets/tasks/core/index-refresh.yml +6 -5
- package/dist/assets/tasks/core/sync.yml +6 -5
- package/dist/assets/tasks/core/version-check.yml +6 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
- package/dist/cli/confirm.js +2 -2
- package/dist/cli/parse-args.js +3 -24
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +2 -2
- package/dist/cli.js +11 -9
- package/dist/commands/agent/agent-dispatch.js +55 -89
- package/dist/commands/agent/contribute-cli.js +12 -45
- package/dist/commands/command/builtin-action.js +32 -0
- package/dist/commands/command/command-cli.js +99 -0
- package/dist/commands/command/command-execution.js +308 -0
- package/dist/commands/command/execution-source-loader.js +176 -0
- package/dist/commands/command/portable-template.js +60 -0
- package/dist/commands/config-cli.js +10 -4
- package/dist/commands/env/env.js +4 -2
- package/dist/commands/feedback-cli.js +1 -1
- package/dist/commands/health/checks.js +241 -29
- package/dist/commands/health/html-report.js +0 -14
- package/dist/commands/health/report-view-model.js +0 -1
- package/dist/commands/health/surfaces.js +6 -7
- package/dist/commands/health/types.js +0 -2
- package/dist/commands/health.js +63 -18
- package/dist/commands/improve/collapse-detector.js +2 -2
- package/dist/commands/improve/consolidate.js +251 -214
- package/dist/commands/improve/distill/promote-memory.js +71 -34
- package/dist/commands/improve/distill/quality-gate.js +17 -5
- package/dist/commands/improve/distill.js +232 -155
- package/dist/commands/improve/eligibility.js +112 -79
- package/dist/commands/improve/execution.js +57 -0
- package/dist/commands/improve/extract-cli.js +5 -5
- package/dist/commands/improve/extract.js +521 -342
- package/dist/commands/improve/improve-strategies.js +43 -14
- package/dist/commands/improve/improve.js +249 -29
- package/dist/commands/improve/loop-stages.js +11 -17
- package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
- package/dist/commands/improve/outcome-loop.js +22 -38
- package/dist/commands/improve/planner.js +134 -0
- package/dist/commands/improve/preparation.js +730 -409
- package/dist/commands/improve/reflect.js +386 -223
- package/dist/commands/improve/run-context.js +3 -4
- package/dist/commands/improve/salience.js +6 -58
- package/dist/commands/improve/session-asset.js +12 -12
- package/dist/commands/lint/index.js +101 -29
- package/dist/commands/migrate-cli.js +11 -69
- package/dist/commands/migration-tool.js +6 -9
- package/dist/commands/models-cli.js +27 -0
- package/dist/commands/proposal/drain.js +258 -186
- package/dist/commands/proposal/proposal-cli.js +32 -10
- package/dist/commands/proposal/proposal.js +2 -5
- package/dist/commands/proposal/propose.js +192 -172
- package/dist/commands/proposal/repository.js +54 -91
- package/dist/commands/proposal/validators/proposal-validators.js +9 -7
- package/dist/commands/read/curate.js +10 -0
- package/dist/commands/read/registry-search.js +25 -9
- package/dist/commands/read/remember-cli.js +14 -2
- package/dist/commands/read/search.js +10 -4
- package/dist/commands/read/show.js +139 -153
- package/dist/commands/registry-cli.js +16 -7
- package/dist/commands/remember.js +33 -18
- package/dist/commands/sources/add-cli.js +19 -178
- package/dist/commands/sources/bundle-cli.js +15 -3
- package/dist/commands/sources/dangerous-env-audit.js +135 -0
- package/dist/commands/sources/info.js +2 -1
- package/dist/commands/sources/installed-stashes.js +835 -152
- package/dist/commands/sources/schema-repair.js +174 -95
- package/dist/commands/sources/self-update.js +30 -74
- package/dist/commands/sources/source-add.js +3 -5
- package/dist/commands/sources/sources-cli.js +2 -15
- package/dist/commands/sources/update-transaction.js +220 -0
- package/dist/commands/tasks/tasks-cli.js +3 -3
- package/dist/commands/tasks/tasks.js +736 -317
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
- package/dist/core/adapter/adapters/akm-adapter.js +83 -34
- package/dist/core/adapter/adapters/akm-lint.js +54 -39
- package/dist/core/adapter/adapters/akm-metadata.js +45 -45
- package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
- package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
- package/dist/core/adapter/adapters/index.js +0 -9
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
- package/dist/core/adapter/adapters/okf-adapter.js +4 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
- package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
- package/dist/core/adapter/execution-source.js +308 -0
- package/dist/core/adapter/recognize-match.js +36 -13
- package/dist/core/adapter/registry.js +0 -9
- package/dist/core/asset/stash-meta.js +94 -4
- package/dist/core/common.js +6 -11
- package/dist/core/config/config-io.js +3 -3
- package/dist/core/config/config-schema.js +18 -40
- package/dist/core/config/config-sources.js +11 -21
- package/dist/core/config/config-walker.js +31 -13
- package/dist/core/config/config.js +21 -20
- package/dist/core/config/schema/engines.js +8 -7
- package/dist/core/config/schema/improve-processes.js +29 -5
- package/dist/core/config/schema/primitives.js +1 -23
- package/dist/core/config/schema/sources-bundles.js +13 -16
- package/dist/core/errors.js +2 -0
- package/dist/core/events.js +68 -32
- package/dist/core/extra-params.js +1 -0
- package/dist/core/improve-result.js +315 -0
- package/dist/core/lesson-lint.js +0 -6
- package/dist/core/maintenance-barrier.js +4 -4
- package/dist/core/network-policy.js +152 -0
- package/dist/core/paths.js +1 -1
- package/dist/core/recognition-util.js +4 -4
- package/dist/core/registry-url.js +456 -0
- package/dist/core/state/migrations.js +161 -47
- package/dist/core/state-db.js +453 -80
- package/dist/core/system-error.js +32 -0
- package/dist/core/time.js +2 -12
- package/dist/core/write-source.js +0 -18
- package/dist/execution/directory-identity.js +52 -0
- package/dist/execution/executable-identity.js +107 -0
- package/dist/execution/guarded-source.js +398 -0
- package/dist/execution/json.js +95 -0
- package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
- package/dist/execution/record.js +55 -0
- package/dist/execution/resolved-request.js +730 -0
- package/dist/execution/source.js +320 -0
- package/dist/indexer/bundle-identity-guard.js +5 -4
- package/dist/indexer/db/graph-db.js +33 -0
- package/dist/indexer/graph/graph-boost.js +3 -4
- package/dist/indexer/graph/graph-extraction.js +562 -373
- package/dist/indexer/index-written-assets.js +65 -34
- package/dist/indexer/indexer.js +443 -222
- package/dist/indexer/installations.js +6 -0
- package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
- package/dist/indexer/passes/memory-inference.js +227 -174
- package/dist/indexer/scan/doc-to-entry.js +7 -9
- package/dist/indexer/scan/drain-dir.js +51 -23
- package/dist/indexer/search/db-search.js +98 -22
- package/dist/indexer/search/search-fields.js +1 -1
- package/dist/indexer/search/search-hit-enrichers.js +1 -1
- package/dist/indexer/search/search-source.js +7 -16
- package/dist/indexer/search/semantic-status.js +10 -1
- package/dist/indexer/usage/show-usage.js +105 -0
- package/dist/indexer/usage/usage-events.js +7 -2
- package/dist/indexer/walk/matchers.js +40 -10
- package/dist/indexer/walk/path-resolver.js +5 -2
- package/dist/indexer/walk/walker.js +20 -2
- package/dist/integrations/agent/builder-shared.js +3 -6
- package/dist/integrations/agent/conversation-fallback.js +16 -0
- package/dist/integrations/agent/engine-resolution.js +87 -87
- package/dist/integrations/agent/execution-cascade.js +566 -0
- package/dist/integrations/agent/execution-definitions.js +211 -0
- package/dist/integrations/agent/execution-lowering.js +811 -0
- package/dist/integrations/agent/execution-preparation.js +67 -0
- package/dist/integrations/agent/index.js +0 -2
- package/dist/integrations/agent/inline-execution.js +74 -0
- package/dist/integrations/agent/model-map.js +515 -0
- package/dist/integrations/agent/persona-fallback.js +30 -0
- package/dist/integrations/agent/request-lowering.js +186 -0
- package/dist/integrations/agent/runner-dispatch.js +230 -37
- package/dist/integrations/agent/runner.js +12 -83
- package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
- package/dist/integrations/harnesses/aider/index.js +0 -1
- package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
- package/dist/integrations/harnesses/amazonq/index.js +0 -1
- package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
- package/dist/integrations/harnesses/claude/index.js +1 -5
- package/dist/integrations/harnesses/claude/session-log.js +3 -33
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
- package/dist/integrations/harnesses/codex/index.js +0 -1
- package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
- package/dist/integrations/harnesses/copilot/index.js +0 -1
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
- package/dist/integrations/harnesses/gemini/index.js +0 -1
- package/dist/integrations/harnesses/index.js +4 -44
- package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
- package/dist/integrations/harnesses/opencode/index.js +0 -2
- package/dist/integrations/harnesses/opencode/session-log.js +14 -204
- package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
- package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
- package/dist/integrations/harnesses/openhands/index.js +0 -1
- package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
- package/dist/integrations/harnesses/pi/index.js +0 -1
- package/dist/integrations/harnesses/shared.js +0 -1
- package/dist/integrations/harnesses/types.js +1 -3
- package/dist/integrations/lockfile.js +82 -79
- package/dist/integrations/session-logs/index.js +6 -17
- package/dist/integrations/session-logs/provider-base.js +1 -29
- package/dist/llm/client.js +10 -5
- package/dist/llm/embedder.js +6 -7
- package/dist/llm/embedders/local.js +37 -88
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +75 -50
- package/dist/llm/index-passes.js +43 -5
- package/dist/llm/memory-infer.js +8 -6
- package/dist/llm/metadata-enhance.js +5 -3
- package/dist/llm/structured-call.js +122 -25
- package/dist/output/format-exempt.js +1 -1
- package/dist/output/render-registry.js +0 -16
- package/dist/output/renderers.js +12 -7
- package/dist/output/shapes/curate.js +1 -0
- package/dist/output/shapes/helpers.js +10 -2
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/command-format.js +28 -32
- package/dist/output/text/health-format.js +1 -29
- package/dist/output/text/migrate.js +6 -56
- package/dist/output/text/proposal-format.js +16 -1
- package/dist/output/text/workflow-format.js +16 -0
- package/dist/registry/network.js +279 -0
- package/dist/registry/pinned-request-helper.js +247 -0
- package/dist/registry/pinned-transport.js +717 -0
- package/dist/registry/providers/skills-sh.js +18 -6
- package/dist/registry/providers/static-index.js +20 -7
- package/dist/registry/resolve.js +53 -28
- package/dist/scripts/akm-migrate-node.js +19122 -52218
- package/dist/scripts/akm-migrate.js +19064 -51567
- package/dist/setup/registry-stash-loader.js +64 -20
- package/dist/setup/semantic-assets.js +9 -34
- package/dist/setup/setup.js +12 -30
- package/dist/setup/source-identity.js +17 -0
- package/dist/setup/steps/sources.js +36 -15
- package/dist/setup/steps/tasks.js +39 -11
- package/dist/sources/providers/git-provider.js +3 -3
- package/dist/sources/providers/npm.js +2 -2
- package/dist/sources/providers/provider-utils.js +4 -3
- package/dist/sources/providers/website.js +11 -7
- package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
- package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
- package/dist/sources/website-url.js +73 -0
- package/dist/storage/engines/sqlite-migrations.js +81 -26
- package/dist/storage/managed-db.js +27 -24
- package/dist/storage/repositories/events-repository.js +3 -0
- package/dist/storage/repositories/index-connection.js +42 -10
- package/dist/storage/repositories/index-entries-repository.js +167 -207
- package/dist/storage/repositories/index-entry-mapper.js +8 -12
- package/dist/storage/repositories/index-entry-schema.js +255 -0
- package/dist/storage/repositories/index-fts-repository.js +10 -10
- package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
- package/dist/storage/repositories/index-meta-repository.js +0 -11
- package/dist/storage/repositories/index-schema.js +71 -342
- package/dist/storage/repositories/index-utility-repository.js +12 -17
- package/dist/storage/repositories/index-vec-repository.js +1 -1
- package/dist/storage/repositories/proposals-repository.js +4 -127
- package/dist/storage/repositories/registry-cache.js +2 -1
- package/dist/storage/repositories/task-history-repository.js +20 -40
- package/dist/storage/repositories/workflow-runs-repository.js +228 -129
- package/dist/storage/sqlite-read-snapshot.js +148 -0
- package/dist/tasks/backends/cron.js +170 -42
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +787 -202
- package/dist/tasks/backends/schtasks.js +282 -83
- package/dist/tasks/embedded.js +7 -7
- package/dist/tasks/frozen-script.js +50 -0
- package/dist/tasks/resolve-akm-bin.js +5 -1
- package/dist/tasks/runner.js +239 -251
- package/dist/tasks/runtime-v3.js +281 -0
- package/dist/tasks/scheduler-binding.js +272 -0
- package/dist/tasks/scheduler-invocation.js +57 -43
- package/dist/tasks/scheduler-sync.js +654 -0
- package/dist/tasks/source-v3.js +752 -0
- package/dist/tasks/standalone-script-entry.js +5 -0
- package/dist/tasks/task-id.js +29 -0
- package/dist/workflows/authoring/authoring.js +15 -32
- package/dist/workflows/exec/dispatch-redaction.js +14 -8
- package/dist/workflows/exec/exec-unit.js +7 -28
- package/dist/workflows/exec/frozen-judge.js +57 -89
- package/dist/workflows/exec/lowering-notices.js +23 -0
- package/dist/workflows/exec/native-executor.js +301 -458
- package/dist/workflows/exec/param-secrets.js +4 -3
- package/dist/workflows/exec/run-workflow.js +26 -32
- package/dist/workflows/exec/step-work.js +105 -109
- package/dist/workflows/exec/unit-dispatch.js +103 -27
- package/dist/workflows/exec/unit-writer.js +3 -3
- package/dist/workflows/exec/worktree.js +2 -2
- package/dist/workflows/ir/compile.js +86 -72
- package/dist/workflows/ir/environment-v4.js +328 -0
- package/dist/workflows/ir/freeze-v4.js +122 -0
- package/dist/workflows/ir/plan-hash.js +13 -7
- package/dist/workflows/ir/schema-v4.js +525 -0
- package/dist/workflows/ir/schema.js +25 -284
- package/dist/workflows/ir/source-freeze-v4.js +506 -0
- package/dist/workflows/parser.js +27 -24
- package/dist/workflows/program/schema.js +1 -2
- package/dist/workflows/renderer.js +42 -29
- package/dist/workflows/resource-limits.js +4 -5
- package/dist/workflows/runtime/agent-identity.js +11 -13
- package/dist/workflows/runtime/plan-classifier.js +8 -8
- package/dist/workflows/runtime/runs.js +27 -43
- package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
- package/dist/workflows/source-files.js +373 -0
- package/dist/workflows/source-ir/compile.js +196 -0
- package/dist/workflows/source-ir/github-yaml.js +577 -0
- package/dist/workflows/source-ir/ordering.js +38 -0
- package/dist/workflows/source-ir/program.js +50 -0
- package/dist/workflows/source-ir/result.js +26 -0
- package/dist/workflows/source-ir/schema.js +772 -0
- package/dist/workflows/source-ir/semantics.js +242 -0
- package/dist/workflows/source-ir/uses.js +14 -0
- package/docs/README.md +2 -0
- package/docs/migration/README.md +3 -1
- package/docs/migration/release-notes/0.9.2.md +55 -0
- package/docs/migration/release-notes/README.md +5 -0
- package/docs/migration/v0.8-to-v0.9.md +76 -1077
- package/docs/migration/v0.9.0-troubleshooting.md +104 -516
- package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
- package/docs/reference/README.md +1 -0
- package/docs/reference/cli.md +230 -98
- package/docs/reference/configuration.md +153 -27
- package/docs/reference/data-and-telemetry.md +19 -1
- package/docs/reference/supported-formats.md +23 -3
- package/docs/reference/tasks.md +182 -0
- package/docs/reference/workflow-schema.md +91 -40
- package/docs/reference/workflows.md +33 -6
- package/package.json +10 -6
- package/schemas/akm-config.json +372 -216
- package/schemas/akm-task.json +324 -80
- package/schemas/akm-workflow.json +6 -9
- package/dist/core/migration-operation.js +0 -75
- package/dist/integrations/agent/model-aliases.js +0 -74
- package/dist/tasks/parser.js +0 -380
- package/dist/tasks/schema.js +0 -123
- package/dist/tasks/validator.js +0 -80
- package/dist/workflows/ir/freeze.js +0 -320
- package/dist/workflows/runtime/document-cache.js +0 -13
|
@@ -1,77 +1,22 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
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
|
-
|
|
5
|
-
* index.db schema, version stamps, and targeted migrations, kept in the
|
|
6
|
-
* storage layer. This isolates the one genuinely risky area (schema
|
|
7
|
-
* evolution) from the CRUD/FTS/vector queries.
|
|
8
|
-
*
|
|
9
|
-
* The meta accessors, embedding purge, and vec-availability probe that
|
|
10
|
-
* `ensureSchema` leans on live in the sibling `index-meta-repository` /
|
|
11
|
-
* `index-vec-repository` modules.
|
|
12
|
-
*/
|
|
13
|
-
import { bestEffort } from "../../core/best-effort.js";
|
|
14
|
-
import { warn } from "../../core/warn.js";
|
|
4
|
+
import { CANONICAL_ENTRY_SCHEMA_SQL, CANONICAL_INDEX_DB_VERSION, isCanonicalIndexGeneration, } from "./index-entry-schema.js";
|
|
15
5
|
import { getMeta, setMeta } from "./index-meta-repository.js";
|
|
16
6
|
import { isVecAvailable, purgeEmbeddings } from "./index-vec-repository.js";
|
|
17
7
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// TARGETED, graph-only migration (migrateGraphFilesSchema) — the model for any
|
|
23
|
-
// incompatible change: migrate in place, never wipe the whole index.
|
|
24
|
-
//
|
|
25
|
-
// v17→v18 (Chunk-5 Step 2, spec §14.4): the `entries` table gains the durable
|
|
26
|
-
// bundle-adapter identity/provenance columns — `item_ref` (`<bundle>//<concept
|
|
27
|
-
// -id>` canonical stored spelling), `bundle_id`/`component_id`/`concept_id`/
|
|
28
|
-
// `adapter_id` provenance, `type` (open token), and `content_hash`/`document
|
|
29
|
-
// _json`. They land ADDITIVELY ALONGSIDE the legacy `entry_key`/`dir_path`/
|
|
30
|
-
// `stash_dir`/`entry_json`/`entry_type` columns (dev-time transitional shape):
|
|
31
|
-
// the writer populates the identity/provenance columns while every reader still
|
|
32
|
-
// keys on the legacy columns, so the battery stays green while the reader
|
|
33
|
-
// repoint + ref-grammar flip land incrementally. The legacy columns + this
|
|
34
|
-
// coexistence are removed once every reader is repointed onto `item_ref`
|
|
35
|
-
// (spec §3.3 — single clean shape, no dual read-path). The index is a
|
|
36
|
-
// regenerable derived cache, so an `akm index` rebuild repopulates the new
|
|
37
|
-
// columns on any DB opened at an older version.
|
|
8
|
+
// index.db is a regenerable cache. Incompatible entry-schema changes advance
|
|
9
|
+
// this generation and discard only derived index tables; durable state remains
|
|
10
|
+
// in state.db. Current readers and writers therefore target exactly one schema
|
|
11
|
+
// and never carry live compatibility SQL for previous generations.
|
|
38
12
|
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
// (020-three-db-cutover) with orphan quarantine in `legacy_state`. The index is
|
|
45
|
-
// regenerable, so a rebuild is an acceptable fallback if the UNIQUE upgrade finds
|
|
46
|
-
// a duplicate on a partially-migrated DB.
|
|
47
|
-
//
|
|
48
|
-
// v19→v20 (Chunk-8 WI-8.3, three-DB merge): index.db STOPS owning `usage_events`
|
|
49
|
-
// + `legacy_state`. Both are durable, non-regenerable state and now live in
|
|
50
|
-
// state.db (folded by state migration 020; the cutover rescues the old index.db
|
|
51
|
-
// rows across). index.db is a regenerable cache, so dropping their DDL from the
|
|
52
|
-
// schema path needs no migration — a rebuild simply no longer re-creates them.
|
|
53
|
-
// STANDARD REBUILD NOTE: after this bump, any index.db opened at v19 is rebuilt
|
|
54
|
-
// from the stash on the next `akm index`; usage_events/legacy_state are read
|
|
55
|
-
// exclusively from state.db thereafter.
|
|
56
|
-
//
|
|
57
|
-
// Reader/writer repoint progress (spec §3.3 "single clean shape"): the `entries`
|
|
58
|
-
// upsert (index-entries-repository `getUpsertStmts`) uses the UNIQUE `item_ref`
|
|
59
|
-
// as its PRIMARY conflict target, and the graph-boost related-ref reader
|
|
60
|
-
// (`listRelatedPathsForFile`) resolves the user-facing ref from
|
|
61
|
-
// `concept_id`/`item_ref` instead of stripping `entry_key`. The legacy
|
|
62
|
-
// `entry_key`/`dir_path`/`stash_dir`/`entry_type`/`entry_json` columns are NOT
|
|
63
|
-
// yet removable: they retain live consumers outside this module — `entry_key`
|
|
64
|
-
// (mv-cli re-key, usage-event legacy resolution, index-entry-mapper, the LLM
|
|
65
|
-
// cache), `entry_json` (the row payload every reader decodes), `entry_type`
|
|
66
|
-
// (FTS + workflow loader), `stash_dir`/`dir_path` (scan/delete/utility scoping).
|
|
67
|
-
// The upsert therefore keeps `entry_key` as a NULL-item_ref-safe SECOND conflict
|
|
68
|
-
// target (the LLM metadata-enhance re-upsert still writes existing rows with a
|
|
69
|
-
// NULL item_ref) and degrades to it entirely when the item_ref index is the
|
|
70
|
-
// non-unique fallback. Both are deletable once every remaining reader repoints.
|
|
71
|
-
export const DB_VERSION = 20;
|
|
13
|
+
// v20→v21: remove the transitional entry_key/dir_path/stash_dir/entry_json/
|
|
14
|
+
// entry_type columns. item_ref is the sole conflict key; document_json is the
|
|
15
|
+
// sole stored document projection; bundle provenance and file_path provide the
|
|
16
|
+
// current identity and materialized read path.
|
|
17
|
+
export const DB_VERSION = CANONICAL_INDEX_DB_VERSION;
|
|
72
18
|
export const EMBEDDING_DIM = 384;
|
|
73
|
-
// #624-P1: graph_files
|
|
74
|
-
// as a marker; the actual migration is the targeted drop in migrateGraphFilesSchema.
|
|
19
|
+
// #624-P1: graph_files is keyed to (stash_root, file_path, body_hash).
|
|
75
20
|
export const GRAPH_SCHEMA_VERSION = 4;
|
|
76
21
|
// ── Schema ──────────────────────────────────────────────────────────────────
|
|
77
22
|
/**
|
|
@@ -111,9 +56,7 @@ const REGISTRY_INDEX_CACHE_DDL = `
|
|
|
111
56
|
`;
|
|
112
57
|
/**
|
|
113
58
|
* Create the graph-extraction tables (`graph_meta`/`graph_files`/`graph_file_entities`/
|
|
114
|
-
* `graph_file_relations`/`graph_extraction_queue`).
|
|
115
|
-
* {@link ensureSchema} (called at the same point, between `migrateGraphFilesSchema`
|
|
116
|
-
* and `migrateGraphDataFromLegacy`) — a pure, behavior-identical decomposition.
|
|
59
|
+
* `graph_file_relations`/`graph_extraction_queue`).
|
|
117
60
|
*/
|
|
118
61
|
function ensureGraphTables(db) {
|
|
119
62
|
db.exec(`
|
|
@@ -205,6 +148,48 @@ function ensureGraphTables(db) {
|
|
|
205
148
|
ON graph_extraction_queue(stash_root, priority DESC, queued_at);
|
|
206
149
|
`);
|
|
207
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Cross the incompatible entry-schema boundary by discarding the derived index
|
|
153
|
+
* generation. No row conversion or dual-schema compatibility is attempted:
|
|
154
|
+
* the next index run rebuilds entries, FTS, embeddings, utility aggregates,
|
|
155
|
+
* graph extraction, and enrichment caches from current sources/state.
|
|
156
|
+
*/
|
|
157
|
+
function rebuildIncompatibleIndexGeneration(db) {
|
|
158
|
+
const version = getMeta(db, "version");
|
|
159
|
+
const hasEntries = tableExists(db, "entries");
|
|
160
|
+
if (!hasEntries && version === undefined)
|
|
161
|
+
return;
|
|
162
|
+
if (isCanonicalIndexGeneration(db))
|
|
163
|
+
return;
|
|
164
|
+
let vecResetPending = false;
|
|
165
|
+
try {
|
|
166
|
+
db.exec("DROP TABLE IF EXISTS entries_vec");
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// A vec0 table cannot be dropped while sqlite-vec is unavailable. It does
|
|
170
|
+
// not reference entries, so leave a marker and drop it on the first later
|
|
171
|
+
// open where the extension is available.
|
|
172
|
+
vecResetPending = true;
|
|
173
|
+
}
|
|
174
|
+
db.transaction(() => {
|
|
175
|
+
db.exec("DROP TABLE IF EXISTS graph_file_relations");
|
|
176
|
+
db.exec("DROP TABLE IF EXISTS graph_file_entities");
|
|
177
|
+
db.exec("DROP TABLE IF EXISTS graph_files");
|
|
178
|
+
db.exec("DROP TABLE IF EXISTS graph_extraction_queue");
|
|
179
|
+
db.exec("DROP TABLE IF EXISTS graph_meta");
|
|
180
|
+
db.exec("DROP TABLE IF EXISTS entries_fts_dirty");
|
|
181
|
+
db.exec("DROP TABLE IF EXISTS entries_fts");
|
|
182
|
+
db.exec("DROP TABLE IF EXISTS embeddings");
|
|
183
|
+
db.exec("DROP TABLE IF EXISTS utility_scores_scoped");
|
|
184
|
+
db.exec("DROP TABLE IF EXISTS utility_scores");
|
|
185
|
+
db.exec("DROP TABLE IF EXISTS llm_enrichment_cache");
|
|
186
|
+
db.exec("DROP TABLE IF EXISTS index_dir_state");
|
|
187
|
+
db.exec("DROP TABLE IF EXISTS entries");
|
|
188
|
+
db.exec("DELETE FROM index_meta");
|
|
189
|
+
})();
|
|
190
|
+
if (vecResetPending)
|
|
191
|
+
setMeta(db, "vecResetPending", "1");
|
|
192
|
+
}
|
|
208
193
|
export function ensureSchema(db, embeddingDim) {
|
|
209
194
|
// Create meta table first so we can check version
|
|
210
195
|
db.exec(`
|
|
@@ -213,87 +198,14 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
213
198
|
value TEXT NOT NULL
|
|
214
199
|
);
|
|
215
200
|
`);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
// incompatible change is handled by an additive/targeted migration; the few
|
|
225
|
-
// derived tables that ever must be rebuilt are regenerated by `akm index`.
|
|
226
|
-
db.exec(`
|
|
227
|
-
CREATE TABLE IF NOT EXISTS entries (
|
|
228
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
229
|
-
entry_key TEXT NOT NULL UNIQUE,
|
|
230
|
-
dir_path TEXT NOT NULL,
|
|
231
|
-
file_path TEXT NOT NULL,
|
|
232
|
-
stash_dir TEXT NOT NULL,
|
|
233
|
-
entry_json TEXT NOT NULL,
|
|
234
|
-
search_text TEXT NOT NULL,
|
|
235
|
-
entry_type TEXT NOT NULL,
|
|
236
|
-
derived_from TEXT,
|
|
237
|
-
-- Chunk-5 Step 2 / DB v18 (spec 14.4): bundle-adapter identity + provenance,
|
|
238
|
-
-- ADDITIVE alongside the legacy columns above. item_ref is the durable
|
|
239
|
-
-- <bundle>//<concept-id> spelling; nullable during the transition so a
|
|
240
|
-
-- pre-repoint reader path never trips a NOT NULL on a partially-migrated row.
|
|
241
|
-
item_ref TEXT,
|
|
242
|
-
bundle_id TEXT,
|
|
243
|
-
component_id TEXT,
|
|
244
|
-
concept_id TEXT,
|
|
245
|
-
adapter_id TEXT,
|
|
246
|
-
type TEXT,
|
|
247
|
-
content_hash TEXT,
|
|
248
|
-
document_json TEXT
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
CREATE INDEX IF NOT EXISTS idx_entries_dir ON entries(dir_path);
|
|
252
|
-
CREATE INDEX IF NOT EXISTS idx_entries_type ON entries(entry_type);
|
|
253
|
-
CREATE INDEX IF NOT EXISTS idx_entries_file_path ON entries(file_path);
|
|
254
|
-
`);
|
|
255
|
-
// v18: backfill the bundle-adapter identity/provenance columns on databases
|
|
256
|
-
// created against a pre-v18 binary (partial schema) — same PRAGMA-then-ALTER
|
|
257
|
-
// guard pattern as `ensureDerivedFromColumn`. Runs BEFORE the item_ref index
|
|
258
|
-
// so the CREATE INDEX below never references a not-yet-added column.
|
|
259
|
-
ensureBundleRefColumns(db);
|
|
260
|
-
// v19 (F4c, spec §11.4): item_ref is THE durable identity — its index is
|
|
261
|
-
// UNIQUE. Every indexed row now carries item_ref; SQLite treats NULLs as
|
|
262
|
-
// distinct in a UNIQUE index, so NULL-item_ref write-back stragglers coexist.
|
|
263
|
-
// A pre-v19 DB carries a NON-unique `idx_entries_item_ref`, so drop-then-create.
|
|
264
|
-
ensureUniqueItemRefIndex(db);
|
|
265
|
-
// Phase 5A / DB v17: backfill `derived_from` column + index on databases
|
|
266
|
-
// that were created at v17 fresh OR carry a partial v17 schema (a DB whose
|
|
267
|
-
// `index_meta.version` was bumped to 17 but whose `entries` table still
|
|
268
|
-
// lacks the column — this happens when a previous v17 binary opened a
|
|
269
|
-
// pre-v17 DB without taking the upgrade path because no version mismatch
|
|
270
|
-
// was seen at boot). The PRAGMA-then-ALTER guard runs unconditionally so
|
|
271
|
-
// both fresh and partial schemas converge. The CREATE INDEX for
|
|
272
|
-
// `derived_from` MUST run after this helper so we never reference a
|
|
273
|
-
// column that has not yet been added on partial schemas.
|
|
274
|
-
ensureDerivedFromColumn(db);
|
|
275
|
-
// Validated WorkflowDocument JSON, one row per indexed workflow entry.
|
|
276
|
-
// Pure index data — fully rebuilt on each `akm index`. ON DELETE CASCADE
|
|
277
|
-
// means clearing entries (full rebuild or per-dir delete) drops these too.
|
|
278
|
-
db.exec(`
|
|
279
|
-
CREATE TABLE IF NOT EXISTS workflow_documents (
|
|
280
|
-
entry_id INTEGER PRIMARY KEY REFERENCES entries(id) ON DELETE CASCADE,
|
|
281
|
-
schema_version INTEGER NOT NULL,
|
|
282
|
-
document_json TEXT NOT NULL,
|
|
283
|
-
source_path TEXT NOT NULL,
|
|
284
|
-
source_hash TEXT NOT NULL,
|
|
285
|
-
updated_at TEXT NOT NULL
|
|
286
|
-
);
|
|
287
|
-
|
|
288
|
-
CREATE INDEX IF NOT EXISTS idx_workflow_documents_source_path
|
|
289
|
-
ON workflow_documents(source_path);
|
|
290
|
-
`);
|
|
291
|
-
// Set version immediately after table creation so a crash before the end of
|
|
292
|
-
// ensureSchema() does not leave the database in a versionless state on next open.
|
|
293
|
-
const versionAfterCreate = getMeta(db, "version");
|
|
294
|
-
if (!versionAfterCreate) {
|
|
295
|
-
setMeta(db, "version", String(DB_VERSION));
|
|
296
|
-
}
|
|
201
|
+
rebuildIncompatibleIndexGeneration(db);
|
|
202
|
+
db.exec(CANONICAL_ENTRY_SCHEMA_SQL);
|
|
203
|
+
// Workflow source is compiled directly into source IR at each command
|
|
204
|
+
// boundary. The former workflow_documents cache duplicated that IR in a
|
|
205
|
+
// second persisted representation and was never used by current execution.
|
|
206
|
+
// index.db is derived state, so remove the obsolete table on every open.
|
|
207
|
+
db.exec("DROP TABLE IF EXISTS workflow_documents");
|
|
208
|
+
setMeta(db, "version", String(DB_VERSION));
|
|
297
209
|
// BLOB-based embedding storage (always available, no sqlite-vec needed)
|
|
298
210
|
db.exec(`
|
|
299
211
|
CREATE TABLE IF NOT EXISTS embeddings (
|
|
@@ -317,9 +229,8 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
317
229
|
);
|
|
318
230
|
`);
|
|
319
231
|
}
|
|
320
|
-
// usage_events
|
|
321
|
-
//
|
|
322
|
-
// state.db. utility_scores (a regenerable index.db cache) stays here.
|
|
232
|
+
// usage_events lives in state.db. utility_scores remains a regenerable
|
|
233
|
+
// index.db cache.
|
|
323
234
|
// Utility scores table (aggregated per-entry utility metrics)
|
|
324
235
|
db.exec(`
|
|
325
236
|
CREATE TABLE IF NOT EXISTS utility_scores (
|
|
@@ -360,7 +271,7 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
360
271
|
// result for each asset so that subsequent `akm index --enrich` runs can
|
|
361
272
|
// skip the LLM call when the body hasn't changed. The cache is keyed by
|
|
362
273
|
// a stable asset_ref string (e.g. the absolute file path for graph/memory
|
|
363
|
-
// passes, or `
|
|
274
|
+
// passes, or `itemRef:passId` for the metadata-enhance pass).
|
|
364
275
|
// Entries are cleaned up when assets are removed or --re-enrich is used.
|
|
365
276
|
db.exec(`
|
|
366
277
|
CREATE TABLE IF NOT EXISTS llm_enrichment_cache (
|
|
@@ -389,18 +300,7 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
389
300
|
// body_hash) and declare a composite FK -> graph_files ON DELETE CASCADE so
|
|
390
301
|
// child rows are removed when a graph_files row is replaced.
|
|
391
302
|
//
|
|
392
|
-
// #624-P1 targeted migration: an existing DB may still hold the OLD graph_files
|
|
393
|
-
// (entry_id PK). SQLite can't ALTER a primary key, so we RENAME the 3 graph
|
|
394
|
-
// tables aside (→ *_legacy) here — ONLY the graph tables, never the index/
|
|
395
|
-
// embeddings — then the CREATE block below builds the new shape, then
|
|
396
|
-
// migrateGraphDataFromLegacy() copies the data across so the graph is PRESERVED
|
|
397
|
-
// (not re-extracted).
|
|
398
|
-
migrateGraphFilesSchema(db);
|
|
399
303
|
ensureGraphTables(db);
|
|
400
|
-
// #624-P1 migration step 2: copy any renamed-aside legacy graph data into the
|
|
401
|
-
// new-shape tables (just created above), then drop the legacy tables. No-op
|
|
402
|
-
// unless migrateGraphFilesSchema renamed a legacy graph_files this open.
|
|
403
|
-
migrateGraphDataFromLegacy(db);
|
|
404
304
|
// FTS-dirty queue. Created here (not lazily on first upsert) so the
|
|
405
305
|
// per-entry write path doesn't issue a CREATE TABLE IF NOT EXISTS on
|
|
406
306
|
// every call — that DDL would fire thousands of times during a full
|
|
@@ -410,6 +310,12 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
410
310
|
entry_id INTEGER PRIMARY KEY
|
|
411
311
|
);
|
|
412
312
|
`);
|
|
313
|
+
// If a generation rebuild could not drop a vec0 table while the extension
|
|
314
|
+
// was unavailable, finish that reset as soon as vec0 can be loaded again.
|
|
315
|
+
if (isVecAvailable(db) && getMeta(db, "vecResetPending") === "1") {
|
|
316
|
+
db.exec("DROP TABLE IF EXISTS entries_vec");
|
|
317
|
+
setMeta(db, "vecResetPending", "0");
|
|
318
|
+
}
|
|
413
319
|
// sqlite-vec table
|
|
414
320
|
//
|
|
415
321
|
// Dimension contract:
|
|
@@ -471,86 +377,6 @@ export function ensureSchema(db, embeddingDim) {
|
|
|
471
377
|
// `akm search` does not hit the network on every invocation.
|
|
472
378
|
db.exec(REGISTRY_INDEX_CACHE_DDL);
|
|
473
379
|
}
|
|
474
|
-
/**
|
|
475
|
-
* Phase 5A / DB v17 schema guard.
|
|
476
|
-
*
|
|
477
|
-
* Ensures the `entries.derived_from` column + index exist on the open
|
|
478
|
-
* connection. Called from `ensureSchema()` after the entries CREATE so that
|
|
479
|
-
* legacy databases (created against a pre-v17 binary) still gain the new column
|
|
480
|
-
* without data loss. Idempotent: a `PRAGMA table_info` lookup gates the ALTER.
|
|
481
|
-
*/
|
|
482
|
-
function ensureDerivedFromColumn(db) {
|
|
483
|
-
bestEffort(() => {
|
|
484
|
-
const cols = db.prepare("PRAGMA table_info(entries)").all();
|
|
485
|
-
const hasColumn = cols.some((c) => c.name === "derived_from");
|
|
486
|
-
if (!hasColumn) {
|
|
487
|
-
db.exec("ALTER TABLE entries ADD COLUMN derived_from TEXT");
|
|
488
|
-
}
|
|
489
|
-
// Index creation is idempotent on its own; safe to call unconditionally.
|
|
490
|
-
db.exec("CREATE INDEX IF NOT EXISTS idx_entries_derived_from ON entries(derived_from)");
|
|
491
|
-
}, "entries table may not exist on a brand-new DB before CREATE — caller is responsible");
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* Chunk-5 Step 2 / DB v18 schema guard.
|
|
495
|
-
*
|
|
496
|
-
* Ensures the bundle-adapter identity/provenance columns exist on the open
|
|
497
|
-
* `entries` table. Called from `ensureSchema()` after the entries CREATE so a
|
|
498
|
-
* legacy database (created against a pre-v18 binary) gains the new columns
|
|
499
|
-
* without a rebuild. All columns are nullable and added ADDITIVELY — the
|
|
500
|
-
* writer populates `item_ref`/`bundle_id`/`component_id`/`concept_id`/
|
|
501
|
-
* `adapter_id`/`type` while readers still key on the legacy columns. Idempotent:
|
|
502
|
-
* a `PRAGMA table_info` lookup gates each ALTER.
|
|
503
|
-
*/
|
|
504
|
-
function ensureBundleRefColumns(db) {
|
|
505
|
-
bestEffort(() => {
|
|
506
|
-
const cols = db.prepare("PRAGMA table_info(entries)").all();
|
|
507
|
-
const have = new Set(cols.map((c) => c.name));
|
|
508
|
-
const additive = [
|
|
509
|
-
["item_ref", "TEXT"],
|
|
510
|
-
["bundle_id", "TEXT"],
|
|
511
|
-
["component_id", "TEXT"],
|
|
512
|
-
["concept_id", "TEXT"],
|
|
513
|
-
["adapter_id", "TEXT"],
|
|
514
|
-
["type", "TEXT"],
|
|
515
|
-
["content_hash", "TEXT"],
|
|
516
|
-
["document_json", "TEXT"],
|
|
517
|
-
];
|
|
518
|
-
for (const [name, sqlType] of additive) {
|
|
519
|
-
if (!have.has(name))
|
|
520
|
-
db.exec(`ALTER TABLE entries ADD COLUMN ${name} ${sqlType}`);
|
|
521
|
-
}
|
|
522
|
-
}, "entries table may not exist on a brand-new DB before CREATE — caller is responsible");
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Chunk-5 flip F4c / DB v19 schema guard.
|
|
526
|
-
*
|
|
527
|
-
* Upgrade `entries.item_ref`'s lookup index to UNIQUE (item_ref is now THE
|
|
528
|
-
* durable identity — spec §11.4). A pre-v19 DB has a NON-unique
|
|
529
|
-
* `idx_entries_item_ref`, so we DROP-then-CREATE (a `CREATE UNIQUE INDEX IF NOT
|
|
530
|
-
* EXISTS` under the same name would no-op against the existing non-unique index).
|
|
531
|
-
* SQLite treats NULLs as distinct in a UNIQUE index. Duplicate durable identities
|
|
532
|
-
* are an invalid index and fail the schema open rather than enabling a dual-key
|
|
533
|
-
* fallback.
|
|
534
|
-
*/
|
|
535
|
-
function ensureUniqueItemRefIndex(db) {
|
|
536
|
-
// Probe before mutating. This ran unconditionally on EVERY open as two
|
|
537
|
-
// separate autocommit statements, so there was always a window in which the
|
|
538
|
-
// index did not exist — a concurrent open (registry-cache search, indexer,
|
|
539
|
-
// improve) could DROP between the other's DROP and CREATE and then fail with
|
|
540
|
-
// "index idx_entries_item_ref already exists", or serve a query with no index
|
|
541
|
-
// at all. A DB whose index is already UNIQUE needs no work.
|
|
542
|
-
const existing = db
|
|
543
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type = 'index' AND name = 'idx_entries_item_ref'")
|
|
544
|
-
.get();
|
|
545
|
-
if (existing?.sql && /\bUNIQUE\b/i.test(existing.sql))
|
|
546
|
-
return;
|
|
547
|
-
// Pre-v19 (non-unique index) or absent: convert atomically so a racing open
|
|
548
|
-
// sees either the old index or the new one, never neither.
|
|
549
|
-
db.transaction(() => {
|
|
550
|
-
db.exec("DROP INDEX IF EXISTS idx_entries_item_ref");
|
|
551
|
-
db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_entries_item_ref ON entries(item_ref)");
|
|
552
|
-
})();
|
|
553
|
-
}
|
|
554
380
|
/**
|
|
555
381
|
* Returns true when a table exists in the current database.
|
|
556
382
|
*/
|
|
@@ -558,100 +384,3 @@ function tableExists(db, name) {
|
|
|
558
384
|
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name=? LIMIT 1").get(name);
|
|
559
385
|
return row !== undefined && row !== null;
|
|
560
386
|
}
|
|
561
|
-
/**
|
|
562
|
-
* #624-P1 targeted graph-schema migration — STEP 1 of 2 (rename).
|
|
563
|
-
*
|
|
564
|
-
* graph_files was re-keyed from `entry_id INTEGER PRIMARY KEY REFERENCES
|
|
565
|
-
* entries(id)` to a self-contained `(stash_root, file_path, body_hash)` PK.
|
|
566
|
-
* SQLite cannot ALTER a primary key, so an existing DB carrying the OLD shape
|
|
567
|
-
* has its 3 graph tables RENAMED to `*_legacy` here; ensureSchema's CREATE block
|
|
568
|
-
* then builds the new-shape tables, and {@link migrateGraphDataFromLegacy} COPIES
|
|
569
|
-
* the data across before dropping the legacy tables. The graph is preserved —
|
|
570
|
-
* NOT re-extracted (re-extraction is ~19s/file of LLM work).
|
|
571
|
-
*
|
|
572
|
-
* Crucially this is GRAPH-SCOPED: it touches ONLY the graph tables, never the
|
|
573
|
-
* index / embeddings / enrichment cache. So users keep their (expensive)
|
|
574
|
-
* embeddings instead of being forced into a full re-embed by a DB_VERSION bump.
|
|
575
|
-
*
|
|
576
|
-
* Detection: the old schema has an `entry_id` column on graph_files. Fresh DBs
|
|
577
|
-
* (no graph_files yet) and already-migrated DBs (no entry_id column) are no-ops.
|
|
578
|
-
* Idempotent.
|
|
579
|
-
*/
|
|
580
|
-
function migrateGraphFilesSchema(db) {
|
|
581
|
-
bestEffort(() => {
|
|
582
|
-
const cols = db.prepare("PRAGMA table_info(graph_files)").all();
|
|
583
|
-
const isLegacyShape = cols.some((c) => c.name === "entry_id");
|
|
584
|
-
if (!isLegacyShape)
|
|
585
|
-
return;
|
|
586
|
-
// A previous interrupted migration may have left *_legacy behind — drop those
|
|
587
|
-
// husks first so the rename below doesn't collide.
|
|
588
|
-
db.exec("DROP TABLE IF EXISTS graph_file_relations_legacy");
|
|
589
|
-
db.exec("DROP TABLE IF EXISTS graph_file_entities_legacy");
|
|
590
|
-
db.exec("DROP TABLE IF EXISTS graph_files_legacy");
|
|
591
|
-
// Rename the 3 entry_id-keyed tables aside. graph_meta is unchanged (stash_root
|
|
592
|
-
// key) so it is left in place. ALTER … RENAME auto-updates child FK refs in
|
|
593
|
-
// SQLite ≥3.25, which is fine — the legacy children are dropped after the copy.
|
|
594
|
-
db.exec("ALTER TABLE graph_files RENAME TO graph_files_legacy");
|
|
595
|
-
if (tableExists(db, "graph_file_entities")) {
|
|
596
|
-
db.exec("ALTER TABLE graph_file_entities RENAME TO graph_file_entities_legacy");
|
|
597
|
-
}
|
|
598
|
-
if (tableExists(db, "graph_file_relations")) {
|
|
599
|
-
db.exec("ALTER TABLE graph_file_relations RENAME TO graph_file_relations_legacy");
|
|
600
|
-
}
|
|
601
|
-
}, "graph_files may not exist on a brand-new DB before CREATE — caller is responsible");
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* #624-P1 targeted graph-schema migration — STEP 2 of 2 (copy + drop legacy).
|
|
605
|
-
*
|
|
606
|
-
* Runs AFTER the graph CREATE TABLE block, so the new-shape tables exist. Copies
|
|
607
|
-
* every legacy row into the re-keyed tables — the old tables already carry
|
|
608
|
-
* (stash_root, file_path, body_hash) next to entry_id, so the projection is a
|
|
609
|
-
* straight column copy (children JOIN back to graph_files_legacy to resolve the
|
|
610
|
-
* composite key from their entry_id). Then drops the `*_legacy` tables.
|
|
611
|
-
*
|
|
612
|
-
* Best-effort: a copy failure (e.g. a pre-body_hash legacy schema) is tolerated,
|
|
613
|
-
* and the legacy tables are dropped regardless so they never linger. Rows whose
|
|
614
|
-
* body_hash is null/empty can't form the new PK and are skipped (they re-extract).
|
|
615
|
-
*/
|
|
616
|
-
function migrateGraphDataFromLegacy(db) {
|
|
617
|
-
if (!tableExists(db, "graph_files_legacy"))
|
|
618
|
-
return;
|
|
619
|
-
let migratedFiles = 0;
|
|
620
|
-
bestEffort(() => {
|
|
621
|
-
db.transaction(() => {
|
|
622
|
-
const res = db
|
|
623
|
-
.prepare(`INSERT OR IGNORE INTO graph_files
|
|
624
|
-
(stash_root, file_path, body_hash, file_order, file_type, confidence, status, reason, extraction_run_id)
|
|
625
|
-
SELECT stash_root, file_path, body_hash, file_order, file_type, confidence, status, reason, extraction_run_id
|
|
626
|
-
FROM graph_files_legacy
|
|
627
|
-
WHERE body_hash IS NOT NULL AND body_hash != ''`)
|
|
628
|
-
.run();
|
|
629
|
-
migratedFiles = Number(res.changes);
|
|
630
|
-
if (tableExists(db, "graph_file_entities_legacy")) {
|
|
631
|
-
db.exec(`INSERT OR IGNORE INTO graph_file_entities
|
|
632
|
-
(stash_root, file_path, body_hash, entity_order, entity_norm, entity)
|
|
633
|
-
SELECT gf.stash_root, gf.file_path, gf.body_hash, e.entity_order, e.entity_norm, e.entity
|
|
634
|
-
FROM graph_file_entities_legacy e
|
|
635
|
-
JOIN graph_files_legacy gf ON gf.entry_id = e.entry_id
|
|
636
|
-
WHERE gf.body_hash IS NOT NULL AND gf.body_hash != ''`);
|
|
637
|
-
}
|
|
638
|
-
if (tableExists(db, "graph_file_relations_legacy")) {
|
|
639
|
-
db.exec(`INSERT OR IGNORE INTO graph_file_relations
|
|
640
|
-
(stash_root, file_path, body_hash, relation_order, from_entity_norm, from_entity, to_entity_norm, to_entity, relation_type, confidence)
|
|
641
|
-
SELECT gf.stash_root, gf.file_path, gf.body_hash, r.relation_order, r.from_entity_norm, r.from_entity, r.to_entity_norm, r.to_entity, r.relation_type, r.confidence
|
|
642
|
-
FROM graph_file_relations_legacy r
|
|
643
|
-
JOIN graph_files_legacy gf ON gf.entry_id = r.entry_id
|
|
644
|
-
WHERE gf.body_hash IS NOT NULL AND gf.body_hash != ''`);
|
|
645
|
-
}
|
|
646
|
-
})();
|
|
647
|
-
}, "graph data migration is best-effort; legacy tables are dropped regardless below");
|
|
648
|
-
// Always drop the legacy tables (children first), migrated or not.
|
|
649
|
-
bestEffort(() => {
|
|
650
|
-
db.exec("DROP TABLE IF EXISTS graph_file_relations_legacy");
|
|
651
|
-
db.exec("DROP TABLE IF EXISTS graph_file_entities_legacy");
|
|
652
|
-
db.exec("DROP TABLE IF EXISTS graph_files_legacy");
|
|
653
|
-
}, "drop legacy graph tables after migration");
|
|
654
|
-
if (migratedFiles > 0) {
|
|
655
|
-
warn(`[akm] graph index re-keyed (#624): migrated ${migratedFiles} extracted file(s) to the new schema — no re-extraction needed. Index + embeddings untouched.`);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* retrieval-frequency counting over `usage_events`. The bounded-step EMA policy
|
|
9
9
|
* itself lives in `indexer/feedback/utility-policy`; this repo only reads/writes.
|
|
10
10
|
*/
|
|
11
|
-
import path from "node:path";
|
|
12
11
|
import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
|
|
13
12
|
import { computeNextUtility } from "../../indexer/feedback/utility-policy.js";
|
|
14
13
|
import { SQLITE_CHUNK_SIZE } from "./index-sql.js";
|
|
@@ -145,7 +144,7 @@ function bareRefCandidates(ref) {
|
|
|
145
144
|
export function getRetrievalCounts(indexDb, stateDb, refs, options = {}) {
|
|
146
145
|
if (refs.length === 0)
|
|
147
146
|
return new Map();
|
|
148
|
-
if (options.sourceName
|
|
147
|
+
if (options.sourceName) {
|
|
149
148
|
return getSourceScopedRetrievalCounts(indexDb, stateDb, refs, options);
|
|
150
149
|
}
|
|
151
150
|
// Map each conceptId back to the input refs that produced it so DB results
|
|
@@ -218,20 +217,18 @@ function getSourceScopedRetrievalCounts(indexDb, stateDb, refs, options) {
|
|
|
218
217
|
bareToInputs.set(bare, [ref]);
|
|
219
218
|
}
|
|
220
219
|
}
|
|
221
|
-
// Cross-DB
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const entryStashDir = indexDb.prepare("SELECT stash_dir FROM entries WHERE id = ?");
|
|
226
|
-
const stashDirFor = (entryId) => {
|
|
220
|
+
// Cross-DB: usage rows come from state.db; resolve the linked entry's
|
|
221
|
+
// canonical bundle identity from index.db by entry_id.
|
|
222
|
+
const entryBundle = indexDb.prepare("SELECT bundle_id FROM entries WHERE id = ?");
|
|
223
|
+
const bundleFor = (entryId) => {
|
|
227
224
|
if (entryId === null)
|
|
228
225
|
return null;
|
|
229
|
-
const row =
|
|
230
|
-
return row?.
|
|
226
|
+
const row = entryBundle.get(entryId);
|
|
227
|
+
return row?.bundle_id ?? null;
|
|
231
228
|
};
|
|
232
229
|
const countsByBare = new Map();
|
|
233
230
|
const bareForms = [...bareToInputs.keys()];
|
|
234
|
-
const
|
|
231
|
+
const selectedBundle = options.sourceName;
|
|
235
232
|
for (let i = 0; i < bareForms.length; i += SQLITE_CHUNK_SIZE) {
|
|
236
233
|
const chunk = bareForms.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
237
234
|
const placeholders = chunk.map(() => "?").join(", ");
|
|
@@ -248,15 +245,13 @@ function getSourceScopedRetrievalCounts(indexDb, stateDb, refs, options) {
|
|
|
248
245
|
ELSE ue.entry_ref
|
|
249
246
|
END IN (${placeholders})`)
|
|
250
247
|
.all(...chunk);
|
|
251
|
-
const rows = rawRows.map((r) => ({ ...r,
|
|
248
|
+
const rows = rawRows.map((r) => ({ ...r, bundle_id: bundleFor(r.entry_id) }));
|
|
252
249
|
for (const row of rows) {
|
|
253
250
|
const bare = bareRef(row.entry_ref);
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
: false;
|
|
257
|
-
const detached = row.entry_id === null || selectedRoot === undefined;
|
|
251
|
+
const linkedToSelectedBundle = row.entry_id !== null && row.bundle_id === selectedBundle;
|
|
252
|
+
const detached = row.entry_id === null;
|
|
258
253
|
const qualifiedForSource = detached && options.sourceName !== undefined && row.entry_ref === `${options.sourceName}//${bare}`;
|
|
259
|
-
if (!
|
|
254
|
+
if (!linkedToSelectedBundle && !qualifiedForSource)
|
|
260
255
|
continue;
|
|
261
256
|
countsByBare.set(bare, (countsByBare.get(bare) ?? 0) + 1);
|
|
262
257
|
}
|
|
@@ -277,7 +277,7 @@ function searchBlobVec(db, queryEmbedding, k) {
|
|
|
277
277
|
export function getAllEntriesForEmbedding(db) {
|
|
278
278
|
return db
|
|
279
279
|
.prepare(`
|
|
280
|
-
SELECT e.id, e.search_text AS searchText, e.
|
|
280
|
+
SELECT e.id, e.search_text AS searchText, e.item_ref AS itemRef, e.file_path AS filePath FROM entries e
|
|
281
281
|
WHERE NOT EXISTS (SELECT 1 FROM embeddings b WHERE b.id = e.id)
|
|
282
282
|
`)
|
|
283
283
|
.all();
|