lmgrep 0.1.18 → 0.2.0
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/README.md +226 -63
- package/completions/_lmgrep +49 -40
- package/dist/application/Lmgrep.d.ts +107 -0
- package/dist/application/Lmgrep.js +99 -0
- package/dist/application/Lmgrep.js.map +1 -0
- package/dist/application/LmgrepFactory.d.ts +40 -0
- package/dist/application/LmgrepFactory.js +155 -0
- package/dist/application/LmgrepFactory.js.map +1 -0
- package/dist/application/indexing/BranchBootstrapper.d.ts +21 -0
- package/dist/application/indexing/BranchBootstrapper.js +52 -0
- package/dist/application/indexing/BranchBootstrapper.js.map +1 -0
- package/dist/application/indexing/BranchManifestSweeper.d.ts +17 -0
- package/dist/application/indexing/BranchManifestSweeper.js +35 -0
- package/dist/application/indexing/BranchManifestSweeper.js.map +1 -0
- package/dist/application/indexing/Duration.d.ts +9 -0
- package/dist/application/indexing/Duration.js +25 -0
- package/dist/application/indexing/Duration.js.map +1 -0
- package/dist/application/indexing/EmbeddingAbortError.d.ts +11 -0
- package/dist/application/indexing/EmbeddingAbortError.js +20 -0
- package/dist/application/indexing/EmbeddingAbortError.js.map +1 -0
- package/dist/application/indexing/EmbeddingPipeline.d.ts +59 -0
- package/dist/application/indexing/EmbeddingPipeline.js +140 -0
- package/dist/application/indexing/EmbeddingPipeline.js.map +1 -0
- package/dist/application/indexing/IndexBuilder.d.ts +112 -0
- package/dist/application/indexing/IndexBuilder.js +370 -0
- package/dist/application/indexing/IndexBuilder.js.map +1 -0
- package/dist/application/indexing/IndexingProgress.d.ts +34 -0
- package/dist/application/indexing/IndexingProgress.js +2 -0
- package/dist/application/indexing/IndexingProgress.js.map +1 -0
- package/dist/application/operations/Deadline.d.ts +13 -0
- package/dist/application/operations/Deadline.js +29 -0
- package/dist/application/operations/Deadline.js.map +1 -0
- package/dist/application/operations/HealthMonitor.d.ts +58 -0
- package/dist/application/operations/HealthMonitor.js +128 -0
- package/dist/application/operations/HealthMonitor.js.map +1 -0
- package/dist/application/operations/IndexAlternatives.d.ts +35 -0
- package/dist/application/operations/IndexAlternatives.js +61 -0
- package/dist/application/operations/IndexAlternatives.js.map +1 -0
- package/dist/application/operations/IndexInventory.d.ts +69 -0
- package/dist/application/operations/IndexInventory.js +99 -0
- package/dist/application/operations/IndexInventory.js.map +1 -0
- package/dist/application/operations/StatusService.d.ts +90 -0
- package/dist/application/operations/StatusService.js +171 -0
- package/dist/application/operations/StatusService.js.map +1 -0
- package/dist/application/operations/WatchService.d.ts +67 -0
- package/dist/application/operations/WatchService.js +145 -0
- package/dist/application/operations/WatchService.js.map +1 -0
- package/dist/application/operations/WorkingTreeDiff.d.ts +19 -0
- package/dist/application/operations/WorkingTreeDiff.js +36 -0
- package/dist/application/operations/WorkingTreeDiff.js.map +1 -0
- package/dist/application/research/ResearchAgent.d.ts +68 -0
- package/dist/application/research/ResearchAgent.js +201 -0
- package/dist/application/research/ResearchAgent.js.map +1 -0
- package/dist/application/research/ResearchPrompts.d.ts +16 -0
- package/dist/application/research/ResearchPrompts.js +34 -0
- package/dist/application/research/ResearchPrompts.js.map +1 -0
- package/dist/application/search/SearchCriteria.d.ts +37 -0
- package/dist/application/search/SearchCriteria.js +48 -0
- package/dist/application/search/SearchCriteria.js.map +1 -0
- package/dist/application/search/SearchService.d.ts +36 -0
- package/dist/application/search/SearchService.js +108 -0
- package/dist/application/search/SearchService.js.map +1 -0
- package/dist/application/search/SearchTargetResolver.d.ts +56 -0
- package/dist/application/search/SearchTargetResolver.js +104 -0
- package/dist/application/search/SearchTargetResolver.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +4 -953
- package/dist/cli.js.map +1 -1
- package/dist/domain/config/ConfigSource.d.ts +16 -0
- package/dist/domain/config/ConfigSource.js +2 -0
- package/dist/domain/config/ConfigSource.js.map +1 -0
- package/dist/domain/config/LmgrepConfig.d.ts +53 -0
- package/dist/domain/config/LmgrepConfig.js +2 -0
- package/dist/domain/config/LmgrepConfig.js.map +1 -0
- package/dist/domain/corpus/Chunk.d.ts +49 -0
- package/dist/domain/corpus/Chunk.js +60 -0
- package/dist/domain/corpus/Chunk.js.map +1 -0
- package/dist/domain/corpus/CodeLocation.d.ts +18 -0
- package/dist/domain/corpus/CodeLocation.js +34 -0
- package/dist/domain/corpus/CodeLocation.js.map +1 -0
- package/dist/domain/corpus/ContentHash.d.ts +15 -0
- package/dist/domain/corpus/ContentHash.js +30 -0
- package/dist/domain/corpus/ContentHash.js.map +1 -0
- package/dist/domain/corpus/FileVersion.d.ts +31 -0
- package/dist/domain/corpus/FileVersion.js +47 -0
- package/dist/domain/corpus/FileVersion.js.map +1 -0
- package/dist/domain/corpus/SourceFile.d.ts +26 -0
- package/dist/domain/corpus/SourceFile.js +47 -0
- package/dist/domain/corpus/SourceFile.js.map +1 -0
- package/dist/domain/corpus/Vector.d.ts +37 -0
- package/dist/domain/corpus/Vector.js +96 -0
- package/dist/domain/corpus/Vector.js.map +1 -0
- package/dist/domain/ports/ChatModelPort.d.ts +57 -0
- package/dist/domain/ports/ChatModelPort.js +2 -0
- package/dist/domain/ports/ChatModelPort.js.map +1 -0
- package/dist/domain/ports/ChunkRepositoryPort.d.ts +42 -0
- package/dist/domain/ports/ChunkRepositoryPort.js +2 -0
- package/dist/domain/ports/ChunkRepositoryPort.js.map +1 -0
- package/dist/domain/ports/ChunkerPort.d.ts +5 -0
- package/dist/domain/ports/ChunkerPort.js +2 -0
- package/dist/domain/ports/ChunkerPort.js.map +1 -0
- package/dist/domain/ports/DatabaseSessionPort.d.ts +10 -0
- package/dist/domain/ports/DatabaseSessionPort.js +2 -0
- package/dist/domain/ports/DatabaseSessionPort.js.map +1 -0
- package/dist/domain/ports/EmbedderPort.d.ts +14 -0
- package/dist/domain/ports/EmbedderPort.js +2 -0
- package/dist/domain/ports/EmbedderPort.js.map +1 -0
- package/dist/domain/ports/FileManifestRepositoryPort.d.ts +32 -0
- package/dist/domain/ports/FileManifestRepositoryPort.js +2 -0
- package/dist/domain/ports/FileManifestRepositoryPort.js.map +1 -0
- package/dist/domain/ports/GitPort.d.ts +24 -0
- package/dist/domain/ports/GitPort.js +2 -0
- package/dist/domain/ports/GitPort.js.map +1 -0
- package/dist/domain/ports/IndexMaintenancePort.d.ts +58 -0
- package/dist/domain/ports/IndexMaintenancePort.js +2 -0
- package/dist/domain/ports/IndexMaintenancePort.js.map +1 -0
- package/dist/domain/ports/IndexMetadataPort.d.ts +23 -0
- package/dist/domain/ports/IndexMetadataPort.js +2 -0
- package/dist/domain/ports/IndexMetadataPort.js.map +1 -0
- package/dist/domain/ports/LockPort.d.ts +17 -0
- package/dist/domain/ports/LockPort.js +2 -0
- package/dist/domain/ports/LockPort.js.map +1 -0
- package/dist/domain/ports/LoggerPort.d.ts +5 -0
- package/dist/domain/ports/LoggerPort.js +2 -0
- package/dist/domain/ports/LoggerPort.js.map +1 -0
- package/dist/domain/ports/ProjectIndexesPort.d.ts +20 -0
- package/dist/domain/ports/ProjectIndexesPort.js +2 -0
- package/dist/domain/ports/ProjectIndexesPort.js.map +1 -0
- package/dist/domain/ports/ProjectRegistryPort.d.ts +42 -0
- package/dist/domain/ports/ProjectRegistryPort.js +2 -0
- package/dist/domain/ports/ProjectRegistryPort.js.map +1 -0
- package/dist/domain/ports/StateDirectoryPort.d.ts +29 -0
- package/dist/domain/ports/StateDirectoryPort.js +2 -0
- package/dist/domain/ports/StateDirectoryPort.js.map +1 -0
- package/dist/domain/ports/WorkspacePort.d.ts +38 -0
- package/dist/domain/ports/WorkspacePort.js +2 -0
- package/dist/domain/ports/WorkspacePort.js.map +1 -0
- package/dist/domain/project/Branch.d.ts +20 -0
- package/dist/domain/project/Branch.js +33 -0
- package/dist/domain/project/Branch.js.map +1 -0
- package/dist/domain/project/DatabaseLocation.d.ts +32 -0
- package/dist/domain/project/DatabaseLocation.js +35 -0
- package/dist/domain/project/DatabaseLocation.js.map +1 -0
- package/dist/domain/project/IndexMetadata.d.ts +17 -0
- package/dist/domain/project/IndexMetadata.js +2 -0
- package/dist/domain/project/IndexMetadata.js.map +1 -0
- package/dist/domain/project/ModelIdentity.d.ts +58 -0
- package/dist/domain/project/ModelIdentity.js +97 -0
- package/dist/domain/project/ModelIdentity.js.map +1 -0
- package/dist/domain/project/Project.d.ts +17 -0
- package/dist/domain/project/Project.js +21 -0
- package/dist/domain/project/Project.js.map +1 -0
- package/dist/domain/project/ProjectId.d.ts +28 -0
- package/dist/domain/project/ProjectId.js +58 -0
- package/dist/domain/project/ProjectId.js.map +1 -0
- package/dist/domain/project/ProjectLocator.d.ts +112 -0
- package/dist/domain/project/ProjectLocator.js +178 -0
- package/dist/domain/project/ProjectLocator.js.map +1 -0
- package/dist/domain/research/Citation.d.ts +27 -0
- package/dist/domain/research/Citation.js +43 -0
- package/dist/domain/research/Citation.js.map +1 -0
- package/dist/domain/research/EvidenceLedger.d.ts +47 -0
- package/dist/domain/research/EvidenceLedger.js +111 -0
- package/dist/domain/research/EvidenceLedger.js.map +1 -0
- package/dist/domain/research/ResearchTrace.d.ts +19 -0
- package/dist/domain/research/ResearchTrace.js +22 -0
- package/dist/domain/research/ResearchTrace.js.map +1 -0
- package/dist/domain/retrieval/Hit.d.ts +19 -0
- package/dist/domain/retrieval/Hit.js +28 -0
- package/dist/domain/retrieval/Hit.js.map +1 -0
- package/dist/domain/retrieval/HitList.d.ts +35 -0
- package/dist/domain/retrieval/HitList.js +81 -0
- package/dist/domain/retrieval/HitList.js.map +1 -0
- package/dist/domain/retrieval/MissingIndexError.d.ts +11 -0
- package/dist/domain/retrieval/MissingIndexError.js +15 -0
- package/dist/domain/retrieval/MissingIndexError.js.map +1 -0
- package/dist/index.d.ts +43 -45
- package/dist/index.js +30 -567
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/ai/AiSdkChatModel.d.ts +31 -0
- package/dist/infrastructure/ai/AiSdkChatModel.js +137 -0
- package/dist/infrastructure/ai/AiSdkChatModel.js.map +1 -0
- package/dist/infrastructure/ai/AiSdkEmbedder.d.ts +28 -0
- package/dist/infrastructure/ai/AiSdkEmbedder.js +79 -0
- package/dist/infrastructure/ai/AiSdkEmbedder.js.map +1 -0
- package/dist/infrastructure/ai/EmbeddingPrefixes.d.ts +21 -0
- package/dist/infrastructure/ai/EmbeddingPrefixes.js +40 -0
- package/dist/infrastructure/ai/EmbeddingPrefixes.js.map +1 -0
- package/dist/infrastructure/ai/LmStudioProbe.d.ts +18 -0
- package/dist/infrastructure/ai/LmStudioProbe.js +49 -0
- package/dist/infrastructure/ai/LmStudioProbe.js.map +1 -0
- package/dist/infrastructure/ai/LocalModelReloader.d.ts +21 -0
- package/dist/infrastructure/ai/LocalModelReloader.js +61 -0
- package/dist/infrastructure/ai/LocalModelReloader.js.map +1 -0
- package/dist/infrastructure/ai/LocalRuntimeDetector.d.ts +36 -0
- package/dist/infrastructure/ai/LocalRuntimeDetector.js +61 -0
- package/dist/infrastructure/ai/LocalRuntimeDetector.js.map +1 -0
- package/dist/infrastructure/ai/ModelRuntime.d.ts +32 -0
- package/dist/infrastructure/ai/ModelRuntime.js +2 -0
- package/dist/infrastructure/ai/ModelRuntime.js.map +1 -0
- package/dist/infrastructure/ai/OllamaProbe.d.ts +21 -0
- package/dist/infrastructure/ai/OllamaProbe.js +69 -0
- package/dist/infrastructure/ai/OllamaProbe.js.map +1 -0
- package/dist/infrastructure/ai/ProviderFailure.d.ts +16 -0
- package/dist/infrastructure/ai/ProviderFailure.js +35 -0
- package/dist/infrastructure/ai/ProviderFailure.js.map +1 -0
- package/dist/infrastructure/ai/ProviderModuleLoader.d.ts +13 -0
- package/dist/infrastructure/ai/ProviderModuleLoader.js +49 -0
- package/dist/infrastructure/ai/ProviderModuleLoader.js.map +1 -0
- package/dist/infrastructure/ai/ProviderRegistry.d.ts +37 -0
- package/dist/infrastructure/ai/ProviderRegistry.js +55 -0
- package/dist/infrastructure/ai/ProviderRegistry.js.map +1 -0
- package/dist/infrastructure/fs/ConfigLoader.d.ts +59 -0
- package/dist/infrastructure/fs/ConfigLoader.js +194 -0
- package/dist/infrastructure/fs/ConfigLoader.js.map +1 -0
- package/dist/infrastructure/fs/DatabaseLocks.d.ts +52 -0
- package/dist/infrastructure/fs/DatabaseLocks.js +92 -0
- package/dist/infrastructure/fs/DatabaseLocks.js.map +1 -0
- package/dist/infrastructure/fs/DiskUsage.d.ts +6 -0
- package/dist/infrastructure/fs/DiskUsage.js +41 -0
- package/dist/infrastructure/fs/DiskUsage.js.map +1 -0
- package/dist/infrastructure/fs/IndexableFileRules.d.ts +33 -0
- package/dist/infrastructure/fs/IndexableFileRules.js +177 -0
- package/dist/infrastructure/fs/IndexableFileRules.js.map +1 -0
- package/dist/infrastructure/fs/Loggers.d.ts +14 -0
- package/dist/infrastructure/fs/Loggers.js +18 -0
- package/dist/infrastructure/fs/Loggers.js.map +1 -0
- package/dist/infrastructure/fs/PidFileLock.d.ts +40 -0
- package/dist/infrastructure/fs/PidFileLock.js +97 -0
- package/dist/infrastructure/fs/PidFileLock.js.map +1 -0
- package/dist/infrastructure/fs/ProjectIndexes.d.ts +8 -0
- package/dist/infrastructure/fs/ProjectIndexes.js +35 -0
- package/dist/infrastructure/fs/ProjectIndexes.js.map +1 -0
- package/dist/infrastructure/fs/ProjectMetadataStore.d.ts +42 -0
- package/dist/infrastructure/fs/ProjectMetadataStore.js +86 -0
- package/dist/infrastructure/fs/ProjectMetadataStore.js.map +1 -0
- package/dist/infrastructure/fs/ProjectRegistry.d.ts +25 -0
- package/dist/infrastructure/fs/ProjectRegistry.js +83 -0
- package/dist/infrastructure/fs/ProjectRegistry.js.map +1 -0
- package/dist/infrastructure/fs/StateDirectory.d.ts +28 -0
- package/dist/infrastructure/fs/StateDirectory.js +71 -0
- package/dist/infrastructure/fs/StateDirectory.js.map +1 -0
- package/dist/infrastructure/fs/Workspace.d.ts +25 -0
- package/dist/infrastructure/fs/Workspace.js +90 -0
- package/dist/infrastructure/fs/Workspace.js.map +1 -0
- package/dist/infrastructure/git/GitClient.d.ts +34 -0
- package/dist/infrastructure/git/GitClient.js +74 -0
- package/dist/infrastructure/git/GitClient.js.map +1 -0
- package/dist/infrastructure/lancedb/ChunkRepository.d.ts +38 -0
- package/dist/infrastructure/lancedb/ChunkRepository.js +166 -0
- package/dist/infrastructure/lancedb/ChunkRepository.js.map +1 -0
- package/dist/infrastructure/lancedb/DatabaseImporter.d.ts +22 -0
- package/dist/infrastructure/lancedb/DatabaseImporter.js +74 -0
- package/dist/infrastructure/lancedb/DatabaseImporter.js.map +1 -0
- package/dist/infrastructure/lancedb/FileManifestRepository.d.ts +34 -0
- package/dist/infrastructure/lancedb/FileManifestRepository.js +137 -0
- package/dist/infrastructure/lancedb/FileManifestRepository.js.map +1 -0
- package/dist/infrastructure/lancedb/IndexMaintenance.d.ts +53 -0
- package/dist/infrastructure/lancedb/IndexMaintenance.js +227 -0
- package/dist/infrastructure/lancedb/IndexMaintenance.js.map +1 -0
- package/dist/infrastructure/lancedb/LanceTables.d.ts +67 -0
- package/dist/infrastructure/lancedb/LanceTables.js +159 -0
- package/dist/infrastructure/lancedb/LanceTables.js.map +1 -0
- package/dist/{lib/native-tuning.js → infrastructure/lancedb/NativeTuning.js} +1 -1
- package/dist/infrastructure/lancedb/NativeTuning.js.map +1 -0
- package/dist/infrastructure/lancedb/RowReplication.d.ts +27 -0
- package/dist/infrastructure/lancedb/RowReplication.js +82 -0
- package/dist/infrastructure/lancedb/RowReplication.js.map +1 -0
- package/dist/infrastructure/lancedb/VectorIndexPolicy.d.ts +60 -0
- package/dist/infrastructure/lancedb/VectorIndexPolicy.js +72 -0
- package/dist/infrastructure/lancedb/VectorIndexPolicy.js.map +1 -0
- package/dist/infrastructure/p2p/IndexShare.d.ts +45 -0
- package/dist/infrastructure/p2p/IndexShare.js +160 -0
- package/dist/infrastructure/p2p/IndexShare.js.map +1 -0
- package/dist/infrastructure/p2p/PeerSwarm.d.ts +16 -0
- package/dist/infrastructure/p2p/PeerSwarm.js +41 -0
- package/dist/infrastructure/p2p/PeerSwarm.js.map +1 -0
- package/dist/infrastructure/p2p/SecureChannel.d.ts +60 -0
- package/dist/infrastructure/p2p/SecureChannel.js +71 -0
- package/dist/infrastructure/p2p/SecureChannel.js.map +1 -0
- package/dist/infrastructure/p2p/ShareCode.d.ts +25 -0
- package/dist/infrastructure/p2p/ShareCode.js +304 -0
- package/dist/infrastructure/p2p/ShareCode.js.map +1 -0
- package/dist/infrastructure/process/ProcessRegistry.d.ts +50 -0
- package/dist/infrastructure/process/ProcessRegistry.js +109 -0
- package/dist/infrastructure/process/ProcessRegistry.js.map +1 -0
- package/dist/infrastructure/treesitter/ChunkContextBuilder.d.ts +45 -0
- package/dist/infrastructure/treesitter/ChunkContextBuilder.js +159 -0
- package/dist/infrastructure/treesitter/ChunkContextBuilder.js.map +1 -0
- package/dist/infrastructure/treesitter/LanguageCatalog.d.ts +30 -0
- package/dist/{lib/chunker/languages.js → infrastructure/treesitter/LanguageCatalog.js} +34 -29
- package/dist/infrastructure/treesitter/LanguageCatalog.js.map +1 -0
- package/dist/infrastructure/treesitter/SlidingWindowChunker.d.ts +15 -0
- package/dist/infrastructure/treesitter/SlidingWindowChunker.js +42 -0
- package/dist/infrastructure/treesitter/SlidingWindowChunker.js.map +1 -0
- package/dist/infrastructure/treesitter/TreeSitterChunker.d.ts +42 -0
- package/dist/infrastructure/treesitter/TreeSitterChunker.js +163 -0
- package/dist/infrastructure/treesitter/TreeSitterChunker.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +14 -72
- package/dist/mcp.js.map +1 -1
- package/dist/presentation/cli/Cli.d.ts +31 -0
- package/dist/presentation/cli/Cli.js +120 -0
- package/dist/presentation/cli/Cli.js.map +1 -0
- package/dist/presentation/cli/CliOptions.d.ts +18 -0
- package/dist/presentation/cli/CliOptions.js +25 -0
- package/dist/presentation/cli/CliOptions.js.map +1 -0
- package/dist/presentation/cli/CommandContext.d.ts +50 -0
- package/dist/presentation/cli/CommandContext.js +88 -0
- package/dist/presentation/cli/CommandContext.js.map +1 -0
- package/dist/presentation/cli/ConfigTemplate.d.ts +31 -0
- package/dist/presentation/cli/ConfigTemplate.js +83 -0
- package/dist/presentation/cli/ConfigTemplate.js.map +1 -0
- package/dist/presentation/cli/Renderer.d.ts +90 -0
- package/dist/presentation/cli/Renderer.js +290 -0
- package/dist/presentation/cli/Renderer.js.map +1 -0
- package/dist/presentation/cli/commands/AskCommand.d.ts +14 -0
- package/dist/presentation/cli/commands/AskCommand.js +48 -0
- package/dist/presentation/cli/commands/AskCommand.js.map +1 -0
- package/dist/presentation/cli/commands/CompletionsCommand.d.ts +18 -0
- package/dist/presentation/cli/commands/CompletionsCommand.js +96 -0
- package/dist/presentation/cli/commands/CompletionsCommand.js.map +1 -0
- package/dist/presentation/cli/commands/ConfigCommands.d.ts +55 -0
- package/dist/presentation/cli/commands/ConfigCommands.js +204 -0
- package/dist/presentation/cli/commands/ConfigCommands.js.map +1 -0
- package/dist/presentation/cli/commands/IndexCommand.d.ts +18 -0
- package/dist/presentation/cli/commands/IndexCommand.js +54 -0
- package/dist/presentation/cli/commands/IndexCommand.js.map +1 -0
- package/dist/presentation/cli/commands/ProjectsCommand.d.ts +48 -0
- package/dist/presentation/cli/commands/ProjectsCommand.js +240 -0
- package/dist/presentation/cli/commands/ProjectsCommand.js.map +1 -0
- package/dist/presentation/cli/commands/SearchCommand.d.ts +19 -0
- package/dist/presentation/cli/commands/SearchCommand.js +55 -0
- package/dist/presentation/cli/commands/SearchCommand.js.map +1 -0
- package/dist/presentation/cli/commands/ServerCommands.d.ts +13 -0
- package/dist/presentation/cli/commands/ServerCommands.js +40 -0
- package/dist/presentation/cli/commands/ServerCommands.js.map +1 -0
- package/dist/presentation/cli/commands/ShareCommands.d.ts +22 -0
- package/dist/presentation/cli/commands/ShareCommands.js +134 -0
- package/dist/presentation/cli/commands/ShareCommands.js.map +1 -0
- package/dist/presentation/cli/commands/StatusCommand.d.ts +15 -0
- package/dist/presentation/cli/commands/StatusCommand.js +53 -0
- package/dist/presentation/cli/commands/StatusCommand.js.map +1 -0
- package/dist/presentation/mcp/HitFormatter.d.ts +17 -0
- package/dist/presentation/mcp/HitFormatter.js +42 -0
- package/dist/presentation/mcp/HitFormatter.js.map +1 -0
- package/dist/presentation/mcp/IndexWatchController.d.ts +17 -0
- package/dist/presentation/mcp/IndexWatchController.js +31 -0
- package/dist/presentation/mcp/IndexWatchController.js.map +1 -0
- package/dist/presentation/mcp/LmgrepCore.d.ts +66 -0
- package/dist/presentation/mcp/LmgrepCore.js +178 -0
- package/dist/presentation/mcp/LmgrepCore.js.map +1 -0
- package/dist/presentation/mcp/McpServer.d.ts +18 -0
- package/dist/presentation/mcp/McpServer.js +63 -0
- package/dist/presentation/mcp/McpServer.js.map +1 -0
- package/dist/presentation/mcp/ToolDescriptions.d.ts +40 -0
- package/dist/presentation/mcp/ToolDescriptions.js +85 -0
- package/dist/presentation/mcp/ToolDescriptions.js.map +1 -0
- package/package.json +84 -89
- package/dist/lib/build.d.ts +0 -21
- package/dist/lib/build.js +0 -374
- package/dist/lib/build.js.map +0 -1
- package/dist/lib/chunker/context.d.ts +0 -21
- package/dist/lib/chunker/context.js +0 -131
- package/dist/lib/chunker/context.js.map +0 -1
- package/dist/lib/chunker/index.d.ts +0 -7
- package/dist/lib/chunker/index.js +0 -209
- package/dist/lib/chunker/index.js.map +0 -1
- package/dist/lib/chunker/languages.d.ts +0 -15
- package/dist/lib/chunker/languages.js.map +0 -1
- package/dist/lib/config.d.ts +0 -12
- package/dist/lib/config.js +0 -83
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/embedder.d.ts +0 -65
- package/dist/lib/embedder.js +0 -236
- package/dist/lib/embedder.js.map +0 -1
- package/dist/lib/facet-session.d.ts +0 -44
- package/dist/lib/facet-session.js +0 -125
- package/dist/lib/facet-session.js.map +0 -1
- package/dist/lib/native-tuning.js.map +0 -1
- package/dist/lib/p2p.d.ts +0 -32
- package/dist/lib/p2p.js +0 -281
- package/dist/lib/p2p.js.map +0 -1
- package/dist/lib/providers.d.ts +0 -1
- package/dist/lib/providers.js +0 -41
- package/dist/lib/providers.js.map +0 -1
- package/dist/lib/repair.d.ts +0 -10
- package/dist/lib/repair.js +0 -57
- package/dist/lib/repair.js.map +0 -1
- package/dist/lib/scanner.d.ts +0 -34
- package/dist/lib/scanner.js +0 -242
- package/dist/lib/scanner.js.map +0 -1
- package/dist/lib/search-tool.d.ts +0 -55
- package/dist/lib/search-tool.js +0 -319
- package/dist/lib/search-tool.js.map +0 -1
- package/dist/lib/serve.d.ts +0 -11
- package/dist/lib/serve.js +0 -144
- package/dist/lib/serve.js.map +0 -1
- package/dist/lib/store.d.ts +0 -252
- package/dist/lib/store.js +0 -1216
- package/dist/lib/store.js.map +0 -1
- package/dist/lib/types.d.ts +0 -194
- package/dist/lib/types.js +0 -13
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/vocab.d.ts +0 -20
- package/dist/lib/vocab.js +0 -275
- package/dist/lib/vocab.js.map +0 -1
- /package/dist/{lib/native-tuning.d.ts → infrastructure/lancedb/NativeTuning.d.ts} +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { CitationMarkers, } from "../../domain/research/Citation.js";
|
|
2
|
+
import { EvidenceLedger } from "../../domain/research/EvidenceLedger.js";
|
|
3
|
+
import { ResearchTrace, } from "../../domain/research/ResearchTrace.js";
|
|
4
|
+
import { SearchCriteria, } from "../search/SearchCriteria.js";
|
|
5
|
+
import { ResearchPrompts } from "./ResearchPrompts.js";
|
|
6
|
+
/**
|
|
7
|
+
* Answers a question by searching the codebase and synthesizing a cited answer.
|
|
8
|
+
*
|
|
9
|
+
* Robustness is layered, because a local model fails in several distinct ways
|
|
10
|
+
* and none of them should hard-fail the caller:
|
|
11
|
+
*
|
|
12
|
+
* 1. Happy path — the model self-terminates with a cited answer.
|
|
13
|
+
* 2. It cannot self-terminate (step cap, timeout, or the transcript overflows
|
|
14
|
+
* its context) — synthesize from a budgeted digest in a fresh context.
|
|
15
|
+
* 3. It answered without ever searching — discard that, since it is ungrounded
|
|
16
|
+
* by construction, search directly and synthesize.
|
|
17
|
+
* 4. The model is unreachable — degrade to raw search hits.
|
|
18
|
+
*/
|
|
19
|
+
export class ResearchAgent {
|
|
20
|
+
searcher;
|
|
21
|
+
chat;
|
|
22
|
+
config;
|
|
23
|
+
static DEFAULT_MAX_STEPS = 8;
|
|
24
|
+
/**
|
|
25
|
+
* Wall clock is only a backstop against a wedged run; the search and step
|
|
26
|
+
* budgets bound the real work. A local model doing a few steps plus a cold
|
|
27
|
+
* load can need minutes, so this stays generous.
|
|
28
|
+
*/
|
|
29
|
+
static DEFAULT_TIMEOUT_MS = 240_000;
|
|
30
|
+
static MAX_SEARCHES = 8;
|
|
31
|
+
static DEFAULT_SEARCH_LIMIT = 5;
|
|
32
|
+
/** The model tends to ask for 10+, which bloats the transcript. */
|
|
33
|
+
static MAX_SEARCH_LIMIT = 6;
|
|
34
|
+
/** After this many searches, nudge it to wrap up. */
|
|
35
|
+
static NUDGE_AFTER = 3;
|
|
36
|
+
constructor(searcher, chat, config) {
|
|
37
|
+
this.searcher = searcher;
|
|
38
|
+
this.chat = chat;
|
|
39
|
+
this.config = config;
|
|
40
|
+
}
|
|
41
|
+
async research(question, onTrace) {
|
|
42
|
+
if (!this.chat.isConfigured) {
|
|
43
|
+
throw new Error("`lmgrep ask` requires a chat model. Set `chatModel` in your lmgrep config " +
|
|
44
|
+
"(e.g. `chatModel: lmstudio:qwen/qwen3.5-9b`).");
|
|
45
|
+
}
|
|
46
|
+
const started = Date.now();
|
|
47
|
+
const trace = new ResearchTrace(onTrace);
|
|
48
|
+
const ledger = new EvidenceLedger();
|
|
49
|
+
const timeoutMs = this.config.chatTimeoutMs ?? ResearchAgent.DEFAULT_TIMEOUT_MS;
|
|
50
|
+
const maxSteps = this.config.chatMaxSteps ?? ResearchAgent.DEFAULT_MAX_STEPS;
|
|
51
|
+
let searchCount = 0;
|
|
52
|
+
const runSearch = async (call) => {
|
|
53
|
+
if (searchCount >= ResearchAgent.MAX_SEARCHES) {
|
|
54
|
+
return ResearchPrompts.BUDGET_EXHAUSTED;
|
|
55
|
+
}
|
|
56
|
+
searchCount++;
|
|
57
|
+
const hits = await this.runSearch(call.query, {
|
|
58
|
+
limit: Math.min(call.limit ?? ResearchAgent.DEFAULT_SEARCH_LIMIT, ResearchAgent.MAX_SEARCH_LIMIT),
|
|
59
|
+
filePrefix: call.filePrefix,
|
|
60
|
+
type: call.type,
|
|
61
|
+
language: call.language,
|
|
62
|
+
});
|
|
63
|
+
trace.searched(call.query, hits.length);
|
|
64
|
+
if (hits.isEmpty) {
|
|
65
|
+
return `No results for "${call.query}". Try different wording or a broader query.`;
|
|
66
|
+
}
|
|
67
|
+
const blocks = ledger
|
|
68
|
+
.ingest(hits.toArray())
|
|
69
|
+
.map(({ id, hit, body }) => `[${id}] ${hit.location} · ${hit.type} ${hit.name} · score ${hit.score.toFixed(2)}\n${body}`);
|
|
70
|
+
const parts = [`Results for "${call.query}":`, ...blocks];
|
|
71
|
+
if (searchCount >= ResearchAgent.NUDGE_AFTER) {
|
|
72
|
+
parts.push(ResearchPrompts.WRAP_UP);
|
|
73
|
+
}
|
|
74
|
+
return parts.join("\n\n");
|
|
75
|
+
};
|
|
76
|
+
const outcome = await this.chat.runToolLoop({
|
|
77
|
+
system: ResearchPrompts.SYSTEM,
|
|
78
|
+
prompt: question,
|
|
79
|
+
maxSteps,
|
|
80
|
+
timeoutMs,
|
|
81
|
+
toolDescription: ResearchPrompts.SEARCH_TOOL,
|
|
82
|
+
onSearch: runSearch,
|
|
83
|
+
});
|
|
84
|
+
const steps = outcome.steps;
|
|
85
|
+
let answer = outcome.status === "completed" ? outcome.text : "";
|
|
86
|
+
if (outcome.status === "failed") {
|
|
87
|
+
return this.degrade(question, outcome.error, trace, steps, started);
|
|
88
|
+
}
|
|
89
|
+
if (outcome.status === "interrupted") {
|
|
90
|
+
trace.noted(outcome.reason === "timeout"
|
|
91
|
+
? `Timed out after ${timeoutMs}ms`
|
|
92
|
+
: "Model context exceeded mid-loop — synthesizing from gathered evidence.");
|
|
93
|
+
}
|
|
94
|
+
// The provider cannot be made to force a tool call (LM Studio ignores
|
|
95
|
+
// toolChoice), so the model sometimes answers from prior knowledge. An
|
|
96
|
+
// answer with no search behind it is ungrounded by construction —
|
|
97
|
+
// discard it and ground the question directly.
|
|
98
|
+
if (searchCount === 0) {
|
|
99
|
+
trace.noted("Model answered without searching — grounding from a direct search.");
|
|
100
|
+
try {
|
|
101
|
+
const hits = await this.runSearch(question, {
|
|
102
|
+
limit: ResearchAgent.DEFAULT_SEARCH_LIMIT,
|
|
103
|
+
});
|
|
104
|
+
trace.searched(question, hits.length);
|
|
105
|
+
ledger.ingest(hits.toArray());
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
return this.degrade(question, err, trace, steps, started);
|
|
109
|
+
}
|
|
110
|
+
answer = "";
|
|
111
|
+
}
|
|
112
|
+
if (!answer) {
|
|
113
|
+
answer =
|
|
114
|
+
(await this.synthesize(question, ledger, trace, timeoutMs)) ?? "";
|
|
115
|
+
}
|
|
116
|
+
if (!answer) {
|
|
117
|
+
return this.degrade(question, new Error("Model produced no answer."), trace, steps, started);
|
|
118
|
+
}
|
|
119
|
+
// Small models drop [n] markers inconsistently on terse answers. One
|
|
120
|
+
// cheap annotation pass beats returning an uncitable result.
|
|
121
|
+
if (!CitationMarkers.present(answer) && !ledger.isEmpty) {
|
|
122
|
+
answer = await this.addCitations(answer, ledger, trace, timeoutMs);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
question,
|
|
126
|
+
answer,
|
|
127
|
+
sources: CitationMarkers.resolve(answer, ledger.sources),
|
|
128
|
+
trace: trace.toArray(),
|
|
129
|
+
steps,
|
|
130
|
+
elapsedMs: Date.now() - started,
|
|
131
|
+
degraded: false,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
runSearch(query, options) {
|
|
135
|
+
return this.searcher.search(query, new SearchCriteria(options));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* One-shot synthesis over a budgeted digest, in a fresh context with no
|
|
139
|
+
* tool transcript to replay — which is what makes it work even when the
|
|
140
|
+
* agentic loop overflowed the window.
|
|
141
|
+
*/
|
|
142
|
+
async synthesize(question, ledger, trace, timeoutMs) {
|
|
143
|
+
if (ledger.isEmpty)
|
|
144
|
+
return undefined;
|
|
145
|
+
trace.noted("Synthesizing answer from evidence…");
|
|
146
|
+
return this.chat.complete({
|
|
147
|
+
system: ResearchPrompts.SYSTEM,
|
|
148
|
+
prompt: `Question: ${question}\n\nEvidence gathered from the codebase:\n\n` +
|
|
149
|
+
`${ledger.digest()}\n\n${ResearchPrompts.FORCE_ANSWER}`,
|
|
150
|
+
timeoutMs,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/** Ask the model to insert markers into its own answer, wording unchanged. */
|
|
154
|
+
async addCitations(answer, ledger, trace, timeoutMs) {
|
|
155
|
+
trace.noted("Answer had no citations — adding them.");
|
|
156
|
+
const revised = await this.chat.complete({
|
|
157
|
+
system: ResearchPrompts.ADD_CITATIONS,
|
|
158
|
+
prompt: `Sources:\n${ledger.menu()}\n\nAnswer to annotate:\n${answer}`,
|
|
159
|
+
timeoutMs,
|
|
160
|
+
});
|
|
161
|
+
// Keep the original if the retry failed or still has no markers.
|
|
162
|
+
return revised && CitationMarkers.present(revised) ? revised : answer;
|
|
163
|
+
}
|
|
164
|
+
/** Last resort: return the raw hits, clearly marked as un-synthesized. */
|
|
165
|
+
async degrade(question, error, trace, steps, started) {
|
|
166
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
167
|
+
trace.noted(`Synthesis unavailable: ${message}`);
|
|
168
|
+
let sources = [];
|
|
169
|
+
let body;
|
|
170
|
+
try {
|
|
171
|
+
const hits = await this.runSearch(question, {
|
|
172
|
+
limit: ResearchAgent.DEFAULT_SEARCH_LIMIT,
|
|
173
|
+
});
|
|
174
|
+
const list = hits.toArray();
|
|
175
|
+
sources = list.map((hit, i) => ({
|
|
176
|
+
n: i + 1,
|
|
177
|
+
path: hit.location.filePath,
|
|
178
|
+
startLine: hit.location.startLine,
|
|
179
|
+
endLine: hit.location.endLine,
|
|
180
|
+
}));
|
|
181
|
+
body = list.length
|
|
182
|
+
? list
|
|
183
|
+
.map((hit, i) => `[${i + 1}] ${hit.location} (${hit.type} ${hit.name})`)
|
|
184
|
+
.join("\n")
|
|
185
|
+
: "No results found.";
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
body = "No results found (search also failed).";
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
question,
|
|
192
|
+
answer: `Synthesis unavailable (${message}). Raw search results:\n${body}`,
|
|
193
|
+
sources,
|
|
194
|
+
trace: trace.toArray(),
|
|
195
|
+
steps,
|
|
196
|
+
elapsedMs: Date.now() - started,
|
|
197
|
+
degraded: true,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=ResearchAgent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResearchAgent.js","sourceRoot":"","sources":["../../../src/application/research/ResearchAgent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The instructions given to the research model.
|
|
3
|
+
*
|
|
4
|
+
* Tuned against small local models, which is why they are unusually blunt
|
|
5
|
+
* about stopping: left to themselves these models keep searching for
|
|
6
|
+
* completeness, and every extra step costs seconds.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ResearchPrompts {
|
|
9
|
+
static readonly SYSTEM: string;
|
|
10
|
+
/** How the one available tool is described to the model. */
|
|
11
|
+
static readonly SEARCH_TOOL = "Semantic code search. Returns the top matching code units, each with a [n] id, file:line, and its source. This is the only tool \u2014 answer from what it returns.";
|
|
12
|
+
static readonly FORCE_ANSWER = "Using ONLY the evidence above, write the final answer now. Cite [n] for every claim, reusing the ids shown. If the evidence is insufficient, say so plainly and list what is still missing. Do not ask to search further.";
|
|
13
|
+
static readonly ADD_CITATIONS = "You add source citations to an existing answer. Insert [n] markers after the claims each source supports, using the ids from the source list. Do not change the wording or substance otherwise. Output only the revised answer.";
|
|
14
|
+
static readonly BUDGET_EXHAUSTED = "Search budget exhausted. Stop searching and answer from what you have.";
|
|
15
|
+
static readonly WRAP_UP = "(You've searched several times \u2014 answer now from what you've gathered unless a specific detail is still missing.)";
|
|
16
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The instructions given to the research model.
|
|
3
|
+
*
|
|
4
|
+
* Tuned against small local models, which is why they are unusually blunt
|
|
5
|
+
* about stopping: left to themselves these models keep searching for
|
|
6
|
+
* completeness, and every extra step costs seconds.
|
|
7
|
+
*/
|
|
8
|
+
export class ResearchPrompts {
|
|
9
|
+
static SYSTEM = [
|
|
10
|
+
"You are a code research assistant working inside a repository. Answer the user's question by searching the codebase and writing a concise, grounded answer.",
|
|
11
|
+
"",
|
|
12
|
+
"Tool:",
|
|
13
|
+
"- search({query, filePrefix?, type?, language?, limit?}): semantic code search. Returns the top matching code units (functions, classes, blocks), each with a [n] id, its file:line, and its source. Phrase `query` as a natural-language intent, not keywords. The returned source is what you answer from — there is no separate file-reading step.",
|
|
14
|
+
"",
|
|
15
|
+
"Method — be decisive, minimize steps (each step is slow):",
|
|
16
|
+
"- ALWAYS search before answering. Never answer from prior knowledge or assumptions — the codebase is the only source of truth, and defaults, names, and behavior often differ from what you'd guess.",
|
|
17
|
+
"- A grounded, focused answer beats an exhaustive survey. Aim to answer in as few searches as possible.",
|
|
18
|
+
"- Typical shape: one search → answer. Search again ONLY if the results revealed a specific gap, or surfaced codebase vocabulary you should follow up on with a sharper query.",
|
|
19
|
+
"- Never search for completeness, breadth, or to double-check. The moment the results let you answer, STOP searching and write the answer.",
|
|
20
|
+
"",
|
|
21
|
+
"Answer rules:",
|
|
22
|
+
'- Cite with the [n] id, never a bare file path. Every claim needs a [n]. Example: write "changes are debounced for 2s [2]", not "in scanner.ts, changes are debounced".',
|
|
23
|
+
"- Do NOT paste code blocks or quote source verbatim. Describe what the code does in your own words and cite [n].",
|
|
24
|
+
"- Be tight: what the code does, where, and how. No tours, no restating the question.",
|
|
25
|
+
"- If the results do not answer the question, say so plainly and list what's missing. Never invent file paths, line numbers, or behavior.",
|
|
26
|
+
].join("\n");
|
|
27
|
+
/** How the one available tool is described to the model. */
|
|
28
|
+
static SEARCH_TOOL = "Semantic code search. Returns the top matching code units, each with a [n] id, file:line, and its source. This is the only tool — answer from what it returns.";
|
|
29
|
+
static FORCE_ANSWER = "Using ONLY the evidence above, write the final answer now. Cite [n] for every claim, reusing the ids shown. If the evidence is insufficient, say so plainly and list what is still missing. Do not ask to search further.";
|
|
30
|
+
static ADD_CITATIONS = "You add source citations to an existing answer. Insert [n] markers after the claims each source supports, using the ids from the source list. Do not change the wording or substance otherwise. Output only the revised answer.";
|
|
31
|
+
static BUDGET_EXHAUSTED = "Search budget exhausted. Stop searching and answer from what you have.";
|
|
32
|
+
static WRAP_UP = "(You've searched several times — answer now from what you've gathered unless a specific detail is still missing.)";
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=ResearchPrompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResearchPrompts.js","sourceRoot":"","sources":["../../../src/application/research/ResearchPrompts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,OAAO,eAAe;IAC3B,MAAM,CAAU,MAAM,GAAG;QACxB,6JAA6J;QAC7J,EAAE;QACF,OAAO;QACP,uVAAuV;QACvV,EAAE;QACF,2DAA2D;QAC3D,sMAAsM;QACtM,wGAAwG;QACxG,+KAA+K;QAC/K,2IAA2I;QAC3I,EAAE;QACF,eAAe;QACf,yKAAyK;QACzK,kHAAkH;QAClH,sFAAsF;QACtF,0IAA0I;KAC1I,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,4DAA4D;IAC5D,MAAM,CAAU,WAAW,GAC1B,gKAAgK,CAAC;IAElK,MAAM,CAAU,YAAY,GAC3B,2NAA2N,CAAC;IAE7N,MAAM,CAAU,aAAa,GAC5B,iOAAiO,CAAC;IAEnO,MAAM,CAAU,gBAAgB,GAC/B,wEAAwE,CAAC;IAE1E,MAAM,CAAU,OAAO,GACtB,mHAAmH,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Hit } from "../../domain/retrieval/Hit.js";
|
|
2
|
+
/** Everything a caller can ask of a search. */
|
|
3
|
+
export interface SearchOptions {
|
|
4
|
+
limit?: number;
|
|
5
|
+
filePrefix?: string;
|
|
6
|
+
/** Push results away from this meaning. */
|
|
7
|
+
not?: string;
|
|
8
|
+
minScore?: number;
|
|
9
|
+
/** Only chunks of these AST types. */
|
|
10
|
+
type?: string[];
|
|
11
|
+
/** Only files with these extensions (".ts", ".py"). */
|
|
12
|
+
language?: string[];
|
|
13
|
+
/** Search another project's index instead of this one. */
|
|
14
|
+
project?: string;
|
|
15
|
+
/** Search several project indexes and merge by score. */
|
|
16
|
+
across?: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A search request, with the filters that can only be applied after retrieval.
|
|
20
|
+
*
|
|
21
|
+
* Language and score filters live here rather than in the query because
|
|
22
|
+
* neither is stored in a form the vector index can filter on: extensions are a
|
|
23
|
+
* property of the path, and scores only exist once distances are computed.
|
|
24
|
+
*/
|
|
25
|
+
export declare class SearchCriteria {
|
|
26
|
+
private readonly options;
|
|
27
|
+
static readonly DEFAULT_LIMIT = 25;
|
|
28
|
+
private readonly extensions;
|
|
29
|
+
constructor(options: SearchOptions);
|
|
30
|
+
get limit(): number;
|
|
31
|
+
get filePrefix(): string | undefined;
|
|
32
|
+
get types(): string[] | undefined;
|
|
33
|
+
get negation(): string | undefined;
|
|
34
|
+
get project(): string | undefined;
|
|
35
|
+
get across(): string[] | undefined;
|
|
36
|
+
admits(hit: Hit): boolean;
|
|
37
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A search request, with the filters that can only be applied after retrieval.
|
|
3
|
+
*
|
|
4
|
+
* Language and score filters live here rather than in the query because
|
|
5
|
+
* neither is stored in a form the vector index can filter on: extensions are a
|
|
6
|
+
* property of the path, and scores only exist once distances are computed.
|
|
7
|
+
*/
|
|
8
|
+
export class SearchCriteria {
|
|
9
|
+
options;
|
|
10
|
+
static DEFAULT_LIMIT = 25;
|
|
11
|
+
extensions;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
const languages = options.language;
|
|
15
|
+
this.extensions =
|
|
16
|
+
languages && languages.length > 0
|
|
17
|
+
? new Set(languages.map((l) => (l.startsWith(".") ? l : `.${l}`)))
|
|
18
|
+
: undefined;
|
|
19
|
+
}
|
|
20
|
+
get limit() {
|
|
21
|
+
return this.options.limit ?? SearchCriteria.DEFAULT_LIMIT;
|
|
22
|
+
}
|
|
23
|
+
get filePrefix() {
|
|
24
|
+
return this.options.filePrefix;
|
|
25
|
+
}
|
|
26
|
+
get types() {
|
|
27
|
+
return this.options.type;
|
|
28
|
+
}
|
|
29
|
+
get negation() {
|
|
30
|
+
return this.options.not;
|
|
31
|
+
}
|
|
32
|
+
get project() {
|
|
33
|
+
return this.options.project;
|
|
34
|
+
}
|
|
35
|
+
get across() {
|
|
36
|
+
return this.options.across;
|
|
37
|
+
}
|
|
38
|
+
admits(hit) {
|
|
39
|
+
if (this.extensions && !this.extensions.has(hit.location.extension)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (this.options.minScore != null && hit.score < this.options.minScore) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=SearchCriteria.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchCriteria.js","sourceRoot":"","sources":["../../../src/application/search/SearchCriteria.ts"],"names":[],"mappings":"AAmBA;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IAKG;IAJ7B,MAAM,CAAU,aAAa,GAAG,EAAE,CAAC;IAElB,UAAU,CAA0B;IAErD,YAA6B,OAAsB;QAAtB,YAAO,GAAP,OAAO,CAAe;QAClD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QACnC,IAAI,CAAC,UAAU;YACd,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;gBAChC,CAAC,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBAClE,CAAC,CAAC,SAAS,CAAC;IACf,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC,aAAa,CAAC;IAC3D,CAAC;IAED,IAAI,UAAU;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;IAChC,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;IACzB,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED,IAAI,MAAM;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,MAAM,CAAC,GAAQ;QACd,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACrE,OAAO,KAAK,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,IAAI,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACxE,OAAO,KAAK,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { LmgrepConfig } from "../../domain/config/LmgrepConfig.js";
|
|
2
|
+
import type { EmbedderPort } from "../../domain/ports/EmbedderPort.js";
|
|
3
|
+
import type { LoggerPort } from "../../domain/ports/LoggerPort.js";
|
|
4
|
+
import type { IndexMetadata } from "../../domain/project/IndexMetadata.js";
|
|
5
|
+
import { HitList } from "../../domain/retrieval/HitList.js";
|
|
6
|
+
import type { IndexAlternatives } from "../operations/IndexAlternatives.js";
|
|
7
|
+
import type { SearchCriteria } from "./SearchCriteria.js";
|
|
8
|
+
import type { SearchTargetResolver } from "./SearchTargetResolver.js";
|
|
9
|
+
/**
|
|
10
|
+
* Runs a semantic search: embed the query, retrieve from every target index,
|
|
11
|
+
* merge, and apply the filters retrieval cannot.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SearchService {
|
|
14
|
+
private readonly embedder;
|
|
15
|
+
private readonly targets;
|
|
16
|
+
private readonly config;
|
|
17
|
+
private readonly logger;
|
|
18
|
+
private readonly readMetadata;
|
|
19
|
+
private readonly alternatives;
|
|
20
|
+
/**
|
|
21
|
+
* How strongly a `--not` query pushes results away. Full subtraction
|
|
22
|
+
* overshoots into unrelated space; half keeps the original intent dominant
|
|
23
|
+
* while still displacing the unwanted sense.
|
|
24
|
+
*/
|
|
25
|
+
private static readonly NEGATION_WEIGHT;
|
|
26
|
+
constructor(embedder: EmbedderPort, targets: SearchTargetResolver, config: LmgrepConfig, logger: LoggerPort, readMetadata: () => IndexMetadata | undefined, alternatives: IndexAlternatives);
|
|
27
|
+
search(query: string, criteria: SearchCriteria): Promise<HitList>;
|
|
28
|
+
private retrieveFrom;
|
|
29
|
+
private buildQueryVector;
|
|
30
|
+
/**
|
|
31
|
+
* A width mismatch is fatal — the vectors are simply incomparable. A family
|
|
32
|
+
* mismatch is only a warning: results degrade rather than break, and the
|
|
33
|
+
* user may have deliberately swapped a compatible model.
|
|
34
|
+
*/
|
|
35
|
+
private verifyModelCompatibility;
|
|
36
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { ModelIdentity } from "../../domain/project/ModelIdentity.js";
|
|
2
|
+
import { HitList } from "../../domain/retrieval/HitList.js";
|
|
3
|
+
import { MissingIndexError } from "../../domain/retrieval/MissingIndexError.js";
|
|
4
|
+
/**
|
|
5
|
+
* Runs a semantic search: embed the query, retrieve from every target index,
|
|
6
|
+
* merge, and apply the filters retrieval cannot.
|
|
7
|
+
*/
|
|
8
|
+
export class SearchService {
|
|
9
|
+
embedder;
|
|
10
|
+
targets;
|
|
11
|
+
config;
|
|
12
|
+
logger;
|
|
13
|
+
readMetadata;
|
|
14
|
+
alternatives;
|
|
15
|
+
/**
|
|
16
|
+
* How strongly a `--not` query pushes results away. Full subtraction
|
|
17
|
+
* overshoots into unrelated space; half keeps the original intent dominant
|
|
18
|
+
* while still displacing the unwanted sense.
|
|
19
|
+
*/
|
|
20
|
+
static NEGATION_WEIGHT = 0.5;
|
|
21
|
+
constructor(embedder, targets, config, logger, readMetadata, alternatives) {
|
|
22
|
+
this.embedder = embedder;
|
|
23
|
+
this.targets = targets;
|
|
24
|
+
this.config = config;
|
|
25
|
+
this.logger = logger;
|
|
26
|
+
this.readMetadata = readMetadata;
|
|
27
|
+
this.alternatives = alternatives;
|
|
28
|
+
}
|
|
29
|
+
async search(query, criteria) {
|
|
30
|
+
const queryVector = await this.buildQueryVector(query, criteria);
|
|
31
|
+
const targets = await this.targets.resolve(criteria);
|
|
32
|
+
try {
|
|
33
|
+
const merged = await this.retrieveFrom(targets, queryVector, criteria);
|
|
34
|
+
return merged.filtered((hit) => criteria.admits(hit));
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
// "No index found" is accurate and useless on its own: the usual
|
|
38
|
+
// cause is a model change, and the index the user is thinking of is
|
|
39
|
+
// intact one directory away.
|
|
40
|
+
if (err instanceof MissingIndexError) {
|
|
41
|
+
const absence = this.alternatives.explainAbsence();
|
|
42
|
+
if (absence) {
|
|
43
|
+
throw new MissingIndexError(`${absence.reason}\n${absence.fix}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
await this.targets.release(targets);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async retrieveFrom(targets, queryVector, criteria) {
|
|
53
|
+
let merged = HitList.empty();
|
|
54
|
+
for (const target of targets) {
|
|
55
|
+
const page = await target.chunks.search({
|
|
56
|
+
vector: queryVector,
|
|
57
|
+
limit: criteria.limit,
|
|
58
|
+
filePrefix: target.filePrefix,
|
|
59
|
+
types: criteria.types,
|
|
60
|
+
// A foreign index has no manifest for our branch, so scoping to
|
|
61
|
+
// it would filter everything away.
|
|
62
|
+
scopeToBranch: target.projectRoot === undefined,
|
|
63
|
+
});
|
|
64
|
+
merged = merged.concat(target.projectRoot
|
|
65
|
+
? page.mapped((hit) => hit.relocatedUnder(target.projectRoot))
|
|
66
|
+
: page);
|
|
67
|
+
}
|
|
68
|
+
// Scores are comparable across indexes only when the same model built
|
|
69
|
+
// them; re-sorting is still the best available merge.
|
|
70
|
+
return targets.length > 1
|
|
71
|
+
? merged.sortedByScoreDescending().takeAtMost(criteria.limit)
|
|
72
|
+
: merged;
|
|
73
|
+
}
|
|
74
|
+
async buildQueryVector(query, criteria) {
|
|
75
|
+
const vector = await this.embedder.embedQuery(query);
|
|
76
|
+
this.verifyModelCompatibility(vector);
|
|
77
|
+
const negation = criteria.negation;
|
|
78
|
+
if (!negation)
|
|
79
|
+
return vector;
|
|
80
|
+
const away = await this.embedder.embedQuery(negation);
|
|
81
|
+
return vector.minus(away.scaledBy(SearchService.NEGATION_WEIGHT));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A width mismatch is fatal — the vectors are simply incomparable. A family
|
|
85
|
+
* mismatch is only a warning: results degrade rather than break, and the
|
|
86
|
+
* user may have deliberately swapped a compatible model.
|
|
87
|
+
*/
|
|
88
|
+
verifyModelCompatibility(queryVector) {
|
|
89
|
+
const meta = this.readMetadata();
|
|
90
|
+
if (!meta)
|
|
91
|
+
return;
|
|
92
|
+
if (meta.dimensions != null && queryVector.dimensions !== meta.dimensions) {
|
|
93
|
+
throw new Error(`Dimension mismatch: index has ${meta.dimensions}-dim vectors but ` +
|
|
94
|
+
`your model produces ${queryVector.dimensions}-dim. ` +
|
|
95
|
+
"These embeddings are incompatible.");
|
|
96
|
+
}
|
|
97
|
+
if (!meta.model)
|
|
98
|
+
return;
|
|
99
|
+
const indexModel = ModelIdentity.of(meta.model);
|
|
100
|
+
const queryModel = ModelIdentity.of(this.config.model);
|
|
101
|
+
if (!indexModel.isSameFamilyAs(queryModel)) {
|
|
102
|
+
this.logger.info(`Warning: index was built with "${meta.model}" (${indexModel.family}) ` +
|
|
103
|
+
`but searching with "${this.config.model}" (${queryModel.family}). ` +
|
|
104
|
+
"Results may be degraded if these are different model families.");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=SearchService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchService.js","sourceRoot":"","sources":["../../../src/application/search/SearchService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ChunkRepositoryPort } from "../../domain/ports/ChunkRepositoryPort.js";
|
|
2
|
+
import type { DatabaseLocation } from "../../domain/project/DatabaseLocation.js";
|
|
3
|
+
import type { ProjectLocator } from "../../domain/project/ProjectLocator.js";
|
|
4
|
+
import type { SearchCriteria } from "./SearchCriteria.js";
|
|
5
|
+
/** One index a search should consult. */
|
|
6
|
+
export interface SearchTarget {
|
|
7
|
+
chunks: ChunkRepositoryPort;
|
|
8
|
+
filePrefix?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Absolute root of a foreign project, used to make its relative paths
|
|
11
|
+
* meaningful here. Undefined for the local index.
|
|
12
|
+
*/
|
|
13
|
+
projectRoot?: string;
|
|
14
|
+
/** Whether this target was opened for the query and must be closed after. */
|
|
15
|
+
borrowed: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Opens a chunk repository for another project's database. */
|
|
18
|
+
export interface ForeignIndexOpener {
|
|
19
|
+
open(projectPath: string): Promise<{
|
|
20
|
+
chunks: ChunkRepositoryPort;
|
|
21
|
+
close: () => Promise<void>;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Decides which indexes a search reads.
|
|
26
|
+
*
|
|
27
|
+
* Three cases, in precedence order: `--across` merges several projects,
|
|
28
|
+
* `--project` redirects to one, and the default resolves the local project —
|
|
29
|
+
* including the case where the working directory sits below an indexed root,
|
|
30
|
+
* where the offset becomes a path prefix filter.
|
|
31
|
+
*/
|
|
32
|
+
export declare class SearchTargetResolver {
|
|
33
|
+
private readonly cwd;
|
|
34
|
+
private readonly local;
|
|
35
|
+
private readonly location;
|
|
36
|
+
private readonly locator;
|
|
37
|
+
private readonly foreign;
|
|
38
|
+
private readonly opened;
|
|
39
|
+
constructor(cwd: string, local: ChunkRepositoryPort, location: DatabaseLocation, locator: ProjectLocator, foreign: ForeignIndexOpener);
|
|
40
|
+
resolve(criteria: SearchCriteria): Promise<SearchTarget[]>;
|
|
41
|
+
/** Close the databases this resolver opened; leave the local one alone. */
|
|
42
|
+
release(targets: SearchTarget[]): Promise<void>;
|
|
43
|
+
private openForeign;
|
|
44
|
+
/**
|
|
45
|
+
* The local index, with the working directory's offset from the project
|
|
46
|
+
* root folded into the prefix filter — so searching from `src/lib` only
|
|
47
|
+
* returns hits from there. A manually targeted database is flat and skips
|
|
48
|
+
* this entirely.
|
|
49
|
+
*
|
|
50
|
+
* Inside a git repo the ancestor resolves to the same database, because
|
|
51
|
+
* project identity is the remote. Outside git the walk-up can land on a
|
|
52
|
+
* genuinely different database — an indexed parent directory — which must
|
|
53
|
+
* be opened rather than substituted with the local one.
|
|
54
|
+
*/
|
|
55
|
+
private resolveLocal;
|
|
56
|
+
}
|