akm-cli 0.9.16 → 0.9.17-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2101 -0
- package/STABILITY.md +11 -10
- package/dist/akm +124 -193
- package/dist/akm-migrate +38 -19
- package/dist/assets/hints/cli-hints-full.md +6 -7
- package/dist/assets/improve-strategies/catchup.json +0 -3
- package/dist/assets/improve-strategies/consolidate.json +0 -1
- package/dist/assets/improve-strategies/default.json +1 -2
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
- package/dist/assets/improve-strategies/quick.json +1 -2
- package/dist/assets/improve-strategies/reflect-distill.json +1 -2
- package/dist/assets/improve-strategies/thorough.json +0 -3
- package/dist/assets/prompts/consolidate-pair.md +20 -0
- package/dist/assets/prompts/consolidate-system.md +4 -11
- package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +20 -20
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
- package/dist/assets/templates/html/health.html +3 -5
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +6 -2
- package/dist/cli/unknown-flags.js +24 -1
- package/dist/cli.js +68 -10
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +6 -0
- package/dist/commands/health/archive-usage.js +92 -0
- package/dist/commands/health/checks.js +83 -74
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/data-dir-usage.js +25 -13
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +1 -42
- package/dist/commands/health/improve-metrics.js +136 -591
- package/dist/commands/health/md-report.js +1 -6
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +14 -120
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -74
- package/dist/commands/health.js +145 -143
- package/dist/commands/improve/consolidate/chunking.js +26 -117
- package/dist/commands/improve/consolidate/continuity-check.js +137 -0
- package/dist/commands/improve/consolidate/pair-pass.js +791 -0
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +589 -1127
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1041
- package/dist/commands/improve/eligibility.js +126 -390
- package/dist/commands/improve/execution.js +8 -10
- package/dist/commands/improve/extract-prompt.js +1 -2
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +75 -169
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +52 -4
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +480 -1074
- package/dist/commands/improve/ledger.js +119 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +415 -1073
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +16 -118
- package/dist/commands/improve/memory/memory-improve.js +266 -14
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -15
- package/dist/commands/improve/preparation.js +779 -2319
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +642 -1353
- package/dist/commands/improve/retrieval-gate.js +127 -0
- package/dist/commands/improve/retrieval-scope.js +92 -0
- package/dist/commands/improve/salience.js +41 -240
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +322 -0
- package/dist/commands/lint/base-linter.js +37 -15
- package/dist/commands/proposal/drain.js +261 -578
- package/dist/commands/proposal/proposal-cli.js +19 -20
- package/dist/commands/proposal/proposal-types.js +31 -24
- package/dist/commands/proposal/proposal.js +38 -8
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +1097 -1394
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +22 -89
- package/dist/commands/read/curate.js +105 -462
- package/dist/commands/read/knowledge.js +3 -2
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +57 -108
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +4 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +127 -29
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/source-manage.js +9 -2
- package/dist/commands/sources/stash-cli.js +24 -4
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +12 -13
- package/dist/commands/tasks/tasks.js +350 -936
- package/dist/commands/tasks/validate.js +26 -24
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +2 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +42 -12
- package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/asset-placement.js +4 -13
- package/dist/core/asset/frontmatter.js +106 -1
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +285 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +9 -34
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +184 -111
- package/dist/core/config/engine-semantics.js +0 -2
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +54 -125
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/index-config.js +9 -48
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-change.js +13 -5
- package/dist/core/file-lock.js +76 -173
- package/dist/core/improve-result.js +35 -7
- package/dist/core/improve-types.js +0 -1
- package/dist/core/logs-db.js +2 -2
- package/dist/core/loopback.js +7 -12
- package/dist/core/non-task-input.js +20 -0
- package/dist/core/parse.js +13 -16
- package/dist/core/paths.js +0 -24
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +123 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/time.js +0 -20
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +294 -1005
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/ensure-index.js +77 -73
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +141 -154
- package/dist/indexer/indexer.js +400 -1124
- package/dist/indexer/links/declared-links.js +90 -0
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +96 -90
- package/dist/indexer/passes/metadata.js +132 -219
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +2 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +190 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +36 -7
- package/dist/indexer/walk/walker.js +3 -4
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/client.js +18 -6
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +11 -17
- package/dist/llm/feature-gate.js +0 -8
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +25 -38
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/graph/graph-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +69 -31
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +48 -3
- package/dist/output/text/show-format.js +13 -17
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +42948 -92369
- package/dist/scripts/akm-migrate.js +42935 -92354
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/connection.js +5 -6
- package/dist/setup/steps/platforms.js +2 -2
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +83 -21
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +209 -0
- package/dist/storage/repositories/index-connection.js +39 -72
- package/dist/storage/repositories/index-entries-repository.js +131 -129
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +101 -268
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-links-repository.js +143 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +7 -9
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +257 -325
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +104 -1
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/salience-repository.js +1 -19
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +130 -0
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +191 -302
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +141 -748
- package/dist/tasks/backends/schtasks.js +119 -623
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/run/load-task.js +1 -1
- package/dist/tasks/scheduler-binding.js +20 -238
- package/dist/tasks/scheduler-invocation.js +136 -244
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +368 -679
- package/dist/tasks/source/parse-task-source.js +55 -9
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +464 -88
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +43 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +23 -7
- package/docs/reference/cli.md +232 -135
- package/docs/reference/configuration.md +71 -57
- package/docs/reference/data-and-telemetry.md +20 -21
- package/docs/reference/tasks.md +105 -39
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +115 -738
- package/schemas/akm-workflow.json +1 -0
- package/dist/assets/improve-strategies/graph-refresh.json +0 -15
- package/dist/assets/prompts/contradiction-judge.md +0 -33
- package/dist/assets/prompts/graph-extract-system.md +0 -1
- package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
- package/dist/assets/prompts/metadata-enhance-system.md +0 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -149
- package/dist/commands/improve/distill/promote-memory.js +0 -291
- package/dist/commands/improve/distill/quality-gate.js +0 -337
- package/dist/commands/improve/eval-cases.js +0 -52
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -31
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -427
- package/dist/indexer/db/graph-db.js +0 -444
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/graph/graph-extraction.js +0 -1108
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/search/ranking-types.js +0 -4
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/llm/graph-extract.js +0 -728
- package/dist/llm/metadata-enhance.js +0 -96
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/tasks/source/task-to-v3.js +0 -507
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -77
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -18,20 +18,30 @@ import { getStateDbPath, withStateDb } from "../../core/state-db.js";
|
|
|
18
18
|
import { warn } from "../../core/warn.js";
|
|
19
19
|
import { getMarkdownFragmentContent, hasMarkdownFragmentContent, } from "../../indexer/passes/metadata.js";
|
|
20
20
|
import { buildSearchText } from "../../indexer/search/search-fields.js";
|
|
21
|
+
import { sha256Hex } from "../../runtime.js";
|
|
21
22
|
import { ENTRY_COLUMNS, rowToIndexedEntry } from "./index-entry-mapper.js";
|
|
22
23
|
import { deleteFtsEntries, replaceFtsEntry } from "./index-fts-repository.js";
|
|
24
|
+
import { deleteEntryLinks, replaceEntryLinks } from "./index-links-repository.js";
|
|
23
25
|
import { SQLITE_CHUNK_SIZE } from "./index-sql.js";
|
|
24
|
-
import { deleteEntryVectors
|
|
26
|
+
import { deleteEntryVectors } from "./index-vec-repository.js";
|
|
25
27
|
// ── Entry operations ────────────────────────────────────────────────────────
|
|
28
|
+
/**
|
|
29
|
+
* Hash of the text an entry's vector is embedded from (`buildSearchText`),
|
|
30
|
+
* stored as `entries.embed_hash`: a change deletes the entry's vector, and the
|
|
31
|
+
* next embedding pass re-embeds it.
|
|
32
|
+
*/
|
|
33
|
+
function embedHash(entry) {
|
|
34
|
+
return sha256Hex(buildSearchText(entry));
|
|
35
|
+
}
|
|
26
36
|
/**
|
|
27
37
|
* Insert or update one canonical entry and all synchronously derived search
|
|
28
38
|
* state. Returns the stable row id.
|
|
29
39
|
*
|
|
30
|
-
* The entries row, FTS projection, and stale-vector
|
|
31
|
-
* SQLite transaction. Callers therefore cannot
|
|
32
|
-
* second FTS maintenance step.
|
|
40
|
+
* The entries row, FTS projection, declared links, and stale-vector
|
|
41
|
+
* invalidation commit as one SQLite transaction. Callers therefore cannot
|
|
42
|
+
* publish an entry and forget a second FTS or links maintenance step.
|
|
33
43
|
*/
|
|
34
|
-
export function upsertEntry(db, filePath, entry,
|
|
44
|
+
export function upsertEntry(db, filePath, entry, provenance, contentHash) {
|
|
35
45
|
// Hot path during indexing — cache prepared statements per database
|
|
36
46
|
// connection so we don't pay the SQL parse/compile cost on every call.
|
|
37
47
|
const stmts = getUpsertStmts(db);
|
|
@@ -39,16 +49,18 @@ export function upsertEntry(db, filePath, entry, searchText, provenance, content
|
|
|
39
49
|
// dedicated `derived_from` column so retrieval-time lookup (parent→child)
|
|
40
50
|
// does not have to scan + JSON-decode every memory row.
|
|
41
51
|
const derivedFrom = typeof entry.derivedFrom === "string" && entry.derivedFrom.trim() ? entry.derivedFrom.trim() : null;
|
|
42
|
-
|
|
43
|
-
// preserves the scan
|
|
52
|
+
const hash = embedHash(entry);
|
|
53
|
+
// `content_hash` is optional; an upsert that omits it preserves the scan
|
|
54
|
+
// writer's current value.
|
|
44
55
|
const apply = () => {
|
|
45
56
|
const previous = stmts.findByItemRef.get(provenance.itemRef);
|
|
46
|
-
const result = stmts.upsert.get(provenance.itemRef, provenance.bundleId, provenance.componentId, provenance.conceptId, provenance.adapterId, entry.type, filePath, contentHash ?? null, JSON.stringify(entry),
|
|
57
|
+
const result = stmts.upsert.get(provenance.itemRef, provenance.bundleId, provenance.componentId, provenance.conceptId, provenance.adapterId, entry.type, filePath, contentHash ?? null, JSON.stringify(entry), derivedFrom, hash);
|
|
47
58
|
if (!result)
|
|
48
59
|
throw new Error("upsertEntry: item_ref not found after upsert");
|
|
49
|
-
if (previous?.id === result.id && previous.
|
|
60
|
+
if (previous?.id === result.id && previous.embed_hash !== hash)
|
|
50
61
|
deleteEntryVectors(db, result.id);
|
|
51
62
|
replaceFtsEntry(db, result.id, entry, hasMarkdownFragmentContent(entry) ? (getMarkdownFragmentContent(entry) ?? null) : undefined);
|
|
63
|
+
replaceEntryLinks(db, result.id, entry, provenance);
|
|
52
64
|
return result.id;
|
|
53
65
|
};
|
|
54
66
|
// Always enter the driver's transaction wrapper. Both supported SQLite
|
|
@@ -58,8 +70,8 @@ export function upsertEntry(db, filePath, entry, searchText, provenance, content
|
|
|
58
70
|
return db.transaction(apply)();
|
|
59
71
|
}
|
|
60
72
|
const upsertStmtsByDb = new WeakMap();
|
|
61
|
-
// item_ref is the sole durable conflict target. `content_hash` COALESCEs so
|
|
62
|
-
//
|
|
73
|
+
// item_ref is the sole durable conflict target. `content_hash` COALESCEs so
|
|
74
|
+
// an upsert that omits it (`contentHash` is optional) cannot wipe a scan hash.
|
|
63
75
|
const UPSERT_SET_CLAUSE = `SET
|
|
64
76
|
bundle_id = excluded.bundle_id,
|
|
65
77
|
component_id = excluded.component_id,
|
|
@@ -68,8 +80,8 @@ const UPSERT_SET_CLAUSE = `SET
|
|
|
68
80
|
type = excluded.type,
|
|
69
81
|
file_path = excluded.file_path,
|
|
70
82
|
document_json = excluded.document_json,
|
|
71
|
-
search_text = excluded.search_text,
|
|
72
83
|
derived_from = excluded.derived_from,
|
|
84
|
+
embed_hash = excluded.embed_hash,
|
|
73
85
|
content_hash = COALESCE(excluded.content_hash, content_hash)`;
|
|
74
86
|
function getUpsertStmts(db) {
|
|
75
87
|
const existing = upsertStmtsByDb.get(db);
|
|
@@ -82,13 +94,13 @@ function getUpsertStmts(db) {
|
|
|
82
94
|
upsert: db.prepare(`
|
|
83
95
|
INSERT INTO entries (
|
|
84
96
|
item_ref, bundle_id, component_id, concept_id, adapter_id, type,
|
|
85
|
-
file_path, content_hash, document_json,
|
|
97
|
+
file_path, content_hash, document_json, derived_from, embed_hash
|
|
86
98
|
)
|
|
87
99
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
88
100
|
ON CONFLICT(item_ref) DO UPDATE ${UPSERT_SET_CLAUSE}
|
|
89
101
|
RETURNING id
|
|
90
102
|
`),
|
|
91
|
-
findByItemRef: db.prepare("SELECT id,
|
|
103
|
+
findByItemRef: db.prepare("SELECT id, embed_hash FROM entries WHERE item_ref = ?"),
|
|
92
104
|
};
|
|
93
105
|
upsertStmtsByDb.set(db, stmts);
|
|
94
106
|
return stmts;
|
|
@@ -164,14 +176,13 @@ export function getBaseBeliefStatesForDerivedTwins(db, twinIds) {
|
|
|
164
176
|
/**
|
|
165
177
|
* Re-key an entries row in place for the opt-in source-maintenance script.
|
|
166
178
|
*
|
|
167
|
-
* The row id is preserved on purpose — `utility_scores
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
* `asset_ref` TEXT and are re-keyed separately by `akm mv` — see
|
|
179
|
+
* The row id is preserved on purpose — `utility_scores` and `embeddings` are
|
|
180
|
+
* keyed by `entry_id`, so an UPDATE (rather than a delete + insert under the
|
|
181
|
+
* new `item_ref`) is what keeps the asset's accumulated usage-ranking history
|
|
182
|
+
* attached across a rename. (`asset_salience` / `asset_outcome` live in
|
|
183
|
+
* state.db keyed by `asset_ref` TEXT and are re-keyed separately by `akm mv` — see
|
|
173
184
|
* the state rekey helper.) `document_json.name` (and `filename`, when
|
|
174
|
-
* present) is patched and `
|
|
185
|
+
* present) is patched and `embed_hash` recomputed so search reflects the new
|
|
175
186
|
* name. Its FTS projection and stale vector are updated in the same
|
|
176
187
|
* transaction as the canonical identity.
|
|
177
188
|
*
|
|
@@ -187,7 +198,7 @@ export function getBaseBeliefStatesForDerivedTwins(db, twinIds) {
|
|
|
187
198
|
* A stale row already occupying the new item ref (the caller has verified no
|
|
188
199
|
* FILE exists at the target, so such a row can only be a leftover for a
|
|
189
200
|
* deleted file) is evicted first — through {@link deleteRelatedRows}, so its
|
|
190
|
-
* child rows (embeddings,
|
|
201
|
+
* child rows (embeddings, utility scores, usage events) go with
|
|
191
202
|
* it. A bare `DELETE FROM entries` would trip the non-CASCADE `embeddings`
|
|
192
203
|
* FK under `PRAGMA foreign_keys = ON` and roll back the whole re-key.
|
|
193
204
|
* The moved row keeps its id.
|
|
@@ -199,7 +210,7 @@ export function getBaseBeliefStatesForDerivedTwins(db, twinIds) {
|
|
|
199
210
|
export function rekeyEntryInPlace(db, opts) {
|
|
200
211
|
const oldItemRef = `${opts.sourceName}//${opts.oldRef}`;
|
|
201
212
|
const row = db
|
|
202
|
-
.prepare("SELECT id, file_path, document_json,
|
|
213
|
+
.prepare("SELECT id, file_path, document_json, embed_hash, type FROM entries WHERE item_ref = ?")
|
|
203
214
|
.get(oldItemRef);
|
|
204
215
|
if (!row)
|
|
205
216
|
return null;
|
|
@@ -211,7 +222,7 @@ export function rekeyEntryInPlace(db, opts) {
|
|
|
211
222
|
// Patch the JSON payload. On corrupt document_json still re-key identity/path so
|
|
212
223
|
// the utility history survives; the next full index heals the JSON.
|
|
213
224
|
let documentJson = row.document_json;
|
|
214
|
-
let
|
|
225
|
+
let hash = row.embed_hash;
|
|
215
226
|
let document;
|
|
216
227
|
try {
|
|
217
228
|
const entry = JSON.parse(row.document_json);
|
|
@@ -221,7 +232,7 @@ export function rekeyEntryInPlace(db, opts) {
|
|
|
221
232
|
if (opts.newDerivedFrom !== undefined)
|
|
222
233
|
entry.derivedFrom = opts.newDerivedFrom;
|
|
223
234
|
documentJson = JSON.stringify(entry);
|
|
224
|
-
|
|
235
|
+
hash = embedHash(entry);
|
|
225
236
|
document = entry;
|
|
226
237
|
}
|
|
227
238
|
catch {
|
|
@@ -235,7 +246,7 @@ export function rekeyEntryInPlace(db, opts) {
|
|
|
235
246
|
db.transaction(() => {
|
|
236
247
|
const stale = db.prepare("SELECT id FROM entries WHERE item_ref = ?").get(newItemRef);
|
|
237
248
|
if (stale && stale.id !== row.id) {
|
|
238
|
-
// Full child-row cleanup (embeddings,
|
|
249
|
+
// Full child-row cleanup (embeddings, utility scores,
|
|
239
250
|
// usage events, FTS + dirty marks) BEFORE the entries delete: the
|
|
240
251
|
// `embeddings` FK is non-CASCADE and `foreign_keys = ON`, so a bare
|
|
241
252
|
// entries delete would throw and roll back the entire re-key; and
|
|
@@ -243,14 +254,16 @@ export function rekeyEntryInPlace(db, opts) {
|
|
|
243
254
|
deleteRelatedRows(db, [{ id: stale.id }]);
|
|
244
255
|
db.prepare("DELETE FROM entries WHERE id = ?").run(stale.id);
|
|
245
256
|
}
|
|
246
|
-
db.prepare("UPDATE entries SET file_path = ?, document_json = ?,
|
|
257
|
+
db.prepare("UPDATE entries SET file_path = ?, document_json = ?, embed_hash = ?, item_ref = ?, concept_id = ? WHERE id = ?").run(opts.newFilePath, documentJson, hash, newItemRef, opts.newRef, row.id);
|
|
247
258
|
if (opts.newDerivedFrom !== undefined) {
|
|
248
259
|
db.prepare("UPDATE entries SET derived_from = ? WHERE id = ?").run(opts.newDerivedFrom, row.id);
|
|
249
260
|
}
|
|
250
|
-
if (row.
|
|
261
|
+
if (row.embed_hash !== hash)
|
|
251
262
|
deleteEntryVectors(db, row.id);
|
|
252
|
-
if (document)
|
|
263
|
+
if (document) {
|
|
253
264
|
replaceFtsEntry(db, row.id, document, hasMarkdownFragmentContent(document) ? (getMarkdownFragmentContent(document) ?? null) : undefined);
|
|
265
|
+
replaceEntryLinks(db, row.id, document, { bundleId: opts.sourceName, conceptId: opts.newRef });
|
|
266
|
+
}
|
|
254
267
|
else
|
|
255
268
|
deleteFtsEntries(db, [row.id]);
|
|
256
269
|
})();
|
|
@@ -293,50 +306,6 @@ function rewriteUsageEventRefForMove(opts) {
|
|
|
293
306
|
throw new Error(`Failed to rewrite usage events for move: ${message}`, { cause: error });
|
|
294
307
|
}
|
|
295
308
|
}
|
|
296
|
-
/**
|
|
297
|
-
* Phase 2A / Rec 5: bulk-load positive feedback event counts for the given
|
|
298
|
-
* entry ids. Used by the utility-decay forgetting curve to stabilize
|
|
299
|
-
* (extend the half-life of) memories that have repeatedly proven useful.
|
|
300
|
-
*
|
|
301
|
-
* Returns a `Map<entryId, count>` containing only entries with at least one
|
|
302
|
-
* positive feedback event — missing ids implicitly map to `0`. Chunks at
|
|
303
|
-
* `SQLITE_CHUNK_SIZE` (500) to respect `SQLITE_MAX_VARIABLE_NUMBER`.
|
|
304
|
-
*
|
|
305
|
-
* Cheap when called with zero ids, and silently empty when state.db (or its
|
|
306
|
-
* `usage_events` table) is absent.
|
|
307
|
-
*
|
|
308
|
-
* Chunk-8 WI-8.3: usage_events lives in state.db — this reads it there (no
|
|
309
|
-
* entries join needed; the ids are supplied by the caller). Gated by the caller
|
|
310
|
-
* (`shouldQueryPositiveFeedbackCounts`) so the state.db open is not on the
|
|
311
|
-
* default search hot path.
|
|
312
|
-
*/
|
|
313
|
-
export function getPositiveFeedbackCountsByIds(ids) {
|
|
314
|
-
const result = new Map();
|
|
315
|
-
if (ids.length === 0 || !fs.existsSync(getStateDbPath()))
|
|
316
|
-
return result;
|
|
317
|
-
bestEffort(() => {
|
|
318
|
-
withStateDb((stateDb) => {
|
|
319
|
-
for (let i = 0; i < ids.length; i += SQLITE_CHUNK_SIZE) {
|
|
320
|
-
const chunk = ids.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
321
|
-
const placeholders = chunk.map(() => "?").join(",");
|
|
322
|
-
const rows = stateDb
|
|
323
|
-
.prepare(`SELECT entry_id, COUNT(*) AS cnt
|
|
324
|
-
FROM usage_events
|
|
325
|
-
WHERE event_type = 'feedback'
|
|
326
|
-
AND signal = 'positive'
|
|
327
|
-
AND entry_id IN (${placeholders})
|
|
328
|
-
GROUP BY entry_id`)
|
|
329
|
-
.all(...chunk);
|
|
330
|
-
for (const row of rows) {
|
|
331
|
-
if (row.entry_id !== null && row.cnt > 0) {
|
|
332
|
-
result.set(row.entry_id, row.cnt);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
}, "positive feedback counts are best-effort");
|
|
338
|
-
return result;
|
|
339
|
-
}
|
|
340
309
|
/**
|
|
341
310
|
* Rows whose `file_path` sits directly in `dirPath`. A half-open byte range
|
|
342
311
|
* over `idx_entries_file_path` (`[dir + sep, dir + sep + 1)`) turns the lookup
|
|
@@ -382,14 +351,30 @@ export function deleteEntriesByBundle(db, bundleId) {
|
|
|
382
351
|
})();
|
|
383
352
|
}
|
|
384
353
|
/**
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
354
|
+
* The `file_path` of every entry indexed under one bundle — used by
|
|
355
|
+
* `akm bundle rename` (D6) to find bundle CONTENT that still spells the old
|
|
356
|
+
* `<bundle>//` prefix (xrefs, `supersededBy`, task `uses:`), which the rename
|
|
357
|
+
* reports rather than rewrites.
|
|
358
|
+
*/
|
|
359
|
+
export function getFilePathsByBundle(db, bundleId) {
|
|
360
|
+
const rows = db.prepare("SELECT DISTINCT file_path FROM entries WHERE bundle_id = ?").all(bundleId);
|
|
361
|
+
return rows.map((row) => row.file_path);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Re-key every entry row's `bundle_id`/`item_ref` from `oldBundleId` to
|
|
365
|
+
* `newBundleId` in place (`akm bundle rename`, D6). Unlike
|
|
366
|
+
* {@link rekeyEntryInPlace} (one asset, `akm mv`), this is a bulk identity
|
|
367
|
+
* change with no content move: `concept_id`/`file_path`/`document_json` are
|
|
368
|
+
* untouched, so no FTS/vector rebuild is needed (FTS and `embeddings` key on
|
|
369
|
+
* the entry's row `id`, which this preserves, not on `item_ref`). Returns the
|
|
370
|
+
* number of rows renamed.
|
|
388
371
|
*/
|
|
389
|
-
export function
|
|
372
|
+
export function renameEntriesBundleId(db, oldBundleId, newBundleId) {
|
|
390
373
|
return db.transaction(() => {
|
|
391
|
-
const
|
|
392
|
-
|
|
374
|
+
const result = db
|
|
375
|
+
.prepare("UPDATE entries SET bundle_id = ?, item_ref = ? || '//' || concept_id WHERE bundle_id = ?")
|
|
376
|
+
.run(newBundleId, newBundleId, oldBundleId);
|
|
377
|
+
return Number(result.changes);
|
|
393
378
|
})();
|
|
394
379
|
}
|
|
395
380
|
/**
|
|
@@ -415,56 +400,24 @@ function deleteRelatedRows(db, ids, options = {}) {
|
|
|
415
400
|
if (ids.length === 0)
|
|
416
401
|
return;
|
|
417
402
|
const numericIds = ids.map((r) => r.id);
|
|
418
|
-
|
|
419
|
-
//
|
|
420
|
-
//
|
|
403
|
+
// FTS and declared links are part of the canonical mutation boundary, not a
|
|
404
|
+
// caller-maintained dirty queue. Delete them before the parent row inside
|
|
405
|
+
// this transaction.
|
|
421
406
|
deleteFtsEntries(db, numericIds);
|
|
407
|
+
deleteEntryLinks(db, numericIds);
|
|
422
408
|
// Process in chunks to stay within SQLITE_MAX_VARIABLE_NUMBER
|
|
423
409
|
for (let i = 0; i < numericIds.length; i += SQLITE_CHUNK_SIZE) {
|
|
424
410
|
const chunk = numericIds.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
425
411
|
const placeholders = chunk.map(() => "?").join(",");
|
|
426
412
|
bestEffort(() => db.prepare(`DELETE FROM embeddings WHERE id IN (${placeholders})`).run(...chunk), "delete embeddings for entries");
|
|
427
|
-
if (vecAvail) {
|
|
428
|
-
bestEffort(() => db.prepare(`DELETE FROM entries_vec WHERE id IN (${placeholders})`).run(...chunk), "delete entries_vec for entries");
|
|
429
|
-
}
|
|
430
413
|
// Clean up utility scores before deleting entries
|
|
431
414
|
bestEffort(() => db.prepare(`DELETE FROM utility_scores WHERE entry_id IN (${placeholders})`).run(...chunk), "delete utility_scores for entries");
|
|
432
|
-
bestEffort(() => db.prepare(`DELETE FROM utility_scores_scoped WHERE entry_id IN (${placeholders})`).run(...chunk), "delete utility_scores_scoped for entries");
|
|
433
|
-
}
|
|
434
|
-
// Graph rows are independently keyed and intentionally survive entry
|
|
435
|
-
// deletion. Resolve their owning roots through the canonical physical path
|
|
436
|
-
// before entries disappear, then refresh the derived summary counts.
|
|
437
|
-
const affectedGraphRoots = new Set();
|
|
438
|
-
for (let i = 0; i < numericIds.length; i += SQLITE_CHUNK_SIZE) {
|
|
439
|
-
const chunk = numericIds.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
440
|
-
const placeholders = chunk.map(() => "?").join(",");
|
|
441
|
-
bestEffort(() => {
|
|
442
|
-
const rows = db
|
|
443
|
-
.prepare(`SELECT DISTINCT gf.stash_root
|
|
444
|
-
FROM graph_files gf
|
|
445
|
-
JOIN entries e ON e.file_path = gf.file_path
|
|
446
|
-
WHERE e.id IN (${placeholders})`)
|
|
447
|
-
.all(...chunk);
|
|
448
|
-
for (const row of rows)
|
|
449
|
-
affectedGraphRoots.add(row.stash_root);
|
|
450
|
-
}, "resolve graph roots for graph_meta recompute");
|
|
451
|
-
}
|
|
452
|
-
for (const stashRoot of affectedGraphRoots) {
|
|
453
|
-
bestEffort(() => db
|
|
454
|
-
.prepare(`UPDATE graph_meta
|
|
455
|
-
SET extracted_files = (SELECT COUNT(*) FROM graph_files WHERE stash_root = ?),
|
|
456
|
-
entity_count = (SELECT COUNT(*) FROM graph_file_entities WHERE stash_root = ?),
|
|
457
|
-
relation_count = (SELECT COUNT(*) FROM graph_file_relations WHERE stash_root = ?)
|
|
458
|
-
WHERE stash_root = ?`)
|
|
459
|
-
.run(stashRoot, stashRoot, stashRoot, stashRoot), "sync graph_meta counts after entries delete");
|
|
460
415
|
}
|
|
461
416
|
// usage_events lives in state.db, outside this transaction. Index persistence
|
|
462
417
|
// disables this cleanup and runs it only after its index.db transaction
|
|
463
418
|
// commits; standalone delete callers retain the immediate behavior.
|
|
464
419
|
if (options.cleanupUsageEvents !== false)
|
|
465
420
|
deleteUsageEventsByEntryIds(numericIds);
|
|
466
|
-
// graph_files is keyed by its own stash_root/file_path/body_hash identity,
|
|
467
|
-
// so deleting an entry row intentionally leaves extracted graph data intact.
|
|
468
421
|
}
|
|
469
422
|
export function deleteUsageEventsByEntryIds(entryIds) {
|
|
470
423
|
if (entryIds.length === 0 || !fs.existsSync(getStateDbPath()))
|
|
@@ -481,7 +434,7 @@ export function deleteUsageEventsByEntryIds(entryIds) {
|
|
|
481
434
|
}
|
|
482
435
|
/**
|
|
483
436
|
* Delete entries by their primary key IDs, along with all related rows
|
|
484
|
-
* (embeddings,
|
|
437
|
+
* (embeddings, entries_fts, utility scores, usage_events).
|
|
485
438
|
*
|
|
486
439
|
* Used by explicit `--clean` reconciliation before embeddings and final
|
|
487
440
|
* verification to remove stale entries whose source files no longer exist.
|
|
@@ -645,6 +598,20 @@ export function getEntryById(db, id) {
|
|
|
645
598
|
adapterId: row.adapter_id,
|
|
646
599
|
};
|
|
647
600
|
}
|
|
601
|
+
/** The `item_ref` and `type` of every id that has an entry row. */
|
|
602
|
+
export function getEntryRefsAndTypes(db, ids) {
|
|
603
|
+
const out = new Map();
|
|
604
|
+
for (let i = 0; i < ids.length; i += SQLITE_CHUNK_SIZE) {
|
|
605
|
+
const chunk = ids.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
606
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
607
|
+
const rows = db
|
|
608
|
+
.prepare(`SELECT id, item_ref, type FROM entries WHERE id IN (${placeholders})`)
|
|
609
|
+
.all(...chunk);
|
|
610
|
+
for (const row of rows)
|
|
611
|
+
out.set(row.id, { itemRef: row.item_ref, type: row.type });
|
|
612
|
+
}
|
|
613
|
+
return out;
|
|
614
|
+
}
|
|
648
615
|
export function getEntriesByDir(db, dirPath) {
|
|
649
616
|
return parseEntryRows(selectRowsInDirectory(db, dirPath, ENTRY_COLUMNS), "getEntriesByDir");
|
|
650
617
|
}
|
|
@@ -684,6 +651,22 @@ export function getIndexedFilePaths(db) {
|
|
|
684
651
|
.all();
|
|
685
652
|
return new Set(rows.map((r) => r.file_path));
|
|
686
653
|
}
|
|
654
|
+
/**
|
|
655
|
+
* `entries.file_path -> content_hash` for every currently-indexed file that
|
|
656
|
+
* carries a stored hash. Used by per-file staleness detection
|
|
657
|
+
* (`hasNewerIndexableFiles`, R6) to tell "edited after the last build" apart
|
|
658
|
+
* from "already re-indexed with this exact content after the last build" —
|
|
659
|
+
* `indexWrittenAssets` upserts a fresh row (and its `content_hash`) without
|
|
660
|
+
* bumping `builtAt`, so mtime alone cannot distinguish the two cases.
|
|
661
|
+
*/
|
|
662
|
+
export function getIndexedFileHashes(db) {
|
|
663
|
+
const rows = db
|
|
664
|
+
.prepare(`SELECT file_path, content_hash FROM entries
|
|
665
|
+
WHERE file_path IS NOT NULL AND file_path <> ''
|
|
666
|
+
AND content_hash IS NOT NULL`)
|
|
667
|
+
.all();
|
|
668
|
+
return new Map(rows.map((r) => [r.file_path, r.content_hash]));
|
|
669
|
+
}
|
|
687
670
|
/**
|
|
688
671
|
* Resolve a single `entries.file_path` by primary key, or `undefined` if no
|
|
689
672
|
* row matches.
|
|
@@ -732,6 +715,33 @@ export function getEntryByRef(db, ref) {
|
|
|
732
715
|
const id = findEntryIdByRef(db, ref);
|
|
733
716
|
return id === undefined ? null : { id };
|
|
734
717
|
}
|
|
718
|
+
/** Build a {@link LiveRefSnapshot} from the current `entries` table. */
|
|
719
|
+
export function getLiveRefSnapshot(db) {
|
|
720
|
+
const rows = db.prepare("SELECT item_ref FROM entries").all();
|
|
721
|
+
const itemRefs = new Set();
|
|
722
|
+
const conceptIds = new Set();
|
|
723
|
+
for (const { item_ref } of rows) {
|
|
724
|
+
itemRefs.add(item_ref);
|
|
725
|
+
const boundary = item_ref.indexOf("//");
|
|
726
|
+
if (boundary >= 0)
|
|
727
|
+
conceptIds.add(item_ref.slice(boundary + 2));
|
|
728
|
+
}
|
|
729
|
+
return { itemRefs, conceptIds };
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* `getEntryByRef`'s liveness check (bundle-qualified exact match, or bare
|
|
733
|
+
* `//conceptId` suffix match across bundles, each tried with the `.md`
|
|
734
|
+
* toggle {@link withMdVariants} applies) against a prebuilt
|
|
735
|
+
* {@link LiveRefSnapshot} instead of the database — no query per call.
|
|
736
|
+
*/
|
|
737
|
+
export function isRefLiveInSnapshot(snapshot, ref) {
|
|
738
|
+
const parsed = parseBundleRef(ref);
|
|
739
|
+
const conceptVariants = withMdVariants(parsed.conceptId);
|
|
740
|
+
if (parsed.bundle !== undefined) {
|
|
741
|
+
return conceptVariants.some((conceptId) => snapshot.itemRefs.has(`${parsed.bundle}//${conceptId}`));
|
|
742
|
+
}
|
|
743
|
+
return conceptVariants.some((conceptId) => snapshot.conceptIds.has(conceptId));
|
|
744
|
+
}
|
|
735
745
|
/**
|
|
736
746
|
* The fully-qualified `item_ref` (`<bundle>//<conceptId>`, the durable stored
|
|
737
747
|
* spelling — spec §11.1 D-R3) for an entry `id`, or `null` when the row is gone
|
|
@@ -766,15 +776,7 @@ function resolveUsageEventEntryId(db, ref) {
|
|
|
766
776
|
* distinct linked entry_ids in usage_events is small — and the re-resolution
|
|
767
777
|
* reads `entries` from `indexDb`.
|
|
768
778
|
*/
|
|
769
|
-
function
|
|
770
|
-
if (stateSchema === undefined)
|
|
771
|
-
return "usage_events";
|
|
772
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(stateSchema))
|
|
773
|
-
throw new Error("Invalid attached state schema name.");
|
|
774
|
-
return `"${stateSchema}".usage_events`;
|
|
775
|
-
}
|
|
776
|
-
export function relinkUsageEvents(indexDb, stateDb, options = {}) {
|
|
777
|
-
const usageEvents = qualifiedUsageEventsTable(options.stateSchema);
|
|
779
|
+
export function relinkUsageEvents(indexDb, stateDb) {
|
|
778
780
|
bestEffort(() => {
|
|
779
781
|
// Step 1: null out stale entry_ids (entry was deleted, re-keyed, etc).
|
|
780
782
|
// Leaving them in place would let `recomputeUtilityScores` aggregate by an
|
|
@@ -783,7 +785,7 @@ export function relinkUsageEvents(indexDb, stateDb, options = {}) {
|
|
|
783
785
|
// transaction. Nulled rows can be re-resolved by step 2 below; events whose
|
|
784
786
|
// entry is permanently gone simply stay null and age out via retention.
|
|
785
787
|
const linkedRows = stateDb
|
|
786
|
-
.prepare(
|
|
788
|
+
.prepare("SELECT DISTINCT entry_id AS id, entry_ref AS ref FROM usage_events WHERE entry_id IS NOT NULL")
|
|
787
789
|
.all();
|
|
788
790
|
const entryIdentity = indexDb.prepare("SELECT item_ref AS itemRef FROM entries WHERE id = ?");
|
|
789
791
|
const staleLinks = linkedRows.filter(({ id, ref }) => {
|
|
@@ -791,7 +793,7 @@ export function relinkUsageEvents(indexDb, stateDb, options = {}) {
|
|
|
791
793
|
return live == null || (ref !== null && live.itemRef !== ref);
|
|
792
794
|
});
|
|
793
795
|
if (staleLinks.length > 0) {
|
|
794
|
-
const nullOut = stateDb.prepare(
|
|
796
|
+
const nullOut = stateDb.prepare("UPDATE usage_events SET entry_id = NULL WHERE entry_id = ? AND entry_ref IS ?");
|
|
795
797
|
const nullTx = stateDb.transaction(() => {
|
|
796
798
|
for (const { id, ref } of staleLinks)
|
|
797
799
|
nullOut.run(id, ref);
|
|
@@ -801,9 +803,9 @@ export function relinkUsageEvents(indexDb, stateDb, options = {}) {
|
|
|
801
803
|
// Step 2: re-resolve each fully-qualified ref. Bare rows are not current
|
|
802
804
|
// durable identities and remain detached.
|
|
803
805
|
const refs = stateDb
|
|
804
|
-
.prepare(
|
|
806
|
+
.prepare("SELECT DISTINCT entry_ref AS ref FROM usage_events WHERE entry_id IS NULL AND entry_ref IS NOT NULL")
|
|
805
807
|
.all();
|
|
806
|
-
const update = stateDb.prepare(
|
|
808
|
+
const update = stateDb.prepare("UPDATE usage_events SET entry_id = ? WHERE entry_ref = ? AND entry_id IS NULL");
|
|
807
809
|
const relinkTx = stateDb.transaction(() => {
|
|
808
810
|
for (const { ref } of refs) {
|
|
809
811
|
let id;
|
|
@@ -23,7 +23,7 @@ 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, item_ref, bundle_id, component_id, concept_id, adapter_id, type, file_path, content_hash, document_json
|
|
26
|
+
export const ENTRY_COLUMNS = "id, item_ref, bundle_id, component_id, concept_id, adapter_id, type, file_path, content_hash, document_json";
|
|
27
27
|
/**
|
|
28
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
|
|
@@ -42,7 +42,6 @@ export function rowToIndexedEntry(row, context) {
|
|
|
42
42
|
id: row.id,
|
|
43
43
|
filePath: row.file_path,
|
|
44
44
|
entry,
|
|
45
|
-
searchText: row.search_text,
|
|
46
45
|
itemRef: row.item_ref,
|
|
47
46
|
conceptId: row.concept_id,
|
|
48
47
|
bundleId: row.bundle_id,
|