akm-cli 0.9.1 → 0.9.2-alpha.2
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 +103 -28
- 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/stash-skeleton/facts/conventions/backlinks.md +3 -4
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
- 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 +5 -6
- 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-prompt.js +64 -22
- package/dist/commands/improve/extract.js +608 -360
- 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 +53 -22
- 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 +901 -177
- 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 +85 -35
- 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 +23 -26
- package/dist/core/config/schema/engines.js +8 -7
- package/dist/core/config/schema/improve-processes.js +29 -5
- package/dist/core/config/schema/index-config.js +0 -27
- 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 +78 -39
- package/dist/indexer/indexer.js +471 -432
- package/dist/indexer/installations.js +6 -0
- package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
- package/dist/indexer/materialize-embeddings.js +155 -0
- package/dist/indexer/passes/memory-inference.js +227 -174
- package/dist/indexer/passes/metadata.js +263 -118
- package/dist/indexer/scan/doc-to-entry.js +7 -10
- package/dist/indexer/scan/drain-dir.js +51 -23
- package/dist/indexer/search/db-search.js +156 -50
- package/dist/indexer/search/fts-query.js +40 -40
- package/dist/indexer/search/ranking.js +36 -1
- package/dist/indexer/search/search-attribution.js +3 -1
- package/dist/indexer/search/search-fields.js +23 -14
- 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 +31 -33
- 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 +19334 -52269
- package/dist/scripts/akm-migrate.js +19270 -51612
- 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 +203 -229
- 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 +64 -71
- 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 +74 -350
- package/dist/storage/repositories/index-utility-repository.js +12 -17
- package/dist/storage/repositories/index-vec-repository.js +56 -7
- 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 +159 -36
- 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 -224
- 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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Centralizes the one canonical `entries` SELECT column list and the
|
|
8
8
|
* JSON-parse-guarded row → {@link DbIndexedEntry} mapping that several queries
|
|
9
|
-
* used to reimplement. Corrupt `
|
|
9
|
+
* used to reimplement. Corrupt `document_json` rows are skipped (warn once) rather
|
|
10
10
|
* than crashing the caller.
|
|
11
11
|
*
|
|
12
12
|
* Relocated from `src/indexer/db/entry-mapper.ts` (WI-5a): it now imports the
|
|
@@ -23,36 +23,32 @@ import { warn } from "../../core/warn.js";
|
|
|
23
23
|
* Durable identity columns are surfaced here so every mapped entry carries
|
|
24
24
|
* current indexed provenance.
|
|
25
25
|
*/
|
|
26
|
-
export const ENTRY_COLUMNS = "id,
|
|
26
|
+
export const ENTRY_COLUMNS = "id, item_ref, bundle_id, component_id, concept_id, adapter_id, type, file_path, content_hash, document_json, search_text";
|
|
27
27
|
/**
|
|
28
|
-
* Map one raw `entries` row to a {@link DbIndexedEntry}, parsing `
|
|
28
|
+
* Map one raw `entries` row to a {@link DbIndexedEntry}, parsing `document_json`.
|
|
29
29
|
* Returns `null` (and warns, tagged with `context`) when the JSON is corrupt so
|
|
30
30
|
* callers can skip the row instead of crashing.
|
|
31
31
|
*/
|
|
32
32
|
export function rowToIndexedEntry(row, context) {
|
|
33
33
|
let entry;
|
|
34
34
|
try {
|
|
35
|
-
entry = JSON.parse(row.
|
|
35
|
+
entry = JSON.parse(row.document_json);
|
|
36
36
|
}
|
|
37
37
|
catch {
|
|
38
|
-
warn(`[db] ${context}: skipping entry id=${row.id} — corrupt
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
if (!row.item_ref || !row.concept_id || !row.bundle_id || !row.adapter_id) {
|
|
42
|
-
warn(`[db] ${context}: skipping entry id=${row.id} — missing indexed provenance`);
|
|
38
|
+
warn(`[db] ${context}: skipping entry id=${row.id} — corrupt document_json`);
|
|
43
39
|
return null;
|
|
44
40
|
}
|
|
45
41
|
return {
|
|
46
42
|
id: row.id,
|
|
47
|
-
entryKey: row.entry_key,
|
|
48
|
-
dirPath: row.dir_path,
|
|
49
43
|
filePath: row.file_path,
|
|
50
|
-
stashDir: row.stash_dir,
|
|
51
44
|
entry,
|
|
52
45
|
searchText: row.search_text,
|
|
53
46
|
itemRef: row.item_ref,
|
|
54
47
|
conceptId: row.concept_id,
|
|
55
48
|
bundleId: row.bundle_id,
|
|
49
|
+
componentId: row.component_id,
|
|
56
50
|
adapterId: row.adapter_id,
|
|
51
|
+
type: row.type,
|
|
52
|
+
...(row.content_hash ? { contentHash: row.content_hash } : {}),
|
|
57
53
|
};
|
|
58
54
|
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* The single canonical contract for the derived `entries` generation.
|
|
6
|
+
*
|
|
7
|
+
* `index.db` is regenerable, so callers compare one normalized PRAGMA
|
|
8
|
+
* fingerprint and discard any generation that differs. This module owns both
|
|
9
|
+
* the DDL and its expected fingerprint so schema creation, writable opens,
|
|
10
|
+
* serving preflights, and read-only evaluator tooling cannot drift into
|
|
11
|
+
* separate definitions of "current".
|
|
12
|
+
*/
|
|
13
|
+
export const CANONICAL_INDEX_DB_VERSION = 22;
|
|
14
|
+
export const CANONICAL_ENTRY_SCHEMA_SQL = `
|
|
15
|
+
CREATE TABLE IF NOT EXISTS entries (
|
|
16
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
17
|
+
item_ref TEXT NOT NULL UNIQUE,
|
|
18
|
+
bundle_id TEXT NOT NULL,
|
|
19
|
+
component_id TEXT NOT NULL,
|
|
20
|
+
concept_id TEXT NOT NULL,
|
|
21
|
+
adapter_id TEXT NOT NULL,
|
|
22
|
+
type TEXT NOT NULL,
|
|
23
|
+
file_path TEXT NOT NULL,
|
|
24
|
+
content_hash TEXT,
|
|
25
|
+
document_json TEXT NOT NULL,
|
|
26
|
+
search_text TEXT NOT NULL,
|
|
27
|
+
derived_from TEXT
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_entries_bundle ON entries(bundle_id);
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_entries_type ON entries(type);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_entries_file_path ON entries(file_path);
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_entries_derived_from ON entries(derived_from);
|
|
34
|
+
`;
|
|
35
|
+
const CANONICAL_ENTRY_SCHEMA_FINGERPRINT = {
|
|
36
|
+
tableSql: "CREATE TABLE entries ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_ref TEXT NOT NULL UNIQUE, bundle_id TEXT NOT NULL, component_id TEXT NOT NULL, concept_id TEXT NOT NULL, adapter_id TEXT NOT NULL, type TEXT NOT NULL, file_path TEXT NOT NULL, content_hash TEXT, document_json TEXT NOT NULL, search_text TEXT NOT NULL, derived_from TEXT )",
|
|
37
|
+
sqliteSequenceTable: true,
|
|
38
|
+
sqliteSequenceValid: true,
|
|
39
|
+
columns: [
|
|
40
|
+
{ cid: 0, name: "id", type: "INTEGER", notNull: 0, defaultValue: null, primaryKeyPosition: 1, hidden: 0 },
|
|
41
|
+
{
|
|
42
|
+
cid: 1,
|
|
43
|
+
name: "item_ref",
|
|
44
|
+
type: "TEXT",
|
|
45
|
+
notNull: 1,
|
|
46
|
+
defaultValue: null,
|
|
47
|
+
primaryKeyPosition: 0,
|
|
48
|
+
hidden: 0,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
cid: 2,
|
|
52
|
+
name: "bundle_id",
|
|
53
|
+
type: "TEXT",
|
|
54
|
+
notNull: 1,
|
|
55
|
+
defaultValue: null,
|
|
56
|
+
primaryKeyPosition: 0,
|
|
57
|
+
hidden: 0,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
cid: 3,
|
|
61
|
+
name: "component_id",
|
|
62
|
+
type: "TEXT",
|
|
63
|
+
notNull: 1,
|
|
64
|
+
defaultValue: null,
|
|
65
|
+
primaryKeyPosition: 0,
|
|
66
|
+
hidden: 0,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
cid: 4,
|
|
70
|
+
name: "concept_id",
|
|
71
|
+
type: "TEXT",
|
|
72
|
+
notNull: 1,
|
|
73
|
+
defaultValue: null,
|
|
74
|
+
primaryKeyPosition: 0,
|
|
75
|
+
hidden: 0,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
cid: 5,
|
|
79
|
+
name: "adapter_id",
|
|
80
|
+
type: "TEXT",
|
|
81
|
+
notNull: 1,
|
|
82
|
+
defaultValue: null,
|
|
83
|
+
primaryKeyPosition: 0,
|
|
84
|
+
hidden: 0,
|
|
85
|
+
},
|
|
86
|
+
{ cid: 6, name: "type", type: "TEXT", notNull: 1, defaultValue: null, primaryKeyPosition: 0, hidden: 0 },
|
|
87
|
+
{
|
|
88
|
+
cid: 7,
|
|
89
|
+
name: "file_path",
|
|
90
|
+
type: "TEXT",
|
|
91
|
+
notNull: 1,
|
|
92
|
+
defaultValue: null,
|
|
93
|
+
primaryKeyPosition: 0,
|
|
94
|
+
hidden: 0,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
cid: 8,
|
|
98
|
+
name: "content_hash",
|
|
99
|
+
type: "TEXT",
|
|
100
|
+
notNull: 0,
|
|
101
|
+
defaultValue: null,
|
|
102
|
+
primaryKeyPosition: 0,
|
|
103
|
+
hidden: 0,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
cid: 9,
|
|
107
|
+
name: "document_json",
|
|
108
|
+
type: "TEXT",
|
|
109
|
+
notNull: 1,
|
|
110
|
+
defaultValue: null,
|
|
111
|
+
primaryKeyPosition: 0,
|
|
112
|
+
hidden: 0,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
cid: 10,
|
|
116
|
+
name: "search_text",
|
|
117
|
+
type: "TEXT",
|
|
118
|
+
notNull: 1,
|
|
119
|
+
defaultValue: null,
|
|
120
|
+
primaryKeyPosition: 0,
|
|
121
|
+
hidden: 0,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
cid: 11,
|
|
125
|
+
name: "derived_from",
|
|
126
|
+
type: "TEXT",
|
|
127
|
+
notNull: 0,
|
|
128
|
+
defaultValue: null,
|
|
129
|
+
primaryKeyPosition: 0,
|
|
130
|
+
hidden: 0,
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
indexes: [
|
|
134
|
+
{
|
|
135
|
+
name: "idx_entries_bundle",
|
|
136
|
+
unique: 0,
|
|
137
|
+
origin: "c",
|
|
138
|
+
partial: 0,
|
|
139
|
+
columns: [
|
|
140
|
+
{ sequence: 0, cid: 2, name: "bundle_id", descending: 0, collation: "BINARY", key: 1 },
|
|
141
|
+
{ sequence: 1, cid: -1, name: null, descending: 0, collation: "BINARY", key: 0 },
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: "idx_entries_derived_from",
|
|
146
|
+
unique: 0,
|
|
147
|
+
origin: "c",
|
|
148
|
+
partial: 0,
|
|
149
|
+
columns: [
|
|
150
|
+
{ sequence: 0, cid: 11, name: "derived_from", descending: 0, collation: "BINARY", key: 1 },
|
|
151
|
+
{ sequence: 1, cid: -1, name: null, descending: 0, collation: "BINARY", key: 0 },
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "idx_entries_file_path",
|
|
156
|
+
unique: 0,
|
|
157
|
+
origin: "c",
|
|
158
|
+
partial: 0,
|
|
159
|
+
columns: [
|
|
160
|
+
{ sequence: 0, cid: 7, name: "file_path", descending: 0, collation: "BINARY", key: 1 },
|
|
161
|
+
{ sequence: 1, cid: -1, name: null, descending: 0, collation: "BINARY", key: 0 },
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: "idx_entries_type",
|
|
166
|
+
unique: 0,
|
|
167
|
+
origin: "c",
|
|
168
|
+
partial: 0,
|
|
169
|
+
columns: [
|
|
170
|
+
{ sequence: 0, cid: 6, name: "type", descending: 0, collation: "BINARY", key: 1 },
|
|
171
|
+
{ sequence: 1, cid: -1, name: null, descending: 0, collation: "BINARY", key: 0 },
|
|
172
|
+
],
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: "sqlite_autoindex_entries_1",
|
|
176
|
+
unique: 1,
|
|
177
|
+
origin: "u",
|
|
178
|
+
partial: 0,
|
|
179
|
+
columns: [
|
|
180
|
+
{ sequence: 0, cid: 1, name: "item_ref", descending: 0, collation: "BINARY", key: 1 },
|
|
181
|
+
{ sequence: 1, cid: -1, name: null, descending: 0, collation: "BINARY", key: 0 },
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
};
|
|
186
|
+
function sqlString(value) {
|
|
187
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
188
|
+
}
|
|
189
|
+
function normalizeSchemaSql(value) {
|
|
190
|
+
if (value == null)
|
|
191
|
+
return null;
|
|
192
|
+
return value.replace(/\s+/g, " ").trim();
|
|
193
|
+
}
|
|
194
|
+
export function readEntrySchemaFingerprint(db) {
|
|
195
|
+
const tableRow = db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'entries'").get();
|
|
196
|
+
const sqliteSequenceTable = db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = 'sqlite_sequence'").get() !=
|
|
197
|
+
null;
|
|
198
|
+
const maxId = Number(db.prepare("SELECT COALESCE(MAX(id), 0) AS maxId FROM entries").get().maxId);
|
|
199
|
+
const sequenceRow = sqliteSequenceTable
|
|
200
|
+
? db.prepare("SELECT seq FROM sqlite_sequence WHERE name = 'entries'").get()
|
|
201
|
+
: undefined;
|
|
202
|
+
const sqliteSequenceValid = sqliteSequenceTable &&
|
|
203
|
+
(maxId === 0 ? sequenceRow == null || Number(sequenceRow.seq) >= 0 : Number(sequenceRow?.seq) >= maxId);
|
|
204
|
+
const columns = db.prepare("PRAGMA table_xinfo(entries)").all().map((column) => ({
|
|
205
|
+
cid: Number(column.cid),
|
|
206
|
+
name: column.name,
|
|
207
|
+
type: column.type.trim().toUpperCase(),
|
|
208
|
+
notNull: Number(column.notnull),
|
|
209
|
+
defaultValue: column.dflt_value === null ? null : String(column.dflt_value),
|
|
210
|
+
primaryKeyPosition: Number(column.pk),
|
|
211
|
+
hidden: Number(column.hidden),
|
|
212
|
+
}));
|
|
213
|
+
const indexes = db.prepare("PRAGMA index_list(entries)").all()
|
|
214
|
+
.map((index) => ({
|
|
215
|
+
name: index.name,
|
|
216
|
+
unique: Number(index.unique),
|
|
217
|
+
origin: index.origin,
|
|
218
|
+
partial: Number(index.partial),
|
|
219
|
+
columns: db.prepare(`PRAGMA index_xinfo(${sqlString(index.name)})`).all()
|
|
220
|
+
.sort((left, right) => Number(left.seqno) - Number(right.seqno))
|
|
221
|
+
.map((column) => ({
|
|
222
|
+
sequence: Number(column.seqno),
|
|
223
|
+
cid: Number(column.cid),
|
|
224
|
+
name: column.name,
|
|
225
|
+
descending: Number(column.desc),
|
|
226
|
+
collation: column.coll,
|
|
227
|
+
key: Number(column.key),
|
|
228
|
+
})),
|
|
229
|
+
}))
|
|
230
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
231
|
+
return {
|
|
232
|
+
tableSql: normalizeSchemaSql(tableRow?.sql),
|
|
233
|
+
sqliteSequenceTable,
|
|
234
|
+
sqliteSequenceValid,
|
|
235
|
+
columns,
|
|
236
|
+
indexes,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
export function hasCanonicalEntrySchema(db) {
|
|
240
|
+
try {
|
|
241
|
+
return JSON.stringify(readEntrySchemaFingerprint(db)) === JSON.stringify(CANONICAL_ENTRY_SCHEMA_FINGERPRINT);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
export function isCanonicalIndexGeneration(db) {
|
|
248
|
+
try {
|
|
249
|
+
const row = db.prepare("SELECT value FROM index_meta WHERE key = 'version'").get();
|
|
250
|
+
return row?.value === String(CANONICAL_INDEX_DB_VERSION) && hasCanonicalEntrySchema(db);
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -2,39 +2,69 @@
|
|
|
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` FTS5 search +
|
|
5
|
+
* `index.db` FTS5 search + materialization repository.
|
|
6
6
|
*
|
|
7
|
-
* Owns the `entries_fts` full-text query path and the
|
|
8
|
-
* rebuild.
|
|
7
|
+
* Owns the `entries_fts` full-text query path, per-entry projections, and the
|
|
8
|
+
* explicit full recovery rebuild.
|
|
9
9
|
*/
|
|
10
10
|
import { warn } from "../../core/warn.js";
|
|
11
|
-
import {
|
|
11
|
+
import { buildLexicalQueryPlan } from "../../indexer/search/fts-query.js";
|
|
12
12
|
import { buildSearchFields } from "../../indexer/search/search-fields.js";
|
|
13
13
|
import { SQLITE_CHUNK_SIZE } from "./index-sql.js";
|
|
14
|
+
const INSERT_FTS_SQL = "INSERT INTO entries_fts (entry_id, name, description, tags, hints, content) VALUES (?, ?, ?, ?, ?, ?)";
|
|
15
|
+
const ftsMutationStatementsByDb = new WeakMap();
|
|
16
|
+
function getFtsMutationStatements(db) {
|
|
17
|
+
const existing = ftsMutationStatementsByDb.get(db);
|
|
18
|
+
if (existing)
|
|
19
|
+
return existing;
|
|
20
|
+
const statements = {
|
|
21
|
+
deleteOne: db.prepare("DELETE FROM entries_fts WHERE entry_id = ?"),
|
|
22
|
+
insert: db.prepare(INSERT_FTS_SQL),
|
|
23
|
+
};
|
|
24
|
+
ftsMutationStatementsByDb.set(db, statements);
|
|
25
|
+
return statements;
|
|
26
|
+
}
|
|
27
|
+
/** Replace one entry's derived FTS projection inside the caller's transaction. */
|
|
28
|
+
export function replaceFtsEntry(db, entryId, entry) {
|
|
29
|
+
const fields = buildSearchFields(entry);
|
|
30
|
+
const statements = getFtsMutationStatements(db);
|
|
31
|
+
statements.deleteOne.run(entryId);
|
|
32
|
+
statements.insert.run(entryId, fields.name, fields.description, fields.tags, fields.hints, fields.content);
|
|
33
|
+
}
|
|
34
|
+
/** Delete derived FTS projections for canonical entries that are being removed. */
|
|
35
|
+
export function deleteFtsEntries(db, entryIds) {
|
|
36
|
+
for (let i = 0; i < entryIds.length; i += SQLITE_CHUNK_SIZE) {
|
|
37
|
+
const chunk = entryIds.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
38
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
39
|
+
db.prepare(`DELETE FROM entries_fts WHERE entry_id IN (${placeholders})`).run(...chunk);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
14
42
|
export function searchFts(db, query, limit, entryType, excludeTypes) {
|
|
15
|
-
const
|
|
16
|
-
if (!
|
|
43
|
+
const plan = buildLexicalQueryPlan(query);
|
|
44
|
+
if (!plan.exact)
|
|
17
45
|
return [];
|
|
18
46
|
// Try the exact AND query first
|
|
19
|
-
const exactResults = runFtsQuery(db,
|
|
47
|
+
const exactResults = runFtsQuery(db, plan.exact, "exact", limit, entryType, excludeTypes);
|
|
20
48
|
if (exactResults.length > 0)
|
|
21
49
|
return exactResults;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
50
|
+
if (plan.exactPrefix) {
|
|
51
|
+
const prefixResults = runFtsQuery(db, plan.exactPrefix, "prefix", limit, entryType, excludeTypes);
|
|
52
|
+
if (prefixResults.length > 0)
|
|
53
|
+
return prefixResults;
|
|
54
|
+
}
|
|
55
|
+
// One measured relaxation only after both conjunctive forms miss. This is
|
|
56
|
+
// still the same FTS table, BM25 weights, candidate collection, and
|
|
57
|
+
// downstream ranker — merely an OR candidate query for sentence-shaped
|
|
58
|
+
// input whose filler terms prevented a strict hit.
|
|
59
|
+
return plan.relaxed ? runFtsQuery(db, plan.relaxed, "relaxed", limit, entryType, excludeTypes) : [];
|
|
30
60
|
}
|
|
31
|
-
function runFtsQuery(db, ftsQuery, limit, entryType, excludeTypes) {
|
|
61
|
+
function runFtsQuery(db, ftsQuery, lexicalMatch, limit, entryType, excludeTypes) {
|
|
32
62
|
// #627 — exclude-type clause. Only applies on the untyped ('any') path; an
|
|
33
63
|
// explicit include filter (entryType) already narrows to a single type, so
|
|
34
64
|
// exclusion is redundant there. An empty list skips the clause entirely
|
|
35
65
|
// (never emit `NOT IN ()`, which is a SQL error / always-false).
|
|
36
66
|
const excludes = excludeTypes && excludeTypes.length > 0 ? excludeTypes : [];
|
|
37
|
-
// The typed and untyped paths differ
|
|
67
|
+
// The typed and untyped paths differ only by one `type` WHERE clause
|
|
38
68
|
// equality vs. an optional NOT IN exclusion) and their param order — the
|
|
39
69
|
// SELECT/JOIN/ORDER/LIMIT is shared, so build it once. Join on integer
|
|
40
70
|
// entry_id directly (no CAST; we store integer). bm25() per-column weights:
|
|
@@ -42,16 +72,16 @@ function runFtsQuery(db, ftsQuery, limit, entryType, excludeTypes) {
|
|
|
42
72
|
let filterClause;
|
|
43
73
|
let params;
|
|
44
74
|
if (entryType && entryType !== "any") {
|
|
45
|
-
filterClause = "AND e.
|
|
75
|
+
filterClause = "AND e.type = ?";
|
|
46
76
|
params = [ftsQuery, entryType, limit];
|
|
47
77
|
}
|
|
48
78
|
else {
|
|
49
|
-
filterClause = excludes.length > 0 ? `AND e.
|
|
79
|
+
filterClause = excludes.length > 0 ? `AND e.type NOT IN (${excludes.map(() => "?").join(", ")})` : "";
|
|
50
80
|
// Param order: MATCH, then the NOT IN values, then LIMIT.
|
|
51
81
|
params = [ftsQuery, ...excludes, limit];
|
|
52
82
|
}
|
|
53
83
|
const sql = `
|
|
54
|
-
SELECT e.id, e.file_path AS filePath, e.
|
|
84
|
+
SELECT e.id, e.file_path AS filePath, e.document_json AS documentJson, e.search_text AS searchText,
|
|
55
85
|
e.item_ref AS itemRef, e.bundle_id AS bundleId, e.concept_id AS conceptId, e.adapter_id AS adapterId,
|
|
56
86
|
bm25(entries_fts, 0, 10.0, 5.0, 3.0, 2.0, 1.0) AS bm25Score
|
|
57
87
|
FROM entries_fts f
|
|
@@ -68,10 +98,10 @@ function runFtsQuery(db, ftsQuery, limit, entryType, excludeTypes) {
|
|
|
68
98
|
for (const row of rows) {
|
|
69
99
|
let entry;
|
|
70
100
|
try {
|
|
71
|
-
entry = JSON.parse(row.
|
|
101
|
+
entry = JSON.parse(row.documentJson);
|
|
72
102
|
}
|
|
73
103
|
catch {
|
|
74
|
-
warn(`[db] searchFts: skipping entry id=${row.id} — corrupt
|
|
104
|
+
warn(`[db] searchFts: skipping entry id=${row.id} — corrupt document_json`);
|
|
75
105
|
continue;
|
|
76
106
|
}
|
|
77
107
|
results.push({
|
|
@@ -84,6 +114,7 @@ function runFtsQuery(db, ftsQuery, limit, entryType, excludeTypes) {
|
|
|
84
114
|
bundleId: row.bundleId,
|
|
85
115
|
conceptId: row.conceptId,
|
|
86
116
|
adapterId: row.adapterId,
|
|
117
|
+
lexicalMatch,
|
|
87
118
|
});
|
|
88
119
|
}
|
|
89
120
|
return results;
|
|
@@ -94,55 +125,26 @@ function runFtsQuery(db, ftsQuery, limit, entryType, excludeTypes) {
|
|
|
94
125
|
}
|
|
95
126
|
}
|
|
96
127
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* appropriate for `akm index --full` and version-upgrade rebuilds.
|
|
103
|
-
*
|
|
104
|
-
* Both paths are wrapped in a single transaction so the FTS table is never
|
|
105
|
-
* left in a half-rebuilt state.
|
|
128
|
+
* Explicitly rebuild the complete FTS5 projection from canonical entries.
|
|
129
|
+
* Ordinary entry mutations do not call this: `upsertEntry` and the delete
|
|
130
|
+
* operations publish their FTS state in the same transaction as `entries`.
|
|
131
|
+
* This remains a recovery/schema-verification primitive for regenerable
|
|
132
|
+
* `index.db` state.
|
|
106
133
|
*
|
|
107
134
|
* Skipped corrupt-JSON rows are aggregated into one warning instead of
|
|
108
135
|
* spamming stderr per-entry.
|
|
109
136
|
*/
|
|
110
|
-
export function rebuildFts(db
|
|
111
|
-
const incremental = options?.incremental === true;
|
|
137
|
+
export function rebuildFts(db) {
|
|
112
138
|
db.transaction(() => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Then drop the matching rows from entries_fts so the INSERT below
|
|
117
|
-
// doesn't double-up. The dirty list is drained at the end.
|
|
118
|
-
rows = db
|
|
119
|
-
.prepare(`SELECT e.id AS id, e.entry_json AS entry_json
|
|
120
|
-
FROM entries_fts_dirty d
|
|
121
|
-
JOIN entries e ON e.id = d.entry_id`)
|
|
122
|
-
.all();
|
|
123
|
-
if (rows.length === 0)
|
|
124
|
-
return;
|
|
125
|
-
const ids = rows.map((r) => r.id);
|
|
126
|
-
// Delete only the dirty FTS rows — chunk to stay under
|
|
127
|
-
// SQLITE_MAX_VARIABLE_NUMBER on large dirty queues.
|
|
128
|
-
for (let i = 0; i < ids.length; i += SQLITE_CHUNK_SIZE) {
|
|
129
|
-
const chunk = ids.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
130
|
-
const placeholders = chunk.map(() => "?").join(",");
|
|
131
|
-
db.prepare(`DELETE FROM entries_fts WHERE entry_id IN (${placeholders})`).run(...chunk);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
// Full path: wipe and re-read every row.
|
|
136
|
-
db.exec("DELETE FROM entries_fts");
|
|
137
|
-
rows = db.prepare("SELECT id, entry_json FROM entries").all();
|
|
138
|
-
}
|
|
139
|
-
const insertStmt = db.prepare("INSERT INTO entries_fts (entry_id, name, description, tags, hints, content) VALUES (?, ?, ?, ?, ?, ?)");
|
|
139
|
+
db.exec("DELETE FROM entries_fts");
|
|
140
|
+
const rows = db.prepare("SELECT id, document_json FROM entries").all();
|
|
141
|
+
const insertStmt = db.prepare(INSERT_FTS_SQL);
|
|
140
142
|
let skipped = 0;
|
|
141
143
|
for (const row of rows) {
|
|
142
144
|
let entry;
|
|
143
145
|
let fields;
|
|
144
146
|
try {
|
|
145
|
-
entry = JSON.parse(row.
|
|
147
|
+
entry = JSON.parse(row.document_json);
|
|
146
148
|
fields = buildSearchFields(entry);
|
|
147
149
|
}
|
|
148
150
|
catch {
|
|
@@ -152,16 +154,7 @@ export function rebuildFts(db, options) {
|
|
|
152
154
|
insertStmt.run(row.id, fields.name, fields.description, fields.tags, fields.hints, fields.content);
|
|
153
155
|
}
|
|
154
156
|
if (skipped > 0) {
|
|
155
|
-
warn(`[db] rebuildFts: skipped ${skipped} entr${skipped === 1 ? "y" : "ies"} with invalid
|
|
157
|
+
warn(`[db] rebuildFts: skipped ${skipped} entr${skipped === 1 ? "y" : "ies"} with invalid document_json`);
|
|
156
158
|
}
|
|
157
|
-
// Always drain the dirty queue — both paths converge here. The
|
|
158
|
-
// incremental path drains it because we just consumed every dirty row;
|
|
159
|
-
// the full path drains it because a full rebuild covers everything the
|
|
160
|
-
// dirty list tracks. The table is guaranteed to exist (created by
|
|
161
|
-
// ensureSchema()).
|
|
162
|
-
//
|
|
163
|
-
// BUG-L1: previously the if/else arms ran identical statements — the
|
|
164
|
-
// duplication has been collapsed.
|
|
165
|
-
db.exec("DELETE FROM entries_fts_dirty");
|
|
166
159
|
})();
|
|
167
160
|
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* Owns the raw SQL for `llm_enrichment_cache` — the body-hash-keyed cache that
|
|
8
8
|
* lets `akm index --enrich` skip the LLM call when a file's body is unchanged.
|
|
9
9
|
*/
|
|
10
|
-
import { bestEffort } from "../../core/best-effort.js";
|
|
11
10
|
import { sha256Hex } from "../../runtime.js";
|
|
12
11
|
import { SQLITE_CHUNK_SIZE } from "./index-sql.js";
|
|
13
12
|
/**
|
|
@@ -83,20 +82,16 @@ export function upsertLlmCacheEntry(db, assetRef, bodyHash, resultJson, cacheVar
|
|
|
83
82
|
* `entries` table. Should be called during the cleanup phase of each index
|
|
84
83
|
* run to prevent the cache from growing unboundedly as assets are removed.
|
|
85
84
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* corresponding row in either the entries table (by entry_key) or that
|
|
90
|
-
* matches a live file_path.
|
|
85
|
+
* Graph/memory cache refs are absolute file paths, while metadata-enrichment
|
|
86
|
+
* refs use canonical `item_ref`; preserve a cache row that matches either
|
|
87
|
+
* current identity.
|
|
91
88
|
*/
|
|
92
89
|
export function clearStaleCacheEntries(db) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`);
|
|
99
|
-
}, "llm_enrichment_cache may not exist in very old DBs opened without ensureSchema");
|
|
90
|
+
db.exec(`
|
|
91
|
+
DELETE FROM llm_enrichment_cache
|
|
92
|
+
WHERE asset_ref NOT IN (SELECT file_path FROM entries)
|
|
93
|
+
AND asset_ref NOT IN (SELECT item_ref FROM entries)
|
|
94
|
+
`);
|
|
100
95
|
}
|
|
101
96
|
/**
|
|
102
97
|
* Compute a stable SHA-256 hex digest of a UTF-8 string. Used as the body_hash
|
|
@@ -1,14 +1,6 @@
|
|
|
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` meta + per-directory index-state repository.
|
|
6
|
-
*
|
|
7
|
-
* Owns the raw SQL for `index_meta` (the key/value stamp table) and
|
|
8
|
-
* `index_dir_state` (incremental-index bookkeeping). Lives in the storage
|
|
9
|
-
* layer, not the indexer, so the storage layer owns these primitives.
|
|
10
|
-
*/
|
|
11
|
-
import path from "node:path";
|
|
12
4
|
// ── Meta helpers ────────────────────────────────────────────────────────────
|
|
13
5
|
export function getMeta(db, key) {
|
|
14
6
|
const row = db.prepare("SELECT value FROM index_meta WHERE key = ?").get(key);
|
|
@@ -55,6 +47,3 @@ export function upsertIndexDirState(db, state) {
|
|
|
55
47
|
export function deleteIndexDirState(db, dirPath) {
|
|
56
48
|
db.prepare("DELETE FROM index_dir_state WHERE dir_path = ?").run(dirPath);
|
|
57
49
|
}
|
|
58
|
-
export function deleteIndexDirStatesByStashDir(db, stashDir) {
|
|
59
|
-
db.prepare("DELETE FROM index_dir_state WHERE dir_path = ? OR dir_path LIKE ?").run(stashDir, `${stashDir}${path.sep}%`);
|
|
60
|
-
}
|