trail-code 0.0.0-stage → 0.28.0-semantic.3
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/LICENSE +21 -0
- package/README.md +567 -2
- package/dist/ai/crux.d.ts +88 -0
- package/dist/ai/crux.d.ts.map +1 -0
- package/dist/ai/crux.js +219 -0
- package/dist/ai/crux.js.map +1 -0
- package/dist/ai/failure.d.ts +60 -0
- package/dist/ai/failure.d.ts.map +1 -0
- package/dist/ai/failure.js +86 -0
- package/dist/ai/failure.js.map +1 -0
- package/dist/ai/llm/anthropic.d.ts +37 -0
- package/dist/ai/llm/anthropic.d.ts.map +1 -0
- package/dist/ai/llm/anthropic.js +144 -0
- package/dist/ai/llm/anthropic.js.map +1 -0
- package/dist/ai/llm/factory.d.ts +28 -0
- package/dist/ai/llm/factory.d.ts.map +1 -0
- package/dist/ai/llm/factory.js +36 -0
- package/dist/ai/llm/factory.js.map +1 -0
- package/dist/ai/llm/litellm.d.ts +34 -0
- package/dist/ai/llm/litellm.d.ts.map +1 -0
- package/dist/ai/llm/litellm.js +45 -0
- package/dist/ai/llm/litellm.js.map +1 -0
- package/dist/ai/llm/openai.d.ts +145 -0
- package/dist/ai/llm/openai.d.ts.map +1 -0
- package/dist/ai/llm/openai.js +629 -0
- package/dist/ai/llm/openai.js.map +1 -0
- package/dist/ai/llm/orcarouter.d.ts +34 -0
- package/dist/ai/llm/orcarouter.d.ts.map +1 -0
- package/dist/ai/llm/orcarouter.js +45 -0
- package/dist/ai/llm/orcarouter.js.map +1 -0
- package/dist/ai/llm/recover-tool.d.ts +21 -0
- package/dist/ai/llm/recover-tool.d.ts.map +1 -0
- package/dist/ai/llm/recover-tool.js +109 -0
- package/dist/ai/llm/recover-tool.js.map +1 -0
- package/dist/ai/llm/types.d.ts +122 -0
- package/dist/ai/llm/types.d.ts.map +1 -0
- package/dist/ai/llm/types.js +33 -0
- package/dist/ai/llm/types.js.map +1 -0
- package/dist/ai/providers.d.ts +59 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +54 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/ai/summarize.d.ts +25 -0
- package/dist/ai/summarize.d.ts.map +1 -0
- package/dist/ai/summarize.js +34 -0
- package/dist/ai/summarize.js.map +1 -0
- package/dist/ai/synthesize.d.ts +40 -0
- package/dist/ai/synthesize.d.ts.map +1 -0
- package/dist/ai/synthesize.js +230 -0
- package/dist/ai/synthesize.js.map +1 -0
- package/dist/ask/ask.d.ts +199 -0
- package/dist/ask/ask.d.ts.map +1 -0
- package/dist/ask/ask.js +1291 -0
- package/dist/ask/ask.js.map +1 -0
- package/dist/ask/file-rank.d.ts +72 -0
- package/dist/ask/file-rank.d.ts.map +1 -0
- package/dist/ask/file-rank.js +160 -0
- package/dist/ask/file-rank.js.map +1 -0
- package/dist/ask/file-selection.d.ts +22 -0
- package/dist/ask/file-selection.d.ts.map +1 -0
- package/dist/ask/file-selection.js +66 -0
- package/dist/ask/file-selection.js.map +1 -0
- package/dist/ask/fuse.d.ts +195 -0
- package/dist/ask/fuse.d.ts.map +1 -0
- package/dist/ask/fuse.js +344 -0
- package/dist/ask/fuse.js.map +1 -0
- package/dist/ask/graphrank.d.ts +61 -0
- package/dist/ask/graphrank.d.ts.map +1 -0
- package/dist/ask/graphrank.js +130 -0
- package/dist/ask/graphrank.js.map +1 -0
- package/dist/ask/index-file.d.ts +44 -0
- package/dist/ask/index-file.d.ts.map +1 -0
- package/dist/ask/index-file.js +128 -0
- package/dist/ask/index-file.js.map +1 -0
- package/dist/ask/semantic.d.ts +42 -0
- package/dist/ask/semantic.d.ts.map +1 -0
- package/dist/ask/semantic.js +293 -0
- package/dist/ask/semantic.js.map +1 -0
- package/dist/bin/graft.d.ts +3 -0
- package/dist/bin/graft.d.ts.map +1 -0
- package/dist/bin/graft.js +14 -0
- package/dist/bin/graft.js.map +1 -0
- package/dist/bin/trail.d.ts +3 -0
- package/dist/bin/trail.d.ts.map +1 -0
- package/dist/bin/trail.js +13 -0
- package/dist/bin/trail.js.map +1 -0
- package/dist/blast/blast-cli.d.ts +35 -0
- package/dist/blast/blast-cli.d.ts.map +1 -0
- package/dist/blast/blast-cli.js +155 -0
- package/dist/blast/blast-cli.js.map +1 -0
- package/dist/blast/blast.d.ts +128 -0
- package/dist/blast/blast.d.ts.map +1 -0
- package/dist/blast/blast.js +383 -0
- package/dist/blast/blast.js.map +1 -0
- package/dist/blast/diff.d.ts +53 -0
- package/dist/blast/diff.d.ts.map +1 -0
- package/dist/blast/diff.js +193 -0
- package/dist/blast/diff.js.map +1 -0
- package/dist/blast/evidence.d.ts +51 -0
- package/dist/blast/evidence.d.ts.map +1 -0
- package/dist/blast/evidence.js +162 -0
- package/dist/blast/evidence.js.map +1 -0
- package/dist/blast/modules.d.ts +33 -0
- package/dist/blast/modules.d.ts.map +1 -0
- package/dist/blast/modules.js +83 -0
- package/dist/blast/modules.js.map +1 -0
- package/dist/blast/name.d.ts +74 -0
- package/dist/blast/name.d.ts.map +1 -0
- package/dist/blast/name.js +269 -0
- package/dist/blast/name.js.map +1 -0
- package/dist/blast/owners.d.ts +85 -0
- package/dist/blast/owners.d.ts.map +1 -0
- package/dist/blast/owners.js +272 -0
- package/dist/blast/owners.js.map +1 -0
- package/dist/blast/render.d.ts +46 -0
- package/dist/blast/render.d.ts.map +1 -0
- package/dist/blast/render.js +422 -0
- package/dist/blast/render.js.map +1 -0
- package/dist/blast/viz.d.ts +37 -0
- package/dist/blast/viz.d.ts.map +1 -0
- package/dist/blast/viz.js +180 -0
- package/dist/blast/viz.js.map +1 -0
- package/dist/brand.d.ts +111 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +282 -0
- package/dist/brand.js.map +1 -0
- package/dist/claude/build-progress.d.ts +30 -0
- package/dist/claude/build-progress.d.ts.map +1 -0
- package/dist/claude/build-progress.js +81 -0
- package/dist/claude/build-progress.js.map +1 -0
- package/dist/claude/hermes-skill-template.d.ts +16 -0
- package/dist/claude/hermes-skill-template.d.ts.map +1 -0
- package/dist/claude/hermes-skill-template.js +154 -0
- package/dist/claude/hermes-skill-template.js.map +1 -0
- package/dist/claude/init.d.ts +65 -0
- package/dist/claude/init.d.ts.map +1 -0
- package/dist/claude/init.js +258 -0
- package/dist/claude/init.js.map +1 -0
- package/dist/claude/paths.d.ts +9 -0
- package/dist/claude/paths.d.ts.map +1 -0
- package/dist/claude/paths.js +22 -0
- package/dist/claude/paths.js.map +1 -0
- package/dist/claude/session-metrics.d.ts +73 -0
- package/dist/claude/session-metrics.d.ts.map +1 -0
- package/dist/claude/session-metrics.js +209 -0
- package/dist/claude/session-metrics.js.map +1 -0
- package/dist/claude/settings-merge.d.ts +76 -0
- package/dist/claude/settings-merge.d.ts.map +1 -0
- package/dist/claude/settings-merge.js +283 -0
- package/dist/claude/settings-merge.js.map +1 -0
- package/dist/claude/skill-template.d.ts +13 -0
- package/dist/claude/skill-template.d.ts.map +1 -0
- package/dist/claude/skill-template.js +290 -0
- package/dist/claude/skill-template.js.map +1 -0
- package/dist/claude/state.d.ts +85 -0
- package/dist/claude/state.d.ts.map +1 -0
- package/dist/claude/state.js +88 -0
- package/dist/claude/state.js.map +1 -0
- package/dist/claude/stats.d.ts +5 -0
- package/dist/claude/stats.d.ts.map +1 -0
- package/dist/claude/stats.js +24 -0
- package/dist/claude/stats.js.map +1 -0
- package/dist/cli-epilogue.d.ts +12 -0
- package/dist/cli-epilogue.d.ts.map +1 -0
- package/dist/cli-epilogue.js +72 -0
- package/dist/cli-epilogue.js.map +1 -0
- package/dist/cli-meta.d.ts +82 -0
- package/dist/cli-meta.d.ts.map +1 -0
- package/dist/cli-meta.js +238 -0
- package/dist/cli-meta.js.map +1 -0
- package/dist/cli-picker.d.ts +139 -0
- package/dist/cli-picker.d.ts.map +1 -0
- package/dist/cli-picker.js +439 -0
- package/dist/cli-picker.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1638 -0
- package/dist/cli.js.map +1 -0
- package/dist/context/batches.d.ts +29 -0
- package/dist/context/batches.d.ts.map +1 -0
- package/dist/context/batches.js +130 -0
- package/dist/context/batches.js.map +1 -0
- package/dist/context/build.d.ts +57 -0
- package/dist/context/build.d.ts.map +1 -0
- package/dist/context/build.js +396 -0
- package/dist/context/build.js.map +1 -0
- package/dist/context/check.d.ts +42 -0
- package/dist/context/check.d.ts.map +1 -0
- package/dist/context/check.js +162 -0
- package/dist/context/check.js.map +1 -0
- package/dist/context/map-dir.d.ts +13 -0
- package/dist/context/map-dir.d.ts.map +1 -0
- package/dist/context/map-dir.js +81 -0
- package/dist/context/map-dir.js.map +1 -0
- package/dist/context/node-file.d.ts +109 -0
- package/dist/context/node-file.d.ts.map +1 -0
- package/dist/context/node-file.js +390 -0
- package/dist/context/node-file.js.map +1 -0
- package/dist/context/price.d.ts +49 -0
- package/dist/context/price.d.ts.map +1 -0
- package/dist/context/price.js +83 -0
- package/dist/context/price.js.map +1 -0
- package/dist/context/savings.d.ts +67 -0
- package/dist/context/savings.d.ts.map +1 -0
- package/dist/context/savings.js +125 -0
- package/dist/context/savings.js.map +1 -0
- package/dist/engine.d.ts +85 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +122 -0
- package/dist/engine.js.map +1 -0
- package/dist/graph/bindings.d.ts +64 -0
- package/dist/graph/bindings.d.ts.map +1 -0
- package/dist/graph/bindings.js +713 -0
- package/dist/graph/bindings.js.map +1 -0
- package/dist/graph/build-run.d.ts +25 -0
- package/dist/graph/build-run.d.ts.map +1 -0
- package/dist/graph/build-run.js +121 -0
- package/dist/graph/build-run.js.map +1 -0
- package/dist/graph/build.d.ts +88 -0
- package/dist/graph/build.d.ts.map +1 -0
- package/dist/graph/build.js +386 -0
- package/dist/graph/build.js.map +1 -0
- package/dist/graph/cards.d.ts +46 -0
- package/dist/graph/cards.d.ts.map +1 -0
- package/dist/graph/cards.js +280 -0
- package/dist/graph/cards.js.map +1 -0
- package/dist/graph/check.d.ts +25 -0
- package/dist/graph/check.d.ts.map +1 -0
- package/dist/graph/check.js +192 -0
- package/dist/graph/check.js.map +1 -0
- package/dist/graph/container.d.ts +63 -0
- package/dist/graph/container.d.ts.map +1 -0
- package/dist/graph/container.js +191 -0
- package/dist/graph/container.js.map +1 -0
- package/dist/graph/depth-parser.d.ts +61 -0
- package/dist/graph/depth-parser.d.ts.map +1 -0
- package/dist/graph/depth-parser.js +153 -0
- package/dist/graph/depth-parser.js.map +1 -0
- package/dist/graph/enrich.d.ts +62 -0
- package/dist/graph/enrich.d.ts.map +1 -0
- package/dist/graph/enrich.js +258 -0
- package/dist/graph/enrich.js.map +1 -0
- package/dist/graph/extract-cache.d.ts +101 -0
- package/dist/graph/extract-cache.d.ts.map +1 -0
- package/dist/graph/extract-cache.js +199 -0
- package/dist/graph/extract-cache.js.map +1 -0
- package/dist/graph/extract.d.ts +85 -0
- package/dist/graph/extract.d.ts.map +1 -0
- package/dist/graph/extract.js +2377 -0
- package/dist/graph/extract.js.map +1 -0
- package/dist/graph/fingerprint.d.ts +76 -0
- package/dist/graph/fingerprint.d.ts.map +1 -0
- package/dist/graph/fingerprint.js +160 -0
- package/dist/graph/fingerprint.js.map +1 -0
- package/dist/graph/generic.d.ts +74 -0
- package/dist/graph/generic.d.ts.map +1 -0
- package/dist/graph/generic.js +773 -0
- package/dist/graph/generic.js.map +1 -0
- package/dist/graph/invariants.d.ts +33 -0
- package/dist/graph/invariants.d.ts.map +1 -0
- package/dist/graph/invariants.js +52 -0
- package/dist/graph/invariants.js.map +1 -0
- package/dist/graph/load.d.ts +29 -0
- package/dist/graph/load.d.ts.map +1 -0
- package/dist/graph/load.js +97 -0
- package/dist/graph/load.js.map +1 -0
- package/dist/graph/lsp/client.d.ts +61 -0
- package/dist/graph/lsp/client.d.ts.map +1 -0
- package/dist/graph/lsp/client.js +217 -0
- package/dist/graph/lsp/client.js.map +1 -0
- package/dist/graph/lsp/enrich.d.ts +11 -0
- package/dist/graph/lsp/enrich.d.ts.map +1 -0
- package/dist/graph/lsp/enrich.js +163 -0
- package/dist/graph/lsp/enrich.js.map +1 -0
- package/dist/graph/lsp/registry.d.ts +22 -0
- package/dist/graph/lsp/registry.d.ts.map +1 -0
- package/dist/graph/lsp/registry.js +71 -0
- package/dist/graph/lsp/registry.js.map +1 -0
- package/dist/graph/map.d.ts +107 -0
- package/dist/graph/map.d.ts.map +1 -0
- package/dist/graph/map.js +239 -0
- package/dist/graph/map.js.map +1 -0
- package/dist/graph/markdown.d.ts +22 -0
- package/dist/graph/markdown.d.ts.map +1 -0
- package/dist/graph/markdown.js +143 -0
- package/dist/graph/markdown.js.map +1 -0
- package/dist/graph/native.d.ts +46 -0
- package/dist/graph/native.d.ts.map +1 -0
- package/dist/graph/native.js +169 -0
- package/dist/graph/native.js.map +1 -0
- package/dist/graph/queries/c.scm +13 -0
- package/dist/graph/queries/c_sharp.scm +19 -0
- package/dist/graph/queries/clojure.scm +58 -0
- package/dist/graph/queries/cpp.scm +23 -0
- package/dist/graph/queries/dart.scm +42 -0
- package/dist/graph/queries/elixir.scm +54 -0
- package/dist/graph/queries/gleam.scm +51 -0
- package/dist/graph/queries/java.scm +20 -0
- package/dist/graph/queries/kotlin.scm +43 -0
- package/dist/graph/queries/lua.scm +36 -0
- package/dist/graph/queries/nix.scm +32 -0
- package/dist/graph/queries/php.scm +40 -0
- package/dist/graph/queries/ruby.scm +65 -0
- package/dist/graph/queries/rust.scm +41 -0
- package/dist/graph/queries/scala.scm +66 -0
- package/dist/graph/queries/solidity.scm +43 -0
- package/dist/graph/queries/swift.scm +51 -0
- package/dist/graph/refresh.d.ts +106 -0
- package/dist/graph/refresh.d.ts.map +1 -0
- package/dist/graph/refresh.js +430 -0
- package/dist/graph/refresh.js.map +1 -0
- package/dist/graph/relations.d.ts +14 -0
- package/dist/graph/relations.d.ts.map +1 -0
- package/dist/graph/relations.js +8 -0
- package/dist/graph/relations.js.map +1 -0
- package/dist/graph/resolve.d.ts +17 -0
- package/dist/graph/resolve.d.ts.map +1 -0
- package/dist/graph/resolve.js +716 -0
- package/dist/graph/resolve.js.map +1 -0
- package/dist/graph/root.d.ts +11 -0
- package/dist/graph/root.d.ts.map +1 -0
- package/dist/graph/root.js +40 -0
- package/dist/graph/root.js.map +1 -0
- package/dist/graph/scopes.d.ts +40 -0
- package/dist/graph/scopes.d.ts.map +1 -0
- package/dist/graph/scopes.js +383 -0
- package/dist/graph/scopes.js.map +1 -0
- package/dist/graph/seed.d.ts +38 -0
- package/dist/graph/seed.d.ts.map +1 -0
- package/dist/graph/seed.js +229 -0
- package/dist/graph/seed.js.map +1 -0
- package/dist/graph/source-files.d.ts +46 -0
- package/dist/graph/source-files.d.ts.map +1 -0
- package/dist/graph/source-files.js +118 -0
- package/dist/graph/source-files.js.map +1 -0
- package/dist/graph/traverse-cli.d.ts +55 -0
- package/dist/graph/traverse-cli.d.ts.map +1 -0
- package/dist/graph/traverse-cli.js +189 -0
- package/dist/graph/traverse-cli.js.map +1 -0
- package/dist/graph/traverse.d.ts +112 -0
- package/dist/graph/traverse.d.ts.map +1 -0
- package/dist/graph/traverse.js +192 -0
- package/dist/graph/traverse.js.map +1 -0
- package/dist/graph/types.d.ts +78 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +14 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/graph/wasm-runtime.d.ts +19 -0
- package/dist/graph/wasm-runtime.d.ts.map +1 -0
- package/dist/graph/wasm-runtime.js +38 -0
- package/dist/graph/wasm-runtime.js.map +1 -0
- package/dist/graph/workspace-cli.d.ts +56 -0
- package/dist/graph/workspace-cli.d.ts.map +1 -0
- package/dist/graph/workspace-cli.js +111 -0
- package/dist/graph/workspace-cli.js.map +1 -0
- package/dist/graph/workspace.d.ts +172 -0
- package/dist/graph/workspace.d.ts.map +1 -0
- package/dist/graph/workspace.js +714 -0
- package/dist/graph/workspace.js.map +1 -0
- package/dist/graph/write.d.ts +13 -0
- package/dist/graph/write.d.ts.map +1 -0
- package/dist/graph/write.js +86 -0
- package/dist/graph/write.js.map +1 -0
- package/dist/hosts/antigravity.d.ts +14 -0
- package/dist/hosts/antigravity.d.ts.map +1 -0
- package/dist/hosts/antigravity.js +59 -0
- package/dist/hosts/antigravity.js.map +1 -0
- package/dist/hosts/auto.d.ts +37 -0
- package/dist/hosts/auto.d.ts.map +1 -0
- package/dist/hosts/auto.js +141 -0
- package/dist/hosts/auto.js.map +1 -0
- package/dist/hosts/claude-global.d.ts +72 -0
- package/dist/hosts/claude-global.d.ts.map +1 -0
- package/dist/hosts/claude-global.js +230 -0
- package/dist/hosts/claude-global.js.map +1 -0
- package/dist/hosts/config-write.d.ts +36 -0
- package/dist/hosts/config-write.d.ts.map +1 -0
- package/dist/hosts/config-write.js +64 -0
- package/dist/hosts/config-write.js.map +1 -0
- package/dist/hosts/init.d.ts +28 -0
- package/dist/hosts/init.d.ts.map +1 -0
- package/dist/hosts/init.js +89 -0
- package/dist/hosts/init.js.map +1 -0
- package/dist/hosts/instructions.d.ts +14 -0
- package/dist/hosts/instructions.d.ts.map +1 -0
- package/dist/hosts/instructions.js +95 -0
- package/dist/hosts/instructions.js.map +1 -0
- package/dist/hosts/mcp-config.d.ts +78 -0
- package/dist/hosts/mcp-config.d.ts.map +1 -0
- package/dist/hosts/mcp-config.js +251 -0
- package/dist/hosts/mcp-config.js.map +1 -0
- package/dist/hosts/plan.d.ts +32 -0
- package/dist/hosts/plan.d.ts.map +1 -0
- package/dist/hosts/plan.js +73 -0
- package/dist/hosts/plan.js.map +1 -0
- package/dist/hosts/registry.d.ts +41 -0
- package/dist/hosts/registry.d.ts.map +1 -0
- package/dist/hosts/registry.js +164 -0
- package/dist/hosts/registry.js.map +1 -0
- package/dist/hosts/retract.d.ts +47 -0
- package/dist/hosts/retract.d.ts.map +1 -0
- package/dist/hosts/retract.js +520 -0
- package/dist/hosts/retract.js.map +1 -0
- package/dist/hosts/sections.d.ts +47 -0
- package/dist/hosts/sections.d.ts.map +1 -0
- package/dist/hosts/sections.js +127 -0
- package/dist/hosts/sections.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/fs.d.ts +79 -0
- package/dist/ingest/fs.d.ts.map +1 -0
- package/dist/ingest/fs.js +306 -0
- package/dist/ingest/fs.js.map +1 -0
- package/dist/init-guard.d.ts +16 -0
- package/dist/init-guard.d.ts.map +1 -0
- package/dist/init-guard.js +27 -0
- package/dist/init-guard.js.map +1 -0
- package/dist/mcp/instructions.d.ts +5 -0
- package/dist/mcp/instructions.d.ts.map +1 -0
- package/dist/mcp/instructions.js +64 -0
- package/dist/mcp/instructions.js.map +1 -0
- package/dist/mcp/kept-listing.d.ts +27 -0
- package/dist/mcp/kept-listing.d.ts.map +1 -0
- package/dist/mcp/kept-listing.js +63 -0
- package/dist/mcp/kept-listing.js.map +1 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +147 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tool-names.d.ts +27 -0
- package/dist/mcp/tool-names.d.ts.map +1 -0
- package/dist/mcp/tool-names.js +47 -0
- package/dist/mcp/tool-names.js.map +1 -0
- package/dist/mcp/tools.d.ts +22 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +440 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/node-version.d.ts +15 -0
- package/dist/node-version.d.ts.map +1 -0
- package/dist/node-version.js +23 -0
- package/dist/node-version.js.map +1 -0
- package/dist/search/grep-cli.d.ts +35 -0
- package/dist/search/grep-cli.d.ts.map +1 -0
- package/dist/search/grep-cli.js +115 -0
- package/dist/search/grep-cli.js.map +1 -0
- package/dist/search/grep.d.ts +60 -0
- package/dist/search/grep.d.ts.map +1 -0
- package/dist/search/grep.js +143 -0
- package/dist/search/grep.js.map +1 -0
- package/dist/search/ignored-code.d.ts +9 -0
- package/dist/search/ignored-code.d.ts.map +1 -0
- package/dist/search/ignored-code.js +73 -0
- package/dist/search/ignored-code.js.map +1 -0
- package/dist/search/user-regexp.d.ts +26 -0
- package/dist/search/user-regexp.d.ts.map +1 -0
- package/dist/search/user-regexp.js +150 -0
- package/dist/search/user-regexp.js.map +1 -0
- package/dist/telemetry/contract.d.ts +117 -0
- package/dist/telemetry/contract.d.ts.map +1 -0
- package/dist/telemetry/contract.js +341 -0
- package/dist/telemetry/contract.js.map +1 -0
- package/dist/telemetry/flush.d.ts +21 -0
- package/dist/telemetry/flush.d.ts.map +1 -0
- package/dist/telemetry/flush.js +85 -0
- package/dist/telemetry/flush.js.map +1 -0
- package/dist/telemetry/gate.d.ts +30 -0
- package/dist/telemetry/gate.d.ts.map +1 -0
- package/dist/telemetry/gate.js +81 -0
- package/dist/telemetry/gate.js.map +1 -0
- package/dist/telemetry/identity.d.ts +40 -0
- package/dist/telemetry/identity.d.ts.map +1 -0
- package/dist/telemetry/identity.js +80 -0
- package/dist/telemetry/identity.js.map +1 -0
- package/dist/telemetry/index.d.ts +18 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +16 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/key.d.ts +21 -0
- package/dist/telemetry/key.d.ts.map +1 -0
- package/dist/telemetry/key.js +49 -0
- package/dist/telemetry/key.js.map +1 -0
- package/dist/telemetry/notice.d.ts +19 -0
- package/dist/telemetry/notice.d.ts.map +1 -0
- package/dist/telemetry/notice.js +93 -0
- package/dist/telemetry/notice.js.map +1 -0
- package/dist/telemetry/queue.d.ts +35 -0
- package/dist/telemetry/queue.d.ts.map +1 -0
- package/dist/telemetry/queue.js +162 -0
- package/dist/telemetry/queue.js.map +1 -0
- package/dist/telemetry/send.d.ts +19 -0
- package/dist/telemetry/send.d.ts.map +1 -0
- package/dist/telemetry/send.js +84 -0
- package/dist/telemetry/send.js.map +1 -0
- package/dist/telemetry/sessions.d.ts +25 -0
- package/dist/telemetry/sessions.d.ts.map +1 -0
- package/dist/telemetry/sessions.js +104 -0
- package/dist/telemetry/sessions.js.map +1 -0
- package/dist/telemetry/track.d.ts +62 -0
- package/dist/telemetry/track.d.ts.map +1 -0
- package/dist/telemetry/track.js +143 -0
- package/dist/telemetry/track.js.map +1 -0
- package/dist/upkeep-run.d.ts +22 -0
- package/dist/upkeep-run.d.ts.map +1 -0
- package/dist/upkeep-run.js +85 -0
- package/dist/upkeep-run.js.map +1 -0
- package/dist/upkeep.d.ts +127 -0
- package/dist/upkeep.d.ts.map +1 -0
- package/dist/upkeep.js +252 -0
- package/dist/upkeep.js.map +1 -0
- package/dist/util/actions-folder.d.ts +2 -0
- package/dist/util/actions-folder.d.ts.map +1 -0
- package/dist/util/actions-folder.js +9 -0
- package/dist/util/actions-folder.js.map +1 -0
- package/dist/util/browser.d.ts +3 -0
- package/dist/util/browser.d.ts.map +1 -0
- package/dist/util/browser.js +14 -0
- package/dist/util/browser.js.map +1 -0
- package/dist/util/child-process.d.ts +15 -0
- package/dist/util/child-process.d.ts.map +1 -0
- package/dist/util/child-process.js +15 -0
- package/dist/util/child-process.js.map +1 -0
- package/dist/util/front-matter.d.ts +46 -0
- package/dist/util/front-matter.d.ts.map +1 -0
- package/dist/util/front-matter.js +113 -0
- package/dist/util/front-matter.js.map +1 -0
- package/dist/util/id.d.ts +7 -0
- package/dist/util/id.d.ts.map +1 -0
- package/dist/util/id.js +14 -0
- package/dist/util/id.js.map +1 -0
- package/dist/util/paths.d.ts +29 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +71 -0
- package/dist/util/paths.js.map +1 -0
- package/dist/util/private-file.d.ts +14 -0
- package/dist/util/private-file.d.ts.map +1 -0
- package/dist/util/private-file.js +82 -0
- package/dist/util/private-file.js.map +1 -0
- package/dist/util/source.d.ts +4 -0
- package/dist/util/source.d.ts.map +1 -0
- package/dist/util/source.js +12 -0
- package/dist/util/source.js.map +1 -0
- package/dist/util/spinner.d.ts +15 -0
- package/dist/util/spinner.d.ts.map +1 -0
- package/dist/util/spinner.js +52 -0
- package/dist/util/spinner.js.map +1 -0
- package/dist/util/state.d.ts +120 -0
- package/dist/util/state.d.ts.map +1 -0
- package/dist/util/state.js +264 -0
- package/dist/util/state.js.map +1 -0
- package/dist/vendor/grammars/tree-sitter-go.LICENSE +21 -0
- package/dist/vendor/grammars/tree-sitter-go.wasm +0 -0
- package/dist/vendor/grammars/tree-sitter-java.LICENSE +21 -0
- package/dist/vendor/grammars/tree-sitter-java.wasm +0 -0
- package/dist/vendor/grammars/tree-sitter-kotlin.LICENSE +9 -0
- package/dist/vendor/grammars/tree-sitter-kotlin.wasm +0 -0
- package/dist/vendor/grammars/tree-sitter-php.LICENSE +22 -0
- package/dist/vendor/grammars/tree-sitter-php.wasm +0 -0
- package/dist/vendor/grammars/tree-sitter-python.LICENSE +21 -0
- package/dist/vendor/grammars/tree-sitter-python.wasm +0 -0
- package/dist/vendor/grammars/tree-sitter-r.LICENSE +9 -0
- package/dist/vendor/grammars/tree-sitter-r.wasm +0 -0
- package/dist/vendor/grammars/tree-sitter-swift.LICENSE +21 -0
- package/dist/vendor/grammars/tree-sitter-swift.wasm +0 -0
- package/dist/vendor/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/vendor/grammars/tree-sitter-typescript.LICENSE +21 -0
- package/dist/vendor/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/viewer/app.js +2 -0
- package/dist/viewer/index.html +49 -0
- package/dist/viewer/style.css +154 -0
- package/dist/viz/assemble.d.ts +83 -0
- package/dist/viz/assemble.d.ts.map +1 -0
- package/dist/viz/assemble.js +101 -0
- package/dist/viz/assemble.js.map +1 -0
- package/dist/viz/export.d.ts +39 -0
- package/dist/viz/export.d.ts.map +1 -0
- package/dist/viz/export.js +98 -0
- package/dist/viz/export.js.map +1 -0
- package/dist/viz/serve.d.ts +13 -0
- package/dist/viz/serve.d.ts.map +1 -0
- package/dist/viz/serve.js +130 -0
- package/dist/viz/serve.js.map +1 -0
- package/package.json +115 -4
- package/scripts/build-grammar-wasm.mjs +112 -0
- package/scripts/build-viewer.mjs +44 -0
- package/scripts/graph-quality.mjs +117 -0
- package/scripts/pack-trail.mjs +53 -0
- package/scripts/postinstall.mjs +65 -0
- package/scripts/run-tests.mjs +72 -0
- package/scripts/stamp-telemetry-key.mjs +56 -0
- package/scripts/tally-audit.mjs +140 -0
- package/scripts/vendor-grammars.mjs +53 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { WALK_RELATIONS } from "../graph/relations.js";
|
|
2
|
+
const emptyTopology = () => ({
|
|
3
|
+
ids: new Set(),
|
|
4
|
+
adjacency: new Map(),
|
|
5
|
+
});
|
|
6
|
+
const link = (adjacency, source, target) => {
|
|
7
|
+
const neighbours = adjacency.get(source);
|
|
8
|
+
if (neighbours)
|
|
9
|
+
neighbours.push(target);
|
|
10
|
+
else
|
|
11
|
+
adjacency.set(source, [target]);
|
|
12
|
+
};
|
|
13
|
+
/** Build independent PageRank topologies in one node pass and one edge pass.
|
|
14
|
+
* Edges crossing partitions are excluded, exactly like applying a nodeFilter
|
|
15
|
+
* for each partition independently. Returning `undefined` omits a node. */
|
|
16
|
+
export function preparePageRankPartitions(graph, partitionOfId) {
|
|
17
|
+
const partitionById = new Map();
|
|
18
|
+
const mutable = new Map();
|
|
19
|
+
for (const node of graph.nodes) {
|
|
20
|
+
const partition = partitionOfId(node.id);
|
|
21
|
+
if (partition === undefined)
|
|
22
|
+
continue;
|
|
23
|
+
partitionById.set(node.id, partition);
|
|
24
|
+
const topology = mutable.get(partition);
|
|
25
|
+
if (topology)
|
|
26
|
+
topology.ids.add(node.id);
|
|
27
|
+
else
|
|
28
|
+
mutable.set(partition, { ids: new Set([node.id]), adjacency: new Map() });
|
|
29
|
+
}
|
|
30
|
+
for (const edge of graph.edges) {
|
|
31
|
+
if (!WALK_RELATIONS.has(edge.relation))
|
|
32
|
+
continue;
|
|
33
|
+
const partition = partitionById.get(edge.source);
|
|
34
|
+
if (partition === undefined || partitionById.get(edge.target) !== partition)
|
|
35
|
+
continue;
|
|
36
|
+
const topology = mutable.get(partition);
|
|
37
|
+
link(topology.adjacency, edge.source, edge.target);
|
|
38
|
+
link(topology.adjacency, edge.target, edge.source);
|
|
39
|
+
}
|
|
40
|
+
return new Map(mutable);
|
|
41
|
+
}
|
|
42
|
+
/** Prepare one optionally filtered topology. Kept public for callers/tests that
|
|
43
|
+
* reuse the same graph across multiple seed sets. */
|
|
44
|
+
export function preparePageRankTopology(graph, nodeFilter) {
|
|
45
|
+
const ids = new Set(graph.nodes.map((node) => node.id).filter((id) => !nodeFilter || nodeFilter(id)));
|
|
46
|
+
if (ids.size === 0)
|
|
47
|
+
return emptyTopology();
|
|
48
|
+
const adjacency = new Map();
|
|
49
|
+
for (const edge of graph.edges) {
|
|
50
|
+
if (!WALK_RELATIONS.has(edge.relation))
|
|
51
|
+
continue;
|
|
52
|
+
if (!ids.has(edge.source) || !ids.has(edge.target))
|
|
53
|
+
continue;
|
|
54
|
+
link(adjacency, edge.source, edge.target);
|
|
55
|
+
link(adjacency, edge.target, edge.source);
|
|
56
|
+
}
|
|
57
|
+
return { ids, adjacency };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Personalized PageRank over the wiring graph.
|
|
61
|
+
*
|
|
62
|
+
* `seeds` maps node id → restart weight (a node's lexical score; only positive
|
|
63
|
+
* weights matter). The graph is treated as UNDIRECTED — for "understand this
|
|
64
|
+
* area" a callee is as relevant as a caller. Returns a score per node
|
|
65
|
+
* normalized so the top node is 1; nodes untouched by the walk are absent.
|
|
66
|
+
*
|
|
67
|
+
* Edges whose endpoints aren't both real nodes (e.g. an unresolved import
|
|
68
|
+
* module string) are ignored, so only genuine symbol-to-symbol wiring counts.
|
|
69
|
+
*/
|
|
70
|
+
export function personalizedPageRank(graph, seeds, opts = {}) {
|
|
71
|
+
return personalizedPageRankPrepared(preparePageRankTopology(graph, opts.nodeFilter), seeds, opts);
|
|
72
|
+
}
|
|
73
|
+
/** Run PageRank on an already prepared topology. This is numerically identical
|
|
74
|
+
* to {@link personalizedPageRank}; it only removes repeated topology scans. */
|
|
75
|
+
export function personalizedPageRankPrepared(topology, seeds, opts = {}) {
|
|
76
|
+
const alpha = opts.alpha ?? 0.25;
|
|
77
|
+
const iters = opts.iters ?? 25;
|
|
78
|
+
const ids = topology.ids;
|
|
79
|
+
const adjacency = topology.adjacency;
|
|
80
|
+
// Restart distribution: seed weights, restricted to real nodes, normalized.
|
|
81
|
+
let seedTotal = 0;
|
|
82
|
+
for (const [id, w] of seeds)
|
|
83
|
+
if (ids.has(id) && w > 0)
|
|
84
|
+
seedTotal += w;
|
|
85
|
+
if (seedTotal <= 0)
|
|
86
|
+
return new Map();
|
|
87
|
+
const restart = new Map();
|
|
88
|
+
for (const [id, w] of seeds)
|
|
89
|
+
if (ids.has(id) && w > 0)
|
|
90
|
+
restart.set(id, w / seedTotal);
|
|
91
|
+
// Power iteration from the restart distribution.
|
|
92
|
+
let rank = new Map(restart);
|
|
93
|
+
for (let i = 0; i < iters; i++) {
|
|
94
|
+
const next = new Map();
|
|
95
|
+
// Teleport: every step, alpha of the mass returns to the seed set.
|
|
96
|
+
for (const [id, r] of restart)
|
|
97
|
+
next.set(id, alpha * r);
|
|
98
|
+
// Dangling mass (nodes with no walk edges) is pooled and returned to the
|
|
99
|
+
// seed set ONCE per iteration — same math as redistributing per node, but
|
|
100
|
+
// O(nodes + seeds) instead of O(dangling × seeds).
|
|
101
|
+
let dangling = 0;
|
|
102
|
+
for (const [id, mass] of rank) {
|
|
103
|
+
const nbrs = adjacency.get(id);
|
|
104
|
+
if (!nbrs || nbrs.length === 0) {
|
|
105
|
+
dangling += mass;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const share = ((1 - alpha) * mass) / nbrs.length;
|
|
109
|
+
for (const nb of nbrs)
|
|
110
|
+
next.set(nb, (next.get(nb) ?? 0) + share);
|
|
111
|
+
}
|
|
112
|
+
if (dangling > 0) {
|
|
113
|
+
const dm = (1 - alpha) * dangling;
|
|
114
|
+
for (const [sid, r] of restart)
|
|
115
|
+
next.set(sid, (next.get(sid) ?? 0) + dm * r);
|
|
116
|
+
}
|
|
117
|
+
rank = next;
|
|
118
|
+
}
|
|
119
|
+
let max = 0;
|
|
120
|
+
for (const v of rank.values())
|
|
121
|
+
if (v > max)
|
|
122
|
+
max = v;
|
|
123
|
+
if (max <= 0)
|
|
124
|
+
return new Map();
|
|
125
|
+
const out = new Map();
|
|
126
|
+
for (const [id, v] of rank)
|
|
127
|
+
out.set(id, v / max);
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=graphrank.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphrank.js","sourceRoot":"","sources":["../../src/ask/graphrank.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { GraphV1 } from "../graph/types.js";
|
|
2
|
+
/** Split prose + identifiers into lowercased subword tokens (camelCase, snake, kebab).
|
|
3
|
+
* The single source of truth for tokenization — shared by build-time indexing
|
|
4
|
+
* (this file) and query-time fallback (`ask.ts`) so the sidecar is a provably
|
|
5
|
+
* exact cache of the live path. */
|
|
6
|
+
export declare function tokenize(text: string): string[];
|
|
7
|
+
/** Term-frequency count map. */
|
|
8
|
+
export declare function counts(tokens: string[]): Map<string, number>;
|
|
9
|
+
/** One node's token bags, JSON-friendly (`Map` → sorted `[token, count][]`). */
|
|
10
|
+
export interface AskIndexDoc {
|
|
11
|
+
id: string;
|
|
12
|
+
name: [string, number][];
|
|
13
|
+
path: [string, number][];
|
|
14
|
+
body: [string, number][];
|
|
15
|
+
}
|
|
16
|
+
/** The build-time sidecar. `df`/`docCount` cover symbol+file nodes only (no
|
|
17
|
+
* concepts — see module docstring); `avgBodyLen` is the BM25 corpus average. */
|
|
18
|
+
export interface AskIndex {
|
|
19
|
+
version: 1;
|
|
20
|
+
avgBodyLen: number;
|
|
21
|
+
df: [string, number][];
|
|
22
|
+
docCount: number;
|
|
23
|
+
docs: AskIndexDoc[];
|
|
24
|
+
}
|
|
25
|
+
export declare const ASK_INDEX_FILE = "ask-index.json";
|
|
26
|
+
/** Absolute path to the ask sidecar for a context dir: `<dir>/.cache/ask-index.json`.
|
|
27
|
+
* `.cache/` is the established uncommitted-cache location — this sidecar is a
|
|
28
|
+
* derived, regenerate-anytime cache, not checked-in graph data. */
|
|
29
|
+
export declare function askIndexPath(outDir: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Tokenize every node in `graph` (exactly as `ask.ts`'s lexical pass does) and
|
|
32
|
+
* write the resulting bags + document frequencies to
|
|
33
|
+
* `<outDir>/.cache/ask-index.json`. Returns the path written. Deterministic:
|
|
34
|
+
* nodes are indexed in id order, so an unchanged graph produces a
|
|
35
|
+
* byte-identical sidecar.
|
|
36
|
+
*/
|
|
37
|
+
export declare function writeAskIndex(outDir: string, graph: GraphV1): string;
|
|
38
|
+
/** Read the ask sidecar. Returns null on a missing file, unparseable JSON, an
|
|
39
|
+
* unrecognized shape, an unknown `version`, or a `docCount` that doesn't match
|
|
40
|
+
* the number of docs actually stored (a corrupted/truncated sidecar would
|
|
41
|
+
* otherwise silently skew IDF) — any of which means the caller should fall
|
|
42
|
+
* back to live tokenization, never crash or trust bad data. */
|
|
43
|
+
export declare function readAskIndex(outDir: string): AskIndex | null;
|
|
44
|
+
//# sourceMappingURL=index-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-file.d.ts","sourceRoot":"","sources":["../../src/ask/index-file.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAUjD;;;mCAGmC;AACnC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAM/C;AAED,gCAAgC;AAChC,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAI5D;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACzB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACzB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAC1B;AAED;gFACgF;AAChF,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,WAAW,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C;;mEAEmE;AACnE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAaD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAiCpE;AAED;;;;+DAI+D;AAC/D,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqB5D"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time sidecar for `graft ask` — `<outDir>/.cache/ask-index.json`.
|
|
3
|
+
*
|
|
4
|
+
* `ask`'s lexical pass tokenizes every symbol node's name/path/body on every
|
|
5
|
+
* query; at 32k nodes that re-tokenization is ~45% of query time (profiled).
|
|
6
|
+
* `graft build` writes this sidecar once, with the token→count bags per node
|
|
7
|
+
* plus the corpus-wide document frequencies, so a query just reads counts
|
|
8
|
+
* instead of re-splitting every node's text. It's a derived cache, not
|
|
9
|
+
* checked-in graph data, so it lives under the gitignored `.cache/` dir
|
|
10
|
+
* (see `CACHE_DIR` in `context/node-file.ts`) rather than `.graph/`.
|
|
11
|
+
*
|
|
12
|
+
* `tokenize`/`counts` live here (not duplicated in `ask.ts`) so build-time and
|
|
13
|
+
* query-time text-splitting are provably the same function — the sidecar can
|
|
14
|
+
* only be a correct cache of `ask.ts`'s own math if both sides call the same
|
|
15
|
+
* code. `ask.ts` imports both back from here.
|
|
16
|
+
*
|
|
17
|
+
* Concept (markdown) docs are NOT part of this sidecar — there are only dozens
|
|
18
|
+
* of them, they're still tokenized live at query time, and their doc-frequency
|
|
19
|
+
* contribution is folded into the stored `df` at query time (see `ask.ts`),
|
|
20
|
+
* which is why `df` here counts symbol/file nodes only.
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
23
|
+
import { dirname, join } from "node:path";
|
|
24
|
+
import { CACHE_DIR } from "../context/node-file.js";
|
|
25
|
+
/** Words too common/short to carry query intent — dropped before scoring. */
|
|
26
|
+
const STOP = new Set([
|
|
27
|
+
"the", "a", "an", "of", "to", "in", "is", "are", "how", "does", "do", "what",
|
|
28
|
+
"where", "which", "that", "this", "it", "for", "on", "and", "or", "with",
|
|
29
|
+
"i", "we", "get", "set", "use", "used", "using", "when", "why", "can",
|
|
30
|
+
]);
|
|
31
|
+
/** Split prose + identifiers into lowercased subword tokens (camelCase, snake, kebab).
|
|
32
|
+
* The single source of truth for tokenization — shared by build-time indexing
|
|
33
|
+
* (this file) and query-time fallback (`ask.ts`) so the sidecar is a provably
|
|
34
|
+
* exact cache of the live path. */
|
|
35
|
+
export function tokenize(text) {
|
|
36
|
+
return text
|
|
37
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2") // camelCase → camel Case
|
|
38
|
+
.toLowerCase()
|
|
39
|
+
.split(/[^a-z0-9]+/)
|
|
40
|
+
.filter((t) => t.length > 1 && !STOP.has(t));
|
|
41
|
+
}
|
|
42
|
+
/** Term-frequency count map. */
|
|
43
|
+
export function counts(tokens) {
|
|
44
|
+
const m = new Map();
|
|
45
|
+
for (const t of tokens)
|
|
46
|
+
m.set(t, (m.get(t) ?? 0) + 1);
|
|
47
|
+
return m;
|
|
48
|
+
}
|
|
49
|
+
export const ASK_INDEX_FILE = "ask-index.json";
|
|
50
|
+
/** Absolute path to the ask sidecar for a context dir: `<dir>/.cache/ask-index.json`.
|
|
51
|
+
* `.cache/` is the established uncommitted-cache location — this sidecar is a
|
|
52
|
+
* derived, regenerate-anytime cache, not checked-in graph data. */
|
|
53
|
+
export function askIndexPath(outDir) {
|
|
54
|
+
return join(outDir, CACHE_DIR, ASK_INDEX_FILE);
|
|
55
|
+
}
|
|
56
|
+
function pairs(m) {
|
|
57
|
+
return [...m.entries()];
|
|
58
|
+
}
|
|
59
|
+
/** Sum of a token→count bag's counts (a document's field length). */
|
|
60
|
+
function bagLen(p) {
|
|
61
|
+
let s = 0;
|
|
62
|
+
for (const [, c] of p)
|
|
63
|
+
s += c;
|
|
64
|
+
return s;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Tokenize every node in `graph` (exactly as `ask.ts`'s lexical pass does) and
|
|
68
|
+
* write the resulting bags + document frequencies to
|
|
69
|
+
* `<outDir>/.cache/ask-index.json`. Returns the path written. Deterministic:
|
|
70
|
+
* nodes are indexed in id order, so an unchanged graph produces a
|
|
71
|
+
* byte-identical sidecar.
|
|
72
|
+
*/
|
|
73
|
+
export function writeAskIndex(outDir, graph) {
|
|
74
|
+
const nodes = [...graph.nodes].sort((a, b) => a.id.localeCompare(b.id));
|
|
75
|
+
const docs = [];
|
|
76
|
+
const df = new Map();
|
|
77
|
+
for (const n of nodes) {
|
|
78
|
+
const name = counts(tokenize(n.name));
|
|
79
|
+
const path = counts(tokenize(n.path));
|
|
80
|
+
const body = counts(tokenize(`${n.signature ?? ""} ${n.summary ?? ""} ${n.body_text ?? ""}`));
|
|
81
|
+
docs.push({ id: n.id, name: pairs(name), path: pairs(path), body: pairs(body) });
|
|
82
|
+
const bag = new Set([...name.keys(), ...path.keys(), ...body.keys()]);
|
|
83
|
+
for (const t of bag)
|
|
84
|
+
df.set(t, (df.get(t) ?? 0) + 1);
|
|
85
|
+
}
|
|
86
|
+
const avgBodyLen = docs.length
|
|
87
|
+
? docs.reduce((a, d) => a + bagLen(d.body), 0) / docs.length
|
|
88
|
+
: 0;
|
|
89
|
+
const index = {
|
|
90
|
+
version: 1,
|
|
91
|
+
avgBodyLen,
|
|
92
|
+
df: pairs(df),
|
|
93
|
+
docCount: nodes.length,
|
|
94
|
+
docs,
|
|
95
|
+
};
|
|
96
|
+
const outPath = askIndexPath(outDir);
|
|
97
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
98
|
+
writeFileSync(outPath, JSON.stringify(index) + "\n");
|
|
99
|
+
return outPath;
|
|
100
|
+
}
|
|
101
|
+
/** Read the ask sidecar. Returns null on a missing file, unparseable JSON, an
|
|
102
|
+
* unrecognized shape, an unknown `version`, or a `docCount` that doesn't match
|
|
103
|
+
* the number of docs actually stored (a corrupted/truncated sidecar would
|
|
104
|
+
* otherwise silently skew IDF) — any of which means the caller should fall
|
|
105
|
+
* back to live tokenization, never crash or trust bad data. */
|
|
106
|
+
export function readAskIndex(outDir) {
|
|
107
|
+
const path = askIndexPath(outDir);
|
|
108
|
+
if (!existsSync(path))
|
|
109
|
+
return null;
|
|
110
|
+
try {
|
|
111
|
+
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
112
|
+
if (!raw ||
|
|
113
|
+
typeof raw !== "object" ||
|
|
114
|
+
raw.version !== 1 ||
|
|
115
|
+
typeof raw.docCount !== "number" ||
|
|
116
|
+
typeof raw.avgBodyLen !== "number" ||
|
|
117
|
+
!Array.isArray(raw.df) ||
|
|
118
|
+
!Array.isArray(raw.docs) ||
|
|
119
|
+
raw.docCount !== raw.docs.length) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return raw;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=index-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-file.js","sourceRoot":"","sources":["../../src/ask/index-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { NodeV1 } from '../graph/types.js';
|
|
2
|
+
export interface SemanticHit {
|
|
3
|
+
node_id: string;
|
|
4
|
+
file_path: string;
|
|
5
|
+
symbol: string;
|
|
6
|
+
score: number;
|
|
7
|
+
snippet: string;
|
|
8
|
+
}
|
|
9
|
+
/** The embedding model used. Changing this invalidates all existing DBs (different dimensions). */
|
|
10
|
+
export declare const EMBED_MODEL = "Xenova/all-mpnet-base-v2";
|
|
11
|
+
/** Vector dimensions for the current model. MiniLM-L6=384, mpnet-base=768. */
|
|
12
|
+
export declare const EMBED_DIM = 768;
|
|
13
|
+
/**
|
|
14
|
+
* Inject a fake embedder for tests — bypasses the 87 MB model download.
|
|
15
|
+
* Call with `null` to restore the real pipeline.
|
|
16
|
+
*/
|
|
17
|
+
export declare function _setEmbedderForTest(fn: ((text: string) => Float32Array) | null): void;
|
|
18
|
+
/**
|
|
19
|
+
* Embed all nodes in `nodes` and store them in the sqlite-vec database at
|
|
20
|
+
* `dbPath`. Idempotent: if the DB already contains rows, the function returns
|
|
21
|
+
* immediately without re-embedding.
|
|
22
|
+
*
|
|
23
|
+
* Called from the `graft_search_semantic` MCP tool handler (and optionally
|
|
24
|
+
* from the build pipeline) to pre-populate the vector store.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Embed nodes and store them in the sqlite-vec database at `dbPath`.
|
|
28
|
+
*
|
|
29
|
+
* Incremental: compares each node's `body_hash` against what is already stored.
|
|
30
|
+
* Only new or changed nodes are re-embedded; deleted nodes are removed.
|
|
31
|
+
* Unchanged nodes are left untouched, making repeated calls cheap.
|
|
32
|
+
*/
|
|
33
|
+
export declare function embedNodes(nodes: NodeV1[], dbPath: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Embed `query`, find the top-`limit` nearest nodes in the vector store, and
|
|
36
|
+
* return them with cosine similarity scores.
|
|
37
|
+
*
|
|
38
|
+
* Throws if the DB does not exist or contains no embeddings (call `embedNodes`
|
|
39
|
+
* first, or use the MCP tool which calls it automatically).
|
|
40
|
+
*/
|
|
41
|
+
export declare function searchSemantic(query: string, dbPath: string, limit?: number): Promise<SemanticHit[]>;
|
|
42
|
+
//# sourceMappingURL=semantic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/ask/semantic.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAShD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AA8BD,mGAAmG;AACnG,eAAO,MAAM,WAAW,6BAA6B,CAAC;AACtD,8EAA8E;AAC9E,eAAO,MAAM,SAAS,MAAM,CAAC;AAE7B;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,YAAY,CAAC,GAAG,IAAI,GAAG,IAAI,CAIrF;AA0FD;;;;;;;GAOG;AACH;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4H/E;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,SAAI,GACR,OAAO,CAAC,WAAW,EAAE,CAAC,CAqDxB"}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic search over the code graph using @huggingface/transformers embeddings
|
|
3
|
+
* and sqlite-vec for approximate nearest-neighbour retrieval.
|
|
4
|
+
*
|
|
5
|
+
* Spike 003 — Trail-Code fork integration.
|
|
6
|
+
* Validated building blocks: Spike 001 (embeddings) + Spike 002 (sqlite-vec).
|
|
7
|
+
*/
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { mkdirSync, existsSync } from 'node:fs';
|
|
10
|
+
import { dirname } from 'node:path';
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
// Use createRequire so CJS native modules load cleanly from this ESM file.
|
|
13
|
+
const _require = createRequire(import.meta.url);
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Internals
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
/** Normalise a Float32Array to unit length (required for cosine sim via L2). */
|
|
18
|
+
function normalize(vec) {
|
|
19
|
+
let sum = 0;
|
|
20
|
+
for (const v of vec)
|
|
21
|
+
sum += v * v;
|
|
22
|
+
const norm = Math.sqrt(sum);
|
|
23
|
+
if (norm === 0)
|
|
24
|
+
return vec;
|
|
25
|
+
const out = new Float32Array(vec.length);
|
|
26
|
+
for (let i = 0; i < vec.length; i++)
|
|
27
|
+
out[i] = vec[i] / norm;
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
/** Convert Float32Array → Buffer so better-sqlite3 accepts it as a blob. */
|
|
31
|
+
function vecToBuffer(arr) {
|
|
32
|
+
return Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
33
|
+
}
|
|
34
|
+
// Module-level pipeline cache — one warm-up per process.
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
let _extractor = null;
|
|
37
|
+
// Test-only override: replaces the real pipeline with a fake embedder.
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
let _testEmbedder = null;
|
|
40
|
+
/** The embedding model used. Changing this invalidates all existing DBs (different dimensions). */
|
|
41
|
+
export const EMBED_MODEL = 'Xenova/all-mpnet-base-v2';
|
|
42
|
+
/** Vector dimensions for the current model. MiniLM-L6=384, mpnet-base=768. */
|
|
43
|
+
export const EMBED_DIM = 768;
|
|
44
|
+
/**
|
|
45
|
+
* Inject a fake embedder for tests — bypasses the 87 MB model download.
|
|
46
|
+
* Call with `null` to restore the real pipeline.
|
|
47
|
+
*/
|
|
48
|
+
export function _setEmbedderForTest(fn) {
|
|
49
|
+
_testEmbedder = fn;
|
|
50
|
+
// Also reset the cached extractor so it re-evaluates on the next call.
|
|
51
|
+
_extractor = null;
|
|
52
|
+
}
|
|
53
|
+
async function getExtractor() {
|
|
54
|
+
if (_testEmbedder)
|
|
55
|
+
return _testEmbedder;
|
|
56
|
+
if (_extractor)
|
|
57
|
+
return _extractor;
|
|
58
|
+
// Dynamic import keeps @huggingface/transformers tree-shakeable and avoids
|
|
59
|
+
// loading ONNX during non-semantic code paths.
|
|
60
|
+
const { pipeline, env } = await import('@huggingface/transformers');
|
|
61
|
+
// Point the model cache at a stable location outside node_modules so it
|
|
62
|
+
// survives npm ci / reinstalls (matches Spike 001 recommendation).
|
|
63
|
+
const home = process.env['USERPROFILE'] ?? process.env['HOME'] ?? '.';
|
|
64
|
+
env.cacheDir = `${home}/.cache/huggingface/transformers`;
|
|
65
|
+
_extractor = await pipeline('feature-extraction', EMBED_MODEL, { dtype: 'fp32' });
|
|
66
|
+
return _extractor;
|
|
67
|
+
}
|
|
68
|
+
/** Embed a batch of texts → unit-normalised float32 vectors (EMBED_DIM dimensions). */
|
|
69
|
+
async function embedTexts(texts) {
|
|
70
|
+
const extractor = await getExtractor();
|
|
71
|
+
const results = [];
|
|
72
|
+
for (const text of texts) {
|
|
73
|
+
if (_testEmbedder) {
|
|
74
|
+
// Test path: call the fake embedder directly and normalize.
|
|
75
|
+
results.push(normalize((_testEmbedder)(text)));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
|
+
const output = await extractor(text, { pooling: 'mean', normalize: false });
|
|
80
|
+
results.push(normalize(output.data));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
/** Open (or create) the SQLite db file and load the sqlite-vec extension. */
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
+
function openDb(dbPath) {
|
|
88
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
89
|
+
const Database = _require('better-sqlite3');
|
|
90
|
+
const sqliteVec = _require('sqlite-vec');
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
+
const db = new Database(dbPath);
|
|
93
|
+
sqliteVec.load(db);
|
|
94
|
+
return db;
|
|
95
|
+
}
|
|
96
|
+
/** Idempotent schema setup (IF NOT EXISTS on every statement). */
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
98
|
+
function initSchema(db) {
|
|
99
|
+
db.exec(`
|
|
100
|
+
CREATE TABLE IF NOT EXISTS embed_nodes (
|
|
101
|
+
rowid INTEGER PRIMARY KEY,
|
|
102
|
+
node_id TEXT NOT NULL,
|
|
103
|
+
file_path TEXT NOT NULL,
|
|
104
|
+
symbol TEXT NOT NULL,
|
|
105
|
+
snippet TEXT NOT NULL,
|
|
106
|
+
body_hash TEXT
|
|
107
|
+
);
|
|
108
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS vss_nodes
|
|
109
|
+
USING vec0(embedding float[${EMBED_DIM}]);
|
|
110
|
+
CREATE TABLE IF NOT EXISTS embed_meta (
|
|
111
|
+
key TEXT PRIMARY KEY,
|
|
112
|
+
value TEXT NOT NULL
|
|
113
|
+
);
|
|
114
|
+
`);
|
|
115
|
+
// Migrate older DBs that lack body_hash column (ALTER TABLE is safe if column exists).
|
|
116
|
+
try {
|
|
117
|
+
db.exec(`ALTER TABLE embed_nodes ADD COLUMN body_hash TEXT`);
|
|
118
|
+
}
|
|
119
|
+
catch { /* already exists */ }
|
|
120
|
+
// Detect model change: if stored model differs OR is absent with existing embeddings, wipe and rebuild.
|
|
121
|
+
const storedModel = db.prepare("SELECT value FROM embed_meta WHERE key = 'embed_model'").get()?.value;
|
|
122
|
+
const { c: existingCount } = db.prepare('SELECT COUNT(*) AS c FROM embed_nodes').get();
|
|
123
|
+
if (storedModel !== EMBED_MODEL && existingCount > 0) {
|
|
124
|
+
const reason = storedModel ? `${storedModel} → ${EMBED_MODEL}` : `migrating to ${EMBED_MODEL}`;
|
|
125
|
+
process.stderr.write(`[semantic] model changed (${reason}) — will rebuild\n`);
|
|
126
|
+
return true; // signal caller to delete and reopen
|
|
127
|
+
}
|
|
128
|
+
// Always store current model name.
|
|
129
|
+
db.prepare("INSERT INTO embed_meta (key, value) VALUES ('embed_model', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(EMBED_MODEL);
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
/** Compute a stable SHA-256 hash over all node IDs (sorted). */
|
|
133
|
+
function graphHash(nodes) {
|
|
134
|
+
const sorted = nodes.map(n => n.id).sort().join(',');
|
|
135
|
+
return createHash('sha256').update(sorted).digest('hex');
|
|
136
|
+
}
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Public API
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
/**
|
|
141
|
+
* Embed all nodes in `nodes` and store them in the sqlite-vec database at
|
|
142
|
+
* `dbPath`. Idempotent: if the DB already contains rows, the function returns
|
|
143
|
+
* immediately without re-embedding.
|
|
144
|
+
*
|
|
145
|
+
* Called from the `graft_search_semantic` MCP tool handler (and optionally
|
|
146
|
+
* from the build pipeline) to pre-populate the vector store.
|
|
147
|
+
*/
|
|
148
|
+
/**
|
|
149
|
+
* Embed nodes and store them in the sqlite-vec database at `dbPath`.
|
|
150
|
+
*
|
|
151
|
+
* Incremental: compares each node's `body_hash` against what is already stored.
|
|
152
|
+
* Only new or changed nodes are re-embedded; deleted nodes are removed.
|
|
153
|
+
* Unchanged nodes are left untouched, making repeated calls cheap.
|
|
154
|
+
*/
|
|
155
|
+
export async function embedNodes(nodes, dbPath) {
|
|
156
|
+
let db = openDb(dbPath);
|
|
157
|
+
const needsRebuild = initSchema(db);
|
|
158
|
+
if (needsRebuild) {
|
|
159
|
+
// Model changed — delete DB file and recreate fresh (safest way to change vss_nodes dimensions).
|
|
160
|
+
db.close();
|
|
161
|
+
const { unlinkSync } = await import('node:fs');
|
|
162
|
+
unlinkSync(dbPath);
|
|
163
|
+
db = openDb(dbPath);
|
|
164
|
+
initSchema(db);
|
|
165
|
+
}
|
|
166
|
+
// Guard: nothing to embed — skip silently (0 nodes is valid for .md-only repos
|
|
167
|
+
// that haven't enabled --include-md, or empty workspace children like openspec/).
|
|
168
|
+
if (nodes.length === 0) {
|
|
169
|
+
db.close();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const currentHash = graphHash(nodes);
|
|
173
|
+
// Fast path: graph hash unchanged → index is fresh.
|
|
174
|
+
const stored = db.prepare("SELECT value FROM embed_meta WHERE key = 'graph_hash'").get();
|
|
175
|
+
if (stored?.value === currentHash) {
|
|
176
|
+
const { c } = db.prepare('SELECT COUNT(*) AS c FROM embed_nodes').get();
|
|
177
|
+
process.stderr.write(`[semantic] ${c} embeddings already in DB, fresh (hash match) — skipping re-embed\n`);
|
|
178
|
+
db.close();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// Incremental path: compute per-node diff using body_hash.
|
|
182
|
+
const existingRows = db.prepare('SELECT node_id, body_hash FROM embed_nodes').all();
|
|
183
|
+
const existingMap = new Map(existingRows.map(r => [r.node_id, r.body_hash ?? '']));
|
|
184
|
+
const incomingSet = new Set(nodes.map(n => n.id));
|
|
185
|
+
// Nodes to remove: in DB but not in the new graph.
|
|
186
|
+
const toDelete = existingRows.filter(r => !incomingSet.has(r.node_id)).map(r => r.node_id);
|
|
187
|
+
// Nodes to add or update: new or body_hash changed.
|
|
188
|
+
const toEmbed = nodes.filter(n => {
|
|
189
|
+
const nodeHash = n.body_hash ?? n.id;
|
|
190
|
+
return existingMap.get(n.id) !== nodeHash;
|
|
191
|
+
});
|
|
192
|
+
const added = toEmbed.filter(n => !existingMap.has(n.id)).length;
|
|
193
|
+
const updated = toEmbed.length - added;
|
|
194
|
+
process.stderr.write(`[semantic] incremental update — +${added} new, ~${updated} changed, -${toDelete.length} removed` +
|
|
195
|
+
` of ${nodes.length} total\n`);
|
|
196
|
+
// Delete removed nodes.
|
|
197
|
+
if (toDelete.length > 0) {
|
|
198
|
+
const delMeta = db.prepare('DELETE FROM embed_nodes WHERE node_id = ?');
|
|
199
|
+
const delVec = db.prepare('DELETE FROM vss_nodes WHERE rowid = (SELECT rowid FROM embed_nodes WHERE node_id = ?)');
|
|
200
|
+
const delBatch = db.transaction(() => {
|
|
201
|
+
for (const id of toDelete) {
|
|
202
|
+
delVec.run(id);
|
|
203
|
+
delMeta.run(id);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
delBatch();
|
|
207
|
+
}
|
|
208
|
+
// Embed and insert/update changed nodes.
|
|
209
|
+
if (toEmbed.length > 0) {
|
|
210
|
+
const texts = toEmbed.map(n => [n.id, n.signature ?? '', n.body_text ?? ''].filter(Boolean).join(' '));
|
|
211
|
+
const vecs = await embedTexts(texts);
|
|
212
|
+
const { maxId } = db.prepare('SELECT COALESCE(MAX(rowid), 0) AS maxId FROM embed_nodes').get();
|
|
213
|
+
let nextRowid = maxId + 1;
|
|
214
|
+
// Regular table: UPSERT ok.
|
|
215
|
+
const upsertMeta = db.prepare(`
|
|
216
|
+
INSERT INTO embed_nodes (rowid, node_id, file_path, symbol, snippet, body_hash)
|
|
217
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
218
|
+
ON CONFLICT(rowid) DO UPDATE SET
|
|
219
|
+
node_id = excluded.node_id,
|
|
220
|
+
file_path = excluded.file_path,
|
|
221
|
+
symbol = excluded.symbol,
|
|
222
|
+
snippet = excluded.snippet,
|
|
223
|
+
body_hash = excluded.body_hash
|
|
224
|
+
`);
|
|
225
|
+
// Virtual table (sqlite-vec): no UPSERT support → DELETE then INSERT.
|
|
226
|
+
const deleteVec = db.prepare('DELETE FROM vss_nodes WHERE rowid = ?');
|
|
227
|
+
const insertVec = db.prepare('INSERT INTO vss_nodes (rowid, embedding) VALUES (?, ?)');
|
|
228
|
+
const getRowid = db.prepare('SELECT rowid FROM embed_nodes WHERE node_id = ?');
|
|
229
|
+
const upsertBatch = db.transaction(() => {
|
|
230
|
+
for (let i = 0; i < toEmbed.length; i++) {
|
|
231
|
+
const n = toEmbed[i];
|
|
232
|
+
const v = vecs[i];
|
|
233
|
+
const nodeHash = n.body_hash ?? n.id;
|
|
234
|
+
const snippet = n.summary ?? n.signature ?? n.id;
|
|
235
|
+
const existing = getRowid.get(n.id);
|
|
236
|
+
const rowid = existing ? BigInt(existing.rowid) : BigInt(nextRowid++);
|
|
237
|
+
// For updated nodes: remove old vector before inserting new one.
|
|
238
|
+
if (existing)
|
|
239
|
+
deleteVec.run(rowid);
|
|
240
|
+
upsertMeta.run(Number(rowid), n.id, n.path, n.name, snippet ?? '', nodeHash);
|
|
241
|
+
insertVec.run(rowid, vecToBuffer(v));
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
upsertBatch();
|
|
245
|
+
}
|
|
246
|
+
// Update the graph hash.
|
|
247
|
+
db.prepare("INSERT INTO embed_meta (key, value) VALUES ('graph_hash', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(currentHash);
|
|
248
|
+
process.stderr.write(`[semantic] Done — ${nodes.length} nodes indexed at ${dbPath}\n`);
|
|
249
|
+
db.close();
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Embed `query`, find the top-`limit` nearest nodes in the vector store, and
|
|
253
|
+
* return them with cosine similarity scores.
|
|
254
|
+
*
|
|
255
|
+
* Throws if the DB does not exist or contains no embeddings (call `embedNodes`
|
|
256
|
+
* first, or use the MCP tool which calls it automatically).
|
|
257
|
+
*/
|
|
258
|
+
export async function searchSemantic(query, dbPath, limit = 5) {
|
|
259
|
+
if (!existsSync(dbPath)) {
|
|
260
|
+
throw new Error(`Embeddings DB not found: ${dbPath} — run \`graft build\` or call the MCP tool once first`);
|
|
261
|
+
}
|
|
262
|
+
const db = openDb(dbPath);
|
|
263
|
+
initSchema(db);
|
|
264
|
+
const { c } = db.prepare('SELECT COUNT(*) AS c FROM embed_nodes').get();
|
|
265
|
+
if (c === 0) {
|
|
266
|
+
db.close();
|
|
267
|
+
throw new Error('[semantic] Vector index is empty — run `trail build` to populate it');
|
|
268
|
+
}
|
|
269
|
+
const [queryVec] = await embedTexts([query]);
|
|
270
|
+
const buf = vecToBuffer(queryVec);
|
|
271
|
+
const rows = db.prepare(`
|
|
272
|
+
SELECT
|
|
273
|
+
m.node_id,
|
|
274
|
+
m.file_path,
|
|
275
|
+
m.symbol,
|
|
276
|
+
m.snippet,
|
|
277
|
+
v.distance
|
|
278
|
+
FROM vss_nodes v
|
|
279
|
+
JOIN embed_nodes m ON m.rowid = v.rowid
|
|
280
|
+
WHERE v.embedding MATCH ?
|
|
281
|
+
AND k = ?
|
|
282
|
+
ORDER BY v.distance
|
|
283
|
+
`).all(buf, limit);
|
|
284
|
+
db.close();
|
|
285
|
+
return rows.map(r => ({
|
|
286
|
+
node_id: r.node_id,
|
|
287
|
+
file_path: r.file_path,
|
|
288
|
+
symbol: r.symbol,
|
|
289
|
+
score: +(1 - (r.distance * r.distance) / 2).toFixed(4),
|
|
290
|
+
snippet: r.snippet ?? '',
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=semantic.js.map
|