lmgrep 0.1.18 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -62
- 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 +94 -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/DockerModelRunnerProbe.d.ts +16 -0
- package/dist/infrastructure/ai/DockerModelRunnerProbe.js +52 -0
- package/dist/infrastructure/ai/DockerModelRunnerProbe.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 +63 -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 +22 -0
- package/dist/infrastructure/ai/OllamaProbe.js +71 -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 +14 -0
- package/dist/infrastructure/ai/ProviderModuleLoader.js +56 -0
- package/dist/infrastructure/ai/ProviderModuleLoader.js.map +1 -0
- package/dist/infrastructure/ai/ProviderRegistry.d.ts +38 -0
- package/dist/infrastructure/ai/ProviderRegistry.js +63 -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/EmbeddedTreeSitterAssets.d.ts +8 -0
- package/dist/infrastructure/treesitter/EmbeddedTreeSitterAssets.js +12 -0
- package/dist/infrastructure/treesitter/EmbeddedTreeSitterAssets.js.map +1 -0
- package/dist/infrastructure/treesitter/LanguageCatalog.d.ts +30 -0
- package/dist/{lib/chunker/languages.js → infrastructure/treesitter/LanguageCatalog.js} +38 -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 +165 -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 +56 -0
- package/dist/presentation/cli/commands/ConfigCommands.js +220 -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 +93 -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,171 @@
|
|
|
1
|
+
import { Deadline } from "./Deadline.js";
|
|
2
|
+
/**
|
|
3
|
+
* Reports what the index holds and whether it actually works.
|
|
4
|
+
*
|
|
5
|
+
* The two liveness checks are deliberately shallow and time-boxed: `status`
|
|
6
|
+
* must stay responsive even when the embedder is wedged, since diagnosing that
|
|
7
|
+
* is exactly why someone runs it.
|
|
8
|
+
*/
|
|
9
|
+
export class StatusService {
|
|
10
|
+
chunks;
|
|
11
|
+
maintenance;
|
|
12
|
+
embedder;
|
|
13
|
+
locator;
|
|
14
|
+
metadata;
|
|
15
|
+
location;
|
|
16
|
+
config;
|
|
17
|
+
cwd;
|
|
18
|
+
configSources;
|
|
19
|
+
alternatives;
|
|
20
|
+
static PROBE_TIMEOUT_MS = 3000;
|
|
21
|
+
/** A word generic enough to match something in any codebase. */
|
|
22
|
+
static SMOKE_QUERY = "code";
|
|
23
|
+
constructor(chunks, maintenance, embedder, locator, metadata, location, config, cwd, configSources, alternatives) {
|
|
24
|
+
this.chunks = chunks;
|
|
25
|
+
this.maintenance = maintenance;
|
|
26
|
+
this.embedder = embedder;
|
|
27
|
+
this.locator = locator;
|
|
28
|
+
this.metadata = metadata;
|
|
29
|
+
this.location = location;
|
|
30
|
+
this.config = config;
|
|
31
|
+
this.cwd = cwd;
|
|
32
|
+
this.configSources = configSources;
|
|
33
|
+
this.alternatives = alternatives;
|
|
34
|
+
}
|
|
35
|
+
async status() {
|
|
36
|
+
// A manually targeted database is flat — no ancestor or prefix walking.
|
|
37
|
+
const ancestor = this.location.isGitAware
|
|
38
|
+
? this.locator.findIndexedAncestor(this.cwd)
|
|
39
|
+
: undefined;
|
|
40
|
+
const projectRoot = this.location.manual
|
|
41
|
+
? this.location.root
|
|
42
|
+
: (ancestor?.root ?? this.cwd);
|
|
43
|
+
const filesByPath = await this.chunks.hashesByFile();
|
|
44
|
+
const hashes = await this.chunks.allHashes();
|
|
45
|
+
let chunkCount = 0;
|
|
46
|
+
for (const [, list] of filesByPath)
|
|
47
|
+
chunkCount += list.length;
|
|
48
|
+
const probe = await this.probe(filesByPath.size > 0);
|
|
49
|
+
const meta = this.metadata.read(this.location.manual
|
|
50
|
+
? this.location.path
|
|
51
|
+
: this.locator.databasePathFor(projectRoot));
|
|
52
|
+
const vectorIndex = await this.maintenance.vectorIndexState();
|
|
53
|
+
const info = {
|
|
54
|
+
projectRoot,
|
|
55
|
+
prefix: ancestor?.prefix ?? "",
|
|
56
|
+
databasePath: this.location.path,
|
|
57
|
+
config: this.config,
|
|
58
|
+
configSources: this.configSources,
|
|
59
|
+
fileCount: filesByPath.size,
|
|
60
|
+
chunkCount,
|
|
61
|
+
uniqueHashes: hashes.size,
|
|
62
|
+
...probe,
|
|
63
|
+
vectorIndex,
|
|
64
|
+
indexModel: meta?.model,
|
|
65
|
+
indexDimensions: meta?.dimensions,
|
|
66
|
+
};
|
|
67
|
+
return { ...info, verdict: this.judge(info) };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Reduce the probes to one answer, in the order a user would care.
|
|
71
|
+
*
|
|
72
|
+
* A missing vector index is a note rather than a failure: search works, it
|
|
73
|
+
* is just answering by reading every embedding, which nothing else would
|
|
74
|
+
* tell you.
|
|
75
|
+
*/
|
|
76
|
+
judge(info) {
|
|
77
|
+
if (info.fileCount === 0) {
|
|
78
|
+
// An empty database for the configured model usually means the
|
|
79
|
+
// model changed, not that the project was never indexed.
|
|
80
|
+
const absence = this.alternatives.explainAbsence();
|
|
81
|
+
return absence
|
|
82
|
+
? { searchable: false, reason: absence.reason, fix: absence.fix }
|
|
83
|
+
: {
|
|
84
|
+
searchable: false,
|
|
85
|
+
reason: "This project is not indexed.",
|
|
86
|
+
fix: "lmgrep index",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (!info.embeddingOk) {
|
|
90
|
+
return {
|
|
91
|
+
searchable: false,
|
|
92
|
+
reason: `The embedding provider is unreachable — ${info.embeddingError ?? "no response"}`,
|
|
93
|
+
fix: `Start the server at ${this.config.baseURL ?? "your configured baseURL"}, then retry.`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (!info.searchOk) {
|
|
97
|
+
// Manifests are per branch while chunks are shared by content, so
|
|
98
|
+
// a checkout that has never been indexed searches an empty scope
|
|
99
|
+
// over a full database. That is an ordinary state on a new
|
|
100
|
+
// worktree or branch, and telling someone to `--reset` over it
|
|
101
|
+
// would throw away a working index for no reason.
|
|
102
|
+
return info.anyBranchOk
|
|
103
|
+
? {
|
|
104
|
+
searchable: false,
|
|
105
|
+
reason: "This branch has not been indexed yet.",
|
|
106
|
+
fix: "lmgrep index",
|
|
107
|
+
}
|
|
108
|
+
: {
|
|
109
|
+
searchable: false,
|
|
110
|
+
reason: "The index holds files but answered a test query with nothing — it is likely stale or was built with a different model.",
|
|
111
|
+
fix: "lmgrep index --reset",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (!info.vectorIndex.built && info.vectorIndex.worthBuilding) {
|
|
115
|
+
return {
|
|
116
|
+
searchable: true,
|
|
117
|
+
note: `Every search reads all ${info.vectorIndex.rows} embeddings — slow, and roughly the ` +
|
|
118
|
+
"index's size in memory per query. `lmgrep index` builds the vector index.",
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return { searchable: true };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Embed once and reuse the vector for the search check — one roundtrip
|
|
125
|
+
* covers both, which keeps `status` cheap against a billed provider.
|
|
126
|
+
*/
|
|
127
|
+
async probe(hasFiles) {
|
|
128
|
+
const deadline = Deadline.after(StatusService.PROBE_TIMEOUT_MS);
|
|
129
|
+
let vector;
|
|
130
|
+
let embeddingLatencyMs;
|
|
131
|
+
try {
|
|
132
|
+
const started = Date.now();
|
|
133
|
+
vector = await deadline.enforce(this.embedder.embedQuery(StatusService.SMOKE_QUERY));
|
|
134
|
+
embeddingLatencyMs = Date.now() - started;
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
return {
|
|
138
|
+
embeddingOk: false,
|
|
139
|
+
searchOk: false,
|
|
140
|
+
embeddingError: err instanceof Error ? err.message : String(err),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (!hasFiles) {
|
|
144
|
+
return { embeddingOk: true, embeddingLatencyMs, searchOk: false };
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const started = Date.now();
|
|
148
|
+
const hits = await deadline.enforce(this.chunks.search({ vector, limit: 1, scopeToBranch: true }));
|
|
149
|
+
// Only when the scoped query found nothing: the unscoped one is a
|
|
150
|
+
// second query, and it is worth running solely to tell an
|
|
151
|
+
// unindexed branch apart from a broken index.
|
|
152
|
+
const anyBranchOk = hits.length > 0
|
|
153
|
+
? true
|
|
154
|
+
: (await deadline.enforce(this.chunks.search({ vector, limit: 1, scopeToBranch: false }))).length > 0;
|
|
155
|
+
return {
|
|
156
|
+
embeddingOk: true,
|
|
157
|
+
embeddingLatencyMs,
|
|
158
|
+
searchOk: hits.length > 0,
|
|
159
|
+
searchResultCount: hits.length,
|
|
160
|
+
searchLatencyMs: Date.now() - started,
|
|
161
|
+
anyBranchOk,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// The embedder works; the index does not answer. That is a
|
|
166
|
+
// meaningful distinction the caller reports differently.
|
|
167
|
+
return { embeddingOk: true, embeddingLatencyMs, searchOk: false };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=StatusService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusService.js","sourceRoot":"","sources":["../../../src/application/operations/StatusService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { LmgrepConfig } from "../../domain/config/LmgrepConfig.js";
|
|
2
|
+
import type { LockPort } from "../../domain/ports/LockPort.js";
|
|
3
|
+
import type { LoggerPort } from "../../domain/ports/LoggerPort.js";
|
|
4
|
+
import type { WorkspacePort } from "../../domain/ports/WorkspacePort.js";
|
|
5
|
+
import type { IndexBuilder } from "../indexing/IndexBuilder.js";
|
|
6
|
+
/**
|
|
7
|
+
* Keeps an index current while the process runs.
|
|
8
|
+
*
|
|
9
|
+
* Two mechanisms, because neither suffices alone: filesystem events give a
|
|
10
|
+
* fast path for ordinary edits, and a periodic full reconcile is the backstop
|
|
11
|
+
* for what recursive `fs.watch` misses on Linux — new subdirectories, editor
|
|
12
|
+
* atomic saves, event bursts. The reconcile also retries files that failed
|
|
13
|
+
* while the embedder was down, which is what removes the need to re-run
|
|
14
|
+
* `lmgrep index` by hand.
|
|
15
|
+
*/
|
|
16
|
+
export declare class WatchService {
|
|
17
|
+
private readonly builder;
|
|
18
|
+
private readonly workspace;
|
|
19
|
+
private readonly config;
|
|
20
|
+
private readonly cwd;
|
|
21
|
+
private readonly logger;
|
|
22
|
+
private readonly locks;
|
|
23
|
+
/** How often the backstop reconcile runs. */
|
|
24
|
+
private static readonly RECONCILE_MS;
|
|
25
|
+
/** Window for coalescing a burst of filesystem events. */
|
|
26
|
+
private static readonly DEBOUNCE_MS;
|
|
27
|
+
private indexing;
|
|
28
|
+
/** Whether anything arrived while a run was in flight. */
|
|
29
|
+
private queuedWork;
|
|
30
|
+
/**
|
|
31
|
+
* Paths queued mid-run, or undefined when the queued work is a full
|
|
32
|
+
* rebuild. A full rebuild is a superset, so once one is queued no file list
|
|
33
|
+
* may narrow it back down.
|
|
34
|
+
*/
|
|
35
|
+
private queuedFiles;
|
|
36
|
+
private timer;
|
|
37
|
+
private watcher;
|
|
38
|
+
private holdsLock;
|
|
39
|
+
/** The catch-up build is the one allowed to train a vector index. */
|
|
40
|
+
private caughtUp;
|
|
41
|
+
constructor(builder: IndexBuilder, workspace: WorkspacePort, config: LmgrepConfig, cwd: string, logger: LoggerPort, locks: LockPort);
|
|
42
|
+
/**
|
|
43
|
+
* Begin watching. Returns a function that stops it.
|
|
44
|
+
*
|
|
45
|
+
* Acquiring the maintainer lock is what makes exactly one process
|
|
46
|
+
* responsible for a database; it also registers this process so
|
|
47
|
+
* `lmgrep status` can report who is watching. Losing the race is normal —
|
|
48
|
+
* another server already has it — and simply means not watching.
|
|
49
|
+
*/
|
|
50
|
+
start(): () => void;
|
|
51
|
+
private beginWatching;
|
|
52
|
+
stop(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Run an index pass, coalescing anything that arrives while one is in
|
|
55
|
+
* flight. A queued full rebuild wins over queued file lists: it is the
|
|
56
|
+
* superset, and narrowing it would skip work.
|
|
57
|
+
*/
|
|
58
|
+
private reindex;
|
|
59
|
+
/**
|
|
60
|
+
* Merge incoming work into whatever is already queued.
|
|
61
|
+
*
|
|
62
|
+
* The previous implementation used `undefined` both for "nothing queued"
|
|
63
|
+
* and for "a full rebuild is queued", so a reconcile that landed mid-run
|
|
64
|
+
* was silently dropped. The two states are now distinct.
|
|
65
|
+
*/
|
|
66
|
+
private enqueue;
|
|
67
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps an index current while the process runs.
|
|
3
|
+
*
|
|
4
|
+
* Two mechanisms, because neither suffices alone: filesystem events give a
|
|
5
|
+
* fast path for ordinary edits, and a periodic full reconcile is the backstop
|
|
6
|
+
* for what recursive `fs.watch` misses on Linux — new subdirectories, editor
|
|
7
|
+
* atomic saves, event bursts. The reconcile also retries files that failed
|
|
8
|
+
* while the embedder was down, which is what removes the need to re-run
|
|
9
|
+
* `lmgrep index` by hand.
|
|
10
|
+
*/
|
|
11
|
+
export class WatchService {
|
|
12
|
+
builder;
|
|
13
|
+
workspace;
|
|
14
|
+
config;
|
|
15
|
+
cwd;
|
|
16
|
+
logger;
|
|
17
|
+
locks;
|
|
18
|
+
/** How often the backstop reconcile runs. */
|
|
19
|
+
static RECONCILE_MS = 30_000;
|
|
20
|
+
/** Window for coalescing a burst of filesystem events. */
|
|
21
|
+
static DEBOUNCE_MS = 2000;
|
|
22
|
+
indexing = false;
|
|
23
|
+
/** Whether anything arrived while a run was in flight. */
|
|
24
|
+
queuedWork = false;
|
|
25
|
+
/**
|
|
26
|
+
* Paths queued mid-run, or undefined when the queued work is a full
|
|
27
|
+
* rebuild. A full rebuild is a superset, so once one is queued no file list
|
|
28
|
+
* may narrow it back down.
|
|
29
|
+
*/
|
|
30
|
+
queuedFiles;
|
|
31
|
+
timer;
|
|
32
|
+
watcher;
|
|
33
|
+
holdsLock = false;
|
|
34
|
+
/** The catch-up build is the one allowed to train a vector index. */
|
|
35
|
+
caughtUp = false;
|
|
36
|
+
constructor(builder, workspace, config, cwd, logger, locks) {
|
|
37
|
+
this.builder = builder;
|
|
38
|
+
this.workspace = workspace;
|
|
39
|
+
this.config = config;
|
|
40
|
+
this.cwd = cwd;
|
|
41
|
+
this.logger = logger;
|
|
42
|
+
this.locks = locks;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Begin watching. Returns a function that stops it.
|
|
46
|
+
*
|
|
47
|
+
* Acquiring the maintainer lock is what makes exactly one process
|
|
48
|
+
* responsible for a database; it also registers this process so
|
|
49
|
+
* `lmgrep status` can report who is watching. Losing the race is normal —
|
|
50
|
+
* another server already has it — and simply means not watching.
|
|
51
|
+
*/
|
|
52
|
+
start() {
|
|
53
|
+
if (!this.locks.acquireMaintainer()) {
|
|
54
|
+
this.logger.info("Another process is already watching this index.");
|
|
55
|
+
return () => { };
|
|
56
|
+
}
|
|
57
|
+
this.holdsLock = true;
|
|
58
|
+
return this.beginWatching();
|
|
59
|
+
}
|
|
60
|
+
beginWatching() {
|
|
61
|
+
// Catch up first, so a branch checked out while this was not running
|
|
62
|
+
// gets its manifest bootstrapped before any event arrives.
|
|
63
|
+
void this.reindex();
|
|
64
|
+
this.watcher = this.workspace.watch(this.cwd, this.config.ignore, (changed) => void this.reindex(changed), WatchService.DEBOUNCE_MS, this.config.extensions);
|
|
65
|
+
this.timer = setInterval(() => void this.reindex(), WatchService.RECONCILE_MS);
|
|
66
|
+
// Never keep the host process alive on the timer alone.
|
|
67
|
+
this.timer.unref?.();
|
|
68
|
+
this.logger.info("Watching for changes...");
|
|
69
|
+
return () => this.stop();
|
|
70
|
+
}
|
|
71
|
+
stop() {
|
|
72
|
+
if (this.timer)
|
|
73
|
+
clearInterval(this.timer);
|
|
74
|
+
this.timer = undefined;
|
|
75
|
+
this.watcher?.close();
|
|
76
|
+
this.watcher = undefined;
|
|
77
|
+
if (this.holdsLock) {
|
|
78
|
+
this.locks.releaseMaintainer();
|
|
79
|
+
this.holdsLock = false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Run an index pass, coalescing anything that arrives while one is in
|
|
84
|
+
* flight. A queued full rebuild wins over queued file lists: it is the
|
|
85
|
+
* superset, and narrowing it would skip work.
|
|
86
|
+
*/
|
|
87
|
+
async reindex(changedFiles) {
|
|
88
|
+
if (this.indexing) {
|
|
89
|
+
this.enqueue(changedFiles);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
this.indexing = true;
|
|
93
|
+
try {
|
|
94
|
+
this.logger.info(changedFiles?.length
|
|
95
|
+
? `Changes detected in ${changedFiles.length} file(s), re-indexing...`
|
|
96
|
+
: "Changes detected, re-indexing...");
|
|
97
|
+
// Train the vector index on the catch-up build only.
|
|
98
|
+
//
|
|
99
|
+
// Without an index every search brute-force scans the table, which
|
|
100
|
+
// costs roughly the index's own size in peak memory *per query* —
|
|
101
|
+
// measured at ~1GB a search against a 759MB index, versus ~200MB
|
|
102
|
+
// once indexed. Training spikes higher (~2.5GB) but does so once,
|
|
103
|
+
// so for a process that will serve many queries it is the cheaper
|
|
104
|
+
// option as well as the faster one. Incremental ticks stay off it
|
|
105
|
+
// and only absorb the tail.
|
|
106
|
+
await this.builder.build({
|
|
107
|
+
files: changedFiles,
|
|
108
|
+
createIndex: !this.caughtUp,
|
|
109
|
+
});
|
|
110
|
+
this.caughtUp = true;
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
this.logger.error(`Index error: ${err instanceof Error ? err.message : err}`);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
this.indexing = false;
|
|
117
|
+
if (this.queuedWork) {
|
|
118
|
+
const next = this.queuedFiles;
|
|
119
|
+
this.queuedWork = false;
|
|
120
|
+
this.queuedFiles = undefined;
|
|
121
|
+
void this.reindex(next);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Merge incoming work into whatever is already queued.
|
|
127
|
+
*
|
|
128
|
+
* The previous implementation used `undefined` both for "nothing queued"
|
|
129
|
+
* and for "a full rebuild is queued", so a reconcile that landed mid-run
|
|
130
|
+
* was silently dropped. The two states are now distinct.
|
|
131
|
+
*/
|
|
132
|
+
enqueue(changedFiles) {
|
|
133
|
+
if (!changedFiles) {
|
|
134
|
+
this.queuedWork = true;
|
|
135
|
+
this.queuedFiles = undefined;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// A queued full rebuild already covers these paths.
|
|
139
|
+
if (this.queuedWork && this.queuedFiles === undefined)
|
|
140
|
+
return;
|
|
141
|
+
this.queuedWork = true;
|
|
142
|
+
this.queuedFiles = [...(this.queuedFiles ?? []), ...changedFiles];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=WatchService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WatchService.js","sourceRoot":"","sources":["../../../src/application/operations/WatchService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FileManifest } from "../../domain/corpus/SourceFile.js";
|
|
2
|
+
import type { WorkspacePort } from "../../domain/ports/WorkspacePort.js";
|
|
3
|
+
/** How the working tree differs from what the manifest recorded. */
|
|
4
|
+
export interface TreeChanges {
|
|
5
|
+
added: string[];
|
|
6
|
+
modified: string[];
|
|
7
|
+
deleted: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Compares the working tree against the manifest, without changing anything.
|
|
11
|
+
*
|
|
12
|
+
* This is what `lmgrep status --changes` reports: a read-only preview of what
|
|
13
|
+
* the next index run would do, so a user can see whether it is worth running.
|
|
14
|
+
*/
|
|
15
|
+
export declare class WorkingTreeDiff {
|
|
16
|
+
private readonly workspace;
|
|
17
|
+
constructor(workspace: WorkspacePort);
|
|
18
|
+
compute(projectRoot: string, manifest: FileManifest): TreeChanges;
|
|
19
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compares the working tree against the manifest, without changing anything.
|
|
3
|
+
*
|
|
4
|
+
* This is what `lmgrep status --changes` reports: a read-only preview of what
|
|
5
|
+
* the next index run would do, so a user can see whether it is worth running.
|
|
6
|
+
*/
|
|
7
|
+
export class WorkingTreeDiff {
|
|
8
|
+
workspace;
|
|
9
|
+
constructor(workspace) {
|
|
10
|
+
this.workspace = workspace;
|
|
11
|
+
}
|
|
12
|
+
compute(projectRoot, manifest) {
|
|
13
|
+
const added = [];
|
|
14
|
+
const modified = [];
|
|
15
|
+
const deleted = [];
|
|
16
|
+
const seen = new Set();
|
|
17
|
+
for (const file of this.workspace.listFiles(projectRoot)) {
|
|
18
|
+
seen.add(file);
|
|
19
|
+
const hash = this.workspace.hashOf(projectRoot, file);
|
|
20
|
+
// Unreadable right now: not a reportable change either way.
|
|
21
|
+
if (!hash)
|
|
22
|
+
continue;
|
|
23
|
+
const stored = manifest.versionOf(file);
|
|
24
|
+
if (!stored)
|
|
25
|
+
added.push(file);
|
|
26
|
+
else if (!stored.equals(hash))
|
|
27
|
+
modified.push(file);
|
|
28
|
+
}
|
|
29
|
+
for (const path of manifest.paths()) {
|
|
30
|
+
if (!seen.has(path))
|
|
31
|
+
deleted.push(path);
|
|
32
|
+
}
|
|
33
|
+
return { added, modified, deleted };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=WorkingTreeDiff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkingTreeDiff.js","sourceRoot":"","sources":["../../../src/application/operations/WorkingTreeDiff.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IACE;IAA7B,YAA6B,SAAwB;QAAxB,cAAS,GAAT,SAAS,CAAe;IAAG,CAAC;IAEzD,OAAO,CAAC,WAAmB,EAAE,QAAsB;QAClD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACtD,4DAA4D;YAC5D,IAAI,CAAC,IAAI;gBAAE,SAAS;YAEpB,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;iBACzB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpD,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACrC,CAAC;CACD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { LmgrepConfig } from "../../domain/config/LmgrepConfig.js";
|
|
2
|
+
import type { ChatModelPort } from "../../domain/ports/ChatModelPort.js";
|
|
3
|
+
import { type Source } from "../../domain/research/Citation.js";
|
|
4
|
+
import { type TraceEntry } from "../../domain/research/ResearchTrace.js";
|
|
5
|
+
import type { HitList } from "../../domain/retrieval/HitList.js";
|
|
6
|
+
import { SearchCriteria } from "../search/SearchCriteria.js";
|
|
7
|
+
export interface ResearchResult {
|
|
8
|
+
question: string;
|
|
9
|
+
answer: string;
|
|
10
|
+
/** Sources the answer actually cited, in citation order. */
|
|
11
|
+
sources: Source[];
|
|
12
|
+
trace: TraceEntry[];
|
|
13
|
+
steps: number;
|
|
14
|
+
elapsedMs: number;
|
|
15
|
+
/**
|
|
16
|
+
* True when synthesis was unavailable and the result fell back to raw
|
|
17
|
+
* search hits, so the caller knows not to over-trust the answer.
|
|
18
|
+
*/
|
|
19
|
+
degraded: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** How the agent reaches the index. */
|
|
22
|
+
export interface ResearchSearcher {
|
|
23
|
+
search(query: string, criteria: SearchCriteria): Promise<HitList>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Answers a question by searching the codebase and synthesizing a cited answer.
|
|
27
|
+
*
|
|
28
|
+
* Robustness is layered, because a local model fails in several distinct ways
|
|
29
|
+
* and none of them should hard-fail the caller:
|
|
30
|
+
*
|
|
31
|
+
* 1. Happy path — the model self-terminates with a cited answer.
|
|
32
|
+
* 2. It cannot self-terminate (step cap, timeout, or the transcript overflows
|
|
33
|
+
* its context) — synthesize from a budgeted digest in a fresh context.
|
|
34
|
+
* 3. It answered without ever searching — discard that, since it is ungrounded
|
|
35
|
+
* by construction, search directly and synthesize.
|
|
36
|
+
* 4. The model is unreachable — degrade to raw search hits.
|
|
37
|
+
*/
|
|
38
|
+
export declare class ResearchAgent {
|
|
39
|
+
private readonly searcher;
|
|
40
|
+
private readonly chat;
|
|
41
|
+
private readonly config;
|
|
42
|
+
private static readonly DEFAULT_MAX_STEPS;
|
|
43
|
+
/**
|
|
44
|
+
* Wall clock is only a backstop against a wedged run; the search and step
|
|
45
|
+
* budgets bound the real work. A local model doing a few steps plus a cold
|
|
46
|
+
* load can need minutes, so this stays generous.
|
|
47
|
+
*/
|
|
48
|
+
private static readonly DEFAULT_TIMEOUT_MS;
|
|
49
|
+
private static readonly MAX_SEARCHES;
|
|
50
|
+
private static readonly DEFAULT_SEARCH_LIMIT;
|
|
51
|
+
/** The model tends to ask for 10+, which bloats the transcript. */
|
|
52
|
+
private static readonly MAX_SEARCH_LIMIT;
|
|
53
|
+
/** After this many searches, nudge it to wrap up. */
|
|
54
|
+
private static readonly NUDGE_AFTER;
|
|
55
|
+
constructor(searcher: ResearchSearcher, chat: ChatModelPort, config: LmgrepConfig);
|
|
56
|
+
research(question: string, onTrace?: (entry: TraceEntry) => void): Promise<ResearchResult>;
|
|
57
|
+
private runSearch;
|
|
58
|
+
/**
|
|
59
|
+
* One-shot synthesis over a budgeted digest, in a fresh context with no
|
|
60
|
+
* tool transcript to replay — which is what makes it work even when the
|
|
61
|
+
* agentic loop overflowed the window.
|
|
62
|
+
*/
|
|
63
|
+
private synthesize;
|
|
64
|
+
/** Ask the model to insert markers into its own answer, wording unchanged. */
|
|
65
|
+
private addCitations;
|
|
66
|
+
/** Last resort: return the raw hits, clearly marked as un-synthesized. */
|
|
67
|
+
private degrade;
|
|
68
|
+
}
|