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,194 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir, platform } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
/**
|
|
7
|
+
* Loads configuration from two kinds of file, split by what the settings
|
|
8
|
+
* actually describe.
|
|
9
|
+
*
|
|
10
|
+
* **Machine settings** — which model to embed with, which to answer with,
|
|
11
|
+
* where those servers listen — describe *this computer's* inference setup.
|
|
12
|
+
* They live in one global file. They used to be settable per project too,
|
|
13
|
+
* which was the single most confusing thing about lmgrep: the model determines
|
|
14
|
+
* what a stored vector *means*, so a project file could silently point an
|
|
15
|
+
* index at incompatible embeddings, and `status` would report an effective
|
|
16
|
+
* model without saying which of three files produced it.
|
|
17
|
+
*
|
|
18
|
+
* **Project settings** — what to ignore, which extensions to index — describe
|
|
19
|
+
* *this repository*, are worth committing, and mean the same thing on every
|
|
20
|
+
* machine that checks it out.
|
|
21
|
+
*
|
|
22
|
+
* Machine keys found in a project file are reported and ignored rather than
|
|
23
|
+
* applied. Wanting a different model for one project is a real thing to want;
|
|
24
|
+
* it is now spelled as a different database (`--database`), because the model
|
|
25
|
+
* is a property of an index rather than of a directory.
|
|
26
|
+
*/
|
|
27
|
+
export class ConfigLoader {
|
|
28
|
+
/** Settings that describe this machine's inference setup. */
|
|
29
|
+
static MACHINE_SCHEMA = z.object({
|
|
30
|
+
model: z
|
|
31
|
+
.string()
|
|
32
|
+
.regex(/^.+:.+$/, 'Model must be in "provider:model" format (e.g. "ollama:nomic-embed-text")'),
|
|
33
|
+
provider: z.string().optional(),
|
|
34
|
+
baseURL: z.string().url().optional(),
|
|
35
|
+
local: z.boolean().optional(),
|
|
36
|
+
batchSize: z.number().int().positive().default(100),
|
|
37
|
+
dimensions: z.number().int().positive().optional(),
|
|
38
|
+
queryPrefix: z.string().optional(),
|
|
39
|
+
documentPrefix: z.string().optional(),
|
|
40
|
+
maxTokens: z.number().int().positive().optional(),
|
|
41
|
+
chatModel: z
|
|
42
|
+
.string()
|
|
43
|
+
.regex(/^.+:.+$/, 'chatModel must be in "provider:model" format (e.g. "lmstudio:qwen/qwen3.5-9b")')
|
|
44
|
+
.optional(),
|
|
45
|
+
chatProvider: z.string().optional(),
|
|
46
|
+
chatBaseURL: z.string().url().optional(),
|
|
47
|
+
chatMaxSteps: z.number().int().positive().optional(),
|
|
48
|
+
chatTimeoutMs: z.number().int().positive().optional(),
|
|
49
|
+
});
|
|
50
|
+
/** Settings that describe a repository. */
|
|
51
|
+
static PROJECT_SCHEMA = z.object({
|
|
52
|
+
ignore: z.array(z.string()).optional(),
|
|
53
|
+
extensions: z
|
|
54
|
+
.object({
|
|
55
|
+
include: z.array(z.string()).optional(),
|
|
56
|
+
exclude: z.array(z.string()).optional(),
|
|
57
|
+
})
|
|
58
|
+
.optional(),
|
|
59
|
+
});
|
|
60
|
+
static FILE_NAME = "config.yml";
|
|
61
|
+
static PROJECT_FILE_NAMES = [".lmgrep.yml", ".lmgrep.yaml"];
|
|
62
|
+
static DEFAULTS = { batchSize: 100 };
|
|
63
|
+
/** Populated by {@link load}: what was read, and what was ignored. */
|
|
64
|
+
sources = [];
|
|
65
|
+
warnings = [];
|
|
66
|
+
load(cwd) {
|
|
67
|
+
const layers = [];
|
|
68
|
+
// Home-level files are machine settings wherever they sit; the bare
|
|
69
|
+
// ~/.lmgrep.yml predates the XDG path and is still honoured so an
|
|
70
|
+
// upgrade does not silently unconfigure anyone.
|
|
71
|
+
const legacy = this.readMachineFile(join(homedir(), ".lmgrep.yml"), "deprecated");
|
|
72
|
+
if (legacy)
|
|
73
|
+
layers.push(legacy);
|
|
74
|
+
const global = this.readMachineFile(this.globalConfigPath());
|
|
75
|
+
if (global)
|
|
76
|
+
layers.push(global);
|
|
77
|
+
const project = this.readProjectFile(cwd);
|
|
78
|
+
if (project)
|
|
79
|
+
layers.push(project);
|
|
80
|
+
if (layers.length === 0) {
|
|
81
|
+
throw new Error("No configuration found. Run `lmgrep init` to set up your embedding model.");
|
|
82
|
+
}
|
|
83
|
+
return this.validate(Object.assign({ ...ConfigLoader.DEFAULTS }, ...layers));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The XDG-compliant global config directory.
|
|
87
|
+
* Linux: $XDG_CONFIG_HOME/lmgrep or ~/.config/lmgrep
|
|
88
|
+
* macOS: ~/Library/Application Support/lmgrep
|
|
89
|
+
*/
|
|
90
|
+
configDirectory() {
|
|
91
|
+
if (platform() === "darwin") {
|
|
92
|
+
return join(homedir(), "Library", "Application Support", "lmgrep");
|
|
93
|
+
}
|
|
94
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
95
|
+
return join(xdg || join(homedir(), ".config"), "lmgrep");
|
|
96
|
+
}
|
|
97
|
+
globalConfigPath() {
|
|
98
|
+
return join(this.configDirectory(), ConfigLoader.FILE_NAME);
|
|
99
|
+
}
|
|
100
|
+
/** Path of the project file in `cwd`, whether or not it exists. */
|
|
101
|
+
projectConfigPath(cwd) {
|
|
102
|
+
for (const name of ConfigLoader.PROJECT_FILE_NAMES) {
|
|
103
|
+
if (existsSync(join(cwd, name)))
|
|
104
|
+
return join(cwd, name);
|
|
105
|
+
}
|
|
106
|
+
return join(cwd, ConfigLoader.PROJECT_FILE_NAMES[0]);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Parse a single machine config file, ignoring the layering.
|
|
110
|
+
*
|
|
111
|
+
* `init` rewrites one specific file, so it needs that file's own contents —
|
|
112
|
+
* merging layers here would copy one file's settings into another.
|
|
113
|
+
*/
|
|
114
|
+
readFile(path) {
|
|
115
|
+
const raw = this.parseYaml(path);
|
|
116
|
+
if (!raw)
|
|
117
|
+
return undefined;
|
|
118
|
+
return ConfigLoader.MACHINE_SCHEMA.partial().parse(this.pick(raw, ConfigLoader.machineKeys()));
|
|
119
|
+
}
|
|
120
|
+
readMachineFile(path, deprecated) {
|
|
121
|
+
const raw = this.parseYaml(path);
|
|
122
|
+
if (!raw)
|
|
123
|
+
return undefined;
|
|
124
|
+
const projectKeys = ConfigLoader.projectKeys().filter((k) => k in raw);
|
|
125
|
+
if (projectKeys.length > 0) {
|
|
126
|
+
this.warnings.push(`${path}: ${projectKeys.join(", ")} ${projectKeys.length === 1 ? "is a project setting" : "are project settings"} — ` +
|
|
127
|
+
"move to .lmgrep.yml in the repository it applies to.");
|
|
128
|
+
}
|
|
129
|
+
const parsed = ConfigLoader.MACHINE_SCHEMA.partial().parse(this.pick(raw, ConfigLoader.machineKeys()));
|
|
130
|
+
// Deprecation is not warned about here: `lmgrep status` marks the
|
|
131
|
+
// location in its provenance listing, which is where someone is
|
|
132
|
+
// actually looking at their configuration. Printing it before every
|
|
133
|
+
// search would be noise on the one path that must stay quiet.
|
|
134
|
+
this.sources.push({
|
|
135
|
+
path,
|
|
136
|
+
scope: "machine",
|
|
137
|
+
keys: Object.keys(parsed),
|
|
138
|
+
...(deprecated ? { deprecated: true } : {}),
|
|
139
|
+
});
|
|
140
|
+
return parsed;
|
|
141
|
+
}
|
|
142
|
+
readProjectFile(cwd) {
|
|
143
|
+
for (const name of ConfigLoader.PROJECT_FILE_NAMES) {
|
|
144
|
+
const path = join(cwd, name);
|
|
145
|
+
const raw = this.parseYaml(path);
|
|
146
|
+
if (!raw)
|
|
147
|
+
continue;
|
|
148
|
+
const machineKeys = ConfigLoader.machineKeys().filter((k) => k in raw);
|
|
149
|
+
if (machineKeys.length > 0) {
|
|
150
|
+
// Named individually because the consequence differs per key:
|
|
151
|
+
// a stray `model` here silently decided what an index meant.
|
|
152
|
+
this.warnings.push(`${path}: ignoring ${machineKeys.join(", ")} — these describe your machine, ` +
|
|
153
|
+
`not this repository. Set them in ${this.globalConfigPath()}. ` +
|
|
154
|
+
"For a project-specific model, index it under `--in <name>` instead.");
|
|
155
|
+
}
|
|
156
|
+
const parsed = ConfigLoader.PROJECT_SCHEMA.parse(this.pick(raw, ConfigLoader.projectKeys()));
|
|
157
|
+
this.sources.push({
|
|
158
|
+
path,
|
|
159
|
+
scope: "project",
|
|
160
|
+
keys: Object.keys(parsed),
|
|
161
|
+
});
|
|
162
|
+
return parsed;
|
|
163
|
+
}
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
parseYaml(path) {
|
|
167
|
+
if (!existsSync(path))
|
|
168
|
+
return undefined;
|
|
169
|
+
const parsed = parse(readFileSync(path, "utf-8"));
|
|
170
|
+
if (parsed == null || typeof parsed !== "object")
|
|
171
|
+
return undefined;
|
|
172
|
+
return parsed;
|
|
173
|
+
}
|
|
174
|
+
pick(raw, keys) {
|
|
175
|
+
const out = {};
|
|
176
|
+
for (const key of keys)
|
|
177
|
+
if (key in raw)
|
|
178
|
+
out[key] = raw[key];
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
static machineKeys() {
|
|
182
|
+
return Object.keys(ConfigLoader.MACHINE_SCHEMA.shape);
|
|
183
|
+
}
|
|
184
|
+
static projectKeys() {
|
|
185
|
+
return Object.keys(ConfigLoader.PROJECT_SCHEMA.shape);
|
|
186
|
+
}
|
|
187
|
+
validate(config) {
|
|
188
|
+
if (!config.model) {
|
|
189
|
+
throw new Error(`No model configured. Run \`lmgrep init\` to detect your setup, or set \`model\` in ${this.globalConfigPath()}.`);
|
|
190
|
+
}
|
|
191
|
+
return config;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=ConfigLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigLoader.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/ConfigLoader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { LockPort } from "../../domain/ports/LockPort.js";
|
|
2
|
+
/**
|
|
3
|
+
* The two locks a database has, which exist for different reasons and are
|
|
4
|
+
* therefore scoped differently.
|
|
5
|
+
*
|
|
6
|
+
* The **write mutex** (`.writelock`) is per *database*, because that is what
|
|
7
|
+
* concurrent writers actually contend for: two indexers writing the same
|
|
8
|
+
* tables race into duplicate rows. It is held only around a build.
|
|
9
|
+
*
|
|
10
|
+
* The **maintainer** lock is per *worktree*. Watching is inherently per
|
|
11
|
+
* working tree — a watcher scans its own root and maintains its own branch's
|
|
12
|
+
* manifest — but worktrees of one repository share a single database. Keying
|
|
13
|
+
* this lock by database, as it once was, meant the first worktree to start
|
|
14
|
+
* silently prevented every sibling from ever watching, leaving their branches
|
|
15
|
+
* to go stale with no indication. It also doubles as the liveness registry
|
|
16
|
+
* `lmgrep status` reads, which is why the owning worktree is recorded in it.
|
|
17
|
+
*
|
|
18
|
+
* Both live in the state directory rather than beside the database. Locks
|
|
19
|
+
* coordinate processes on *this machine*; a database now lives inside a
|
|
20
|
+
* repository, which may be on a network filesystem, may be read-only, and is
|
|
21
|
+
* the wrong place to record which local pid is busy with it. Keeping them
|
|
22
|
+
* together in one directory is also what lets `status` find every running
|
|
23
|
+
* lmgrep by reading a single directory.
|
|
24
|
+
*/
|
|
25
|
+
export declare class DatabaseLocks implements LockPort {
|
|
26
|
+
private readonly databasePath;
|
|
27
|
+
/** Working tree this process would be responsible for. */
|
|
28
|
+
private readonly workspaceRoot;
|
|
29
|
+
private static readonly DEFAULT_WAIT_MS;
|
|
30
|
+
private static readonly DEFAULT_POLL_MS;
|
|
31
|
+
/** Enough to separate worktrees without making the filename unreadable. */
|
|
32
|
+
private static readonly ROOT_DIGEST_LENGTH;
|
|
33
|
+
private readonly maintainer;
|
|
34
|
+
private readonly writer;
|
|
35
|
+
constructor(locksDirectory: string, databasePath: string,
|
|
36
|
+
/** Working tree this process would be responsible for. */
|
|
37
|
+
workspaceRoot: string);
|
|
38
|
+
acquireMaintainer(): boolean;
|
|
39
|
+
releaseMaintainer(): void;
|
|
40
|
+
isMaintained(): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Run `fn` holding the write mutex. Waits for a busy lock, taking over one
|
|
43
|
+
* whose owner has died. Throws if it cannot be acquired in time — better to
|
|
44
|
+
* fail than to write concurrently and duplicate rows.
|
|
45
|
+
*/
|
|
46
|
+
withWriteLock<T>(fn: () => Promise<T>, options?: {
|
|
47
|
+
waitMs?: number;
|
|
48
|
+
pollMs?: number;
|
|
49
|
+
}): Promise<T>;
|
|
50
|
+
/** Short stable name for a path, used to key lock files. */
|
|
51
|
+
private static digestOf;
|
|
52
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { PidFileLock } from "./PidFileLock.js";
|
|
4
|
+
/**
|
|
5
|
+
* The two locks a database has, which exist for different reasons and are
|
|
6
|
+
* therefore scoped differently.
|
|
7
|
+
*
|
|
8
|
+
* The **write mutex** (`.writelock`) is per *database*, because that is what
|
|
9
|
+
* concurrent writers actually contend for: two indexers writing the same
|
|
10
|
+
* tables race into duplicate rows. It is held only around a build.
|
|
11
|
+
*
|
|
12
|
+
* The **maintainer** lock is per *worktree*. Watching is inherently per
|
|
13
|
+
* working tree — a watcher scans its own root and maintains its own branch's
|
|
14
|
+
* manifest — but worktrees of one repository share a single database. Keying
|
|
15
|
+
* this lock by database, as it once was, meant the first worktree to start
|
|
16
|
+
* silently prevented every sibling from ever watching, leaving their branches
|
|
17
|
+
* to go stale with no indication. It also doubles as the liveness registry
|
|
18
|
+
* `lmgrep status` reads, which is why the owning worktree is recorded in it.
|
|
19
|
+
*
|
|
20
|
+
* Both live in the state directory rather than beside the database. Locks
|
|
21
|
+
* coordinate processes on *this machine*; a database now lives inside a
|
|
22
|
+
* repository, which may be on a network filesystem, may be read-only, and is
|
|
23
|
+
* the wrong place to record which local pid is busy with it. Keeping them
|
|
24
|
+
* together in one directory is also what lets `status` find every running
|
|
25
|
+
* lmgrep by reading a single directory.
|
|
26
|
+
*/
|
|
27
|
+
export class DatabaseLocks {
|
|
28
|
+
databasePath;
|
|
29
|
+
workspaceRoot;
|
|
30
|
+
static DEFAULT_WAIT_MS = 120_000;
|
|
31
|
+
static DEFAULT_POLL_MS = 200;
|
|
32
|
+
/** Enough to separate worktrees without making the filename unreadable. */
|
|
33
|
+
static ROOT_DIGEST_LENGTH = 12;
|
|
34
|
+
maintainer;
|
|
35
|
+
writer;
|
|
36
|
+
constructor(locksDirectory, databasePath,
|
|
37
|
+
/** Working tree this process would be responsible for. */
|
|
38
|
+
workspaceRoot) {
|
|
39
|
+
this.databasePath = databasePath;
|
|
40
|
+
this.workspaceRoot = workspaceRoot;
|
|
41
|
+
const database = DatabaseLocks.digestOf(databasePath);
|
|
42
|
+
this.maintainer = new PidFileLock(join(locksDirectory, `${database}@${DatabaseLocks.digestOf(workspaceRoot)}.lock`));
|
|
43
|
+
this.writer = new PidFileLock(join(locksDirectory, `${database}.writelock`));
|
|
44
|
+
}
|
|
45
|
+
acquireMaintainer() {
|
|
46
|
+
// The database path goes in the payload because it is no longer in the
|
|
47
|
+
// filename: a digest cannot be reversed, and `status` needs to name the
|
|
48
|
+
// index a process is holding.
|
|
49
|
+
return this.maintainer.tryAcquire({
|
|
50
|
+
root: this.workspaceRoot,
|
|
51
|
+
database: this.databasePath,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
releaseMaintainer() {
|
|
55
|
+
this.maintainer.release();
|
|
56
|
+
}
|
|
57
|
+
isMaintained() {
|
|
58
|
+
return this.maintainer.isHeldByLiveProcess();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Run `fn` holding the write mutex. Waits for a busy lock, taking over one
|
|
62
|
+
* whose owner has died. Throws if it cannot be acquired in time — better to
|
|
63
|
+
* fail than to write concurrently and duplicate rows.
|
|
64
|
+
*/
|
|
65
|
+
async withWriteLock(fn, options = {}) {
|
|
66
|
+
const waitMs = options.waitMs ?? DatabaseLocks.DEFAULT_WAIT_MS;
|
|
67
|
+
const pollMs = options.pollMs ?? DatabaseLocks.DEFAULT_POLL_MS;
|
|
68
|
+
let waited = 0;
|
|
69
|
+
while (!this.writer.tryAcquire()) {
|
|
70
|
+
if (waited >= waitMs) {
|
|
71
|
+
throw new Error("Could not acquire the index write lock — another indexer is busy. " +
|
|
72
|
+
"Try again once it finishes.");
|
|
73
|
+
}
|
|
74
|
+
await new Promise((r) => setTimeout(r, pollMs));
|
|
75
|
+
waited += pollMs;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
return await fn();
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
this.writer.releaseIfOwned();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Short stable name for a path, used to key lock files. */
|
|
85
|
+
static digestOf(path) {
|
|
86
|
+
return createHash("sha256")
|
|
87
|
+
.update(path)
|
|
88
|
+
.digest("hex")
|
|
89
|
+
.slice(0, DatabaseLocks.ROOT_DIGEST_LENGTH);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=DatabaseLocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatabaseLocks.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/DatabaseLocks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,aAAa;IAWP;IAEA;IAZV,MAAM,CAAU,eAAe,GAAG,OAAO,CAAC;IAC1C,MAAM,CAAU,eAAe,GAAG,GAAG,CAAC;IAC9C,2EAA2E;IACnE,MAAM,CAAU,kBAAkB,GAAG,EAAE,CAAC;IAE/B,UAAU,CAAc;IACxB,MAAM,CAAc;IAErC,YACC,cAAsB,EACL,YAAoB;IACrC,0DAA0D;IACzC,aAAqB;QAFrB,iBAAY,GAAZ,YAAY,CAAQ;QAEpB,kBAAa,GAAb,aAAa,CAAQ;QAEtC,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACtD,IAAI,CAAC,UAAU,GAAG,IAAI,WAAW,CAChC,IAAI,CACH,cAAc,EACd,GAAG,QAAQ,IAAI,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAC3D,CACD,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAC5B,IAAI,CAAC,cAAc,EAAE,GAAG,QAAQ,YAAY,CAAC,CAC7C,CAAC;IACH,CAAC;IAED,iBAAiB;QAChB,uEAAuE;QACvE,wEAAwE;QACxE,8BAA8B;QAC9B,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YACjC,IAAI,EAAE,IAAI,CAAC,aAAa;YACxB,QAAQ,EAAE,IAAI,CAAC,YAAY;SAC3B,CAAC,CAAC;IACJ,CAAC;IAED,iBAAiB;QAChB,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,YAAY;QACX,OAAO,IAAI,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC;IAC9C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,aAAa,CAClB,EAAoB,EACpB,UAAgD,EAAE;QAElD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,eAAe,CAAC;QAC/D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,eAAe,CAAC;QAE/D,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;YAClC,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CACd,oEAAoE;oBACnE,6BAA6B,CAC9B,CAAC;YACH,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YAChD,MAAM,IAAI,MAAM,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACJ,OAAO,MAAM,EAAE,EAAE,CAAC;QACnB,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC9B,CAAC;IACF,CAAC;IAED,4DAA4D;IACpD,MAAM,CAAC,QAAQ,CAAC,IAAY;QACnC,OAAO,UAAU,CAAC,QAAQ,CAAC;aACzB,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IAC9C,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** Recursive on-disk size, for reporting what an index actually costs. */
|
|
4
|
+
export class DiskUsage {
|
|
5
|
+
/** Bytes used by `path` and everything under it; 0 when unreadable. */
|
|
6
|
+
static of(path) {
|
|
7
|
+
let total = 0;
|
|
8
|
+
let entries;
|
|
9
|
+
try {
|
|
10
|
+
entries = readdirSync(path, { withFileTypes: true });
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
const child = join(path, entry.name);
|
|
17
|
+
if (entry.isDirectory()) {
|
|
18
|
+
total += DiskUsage.of(child);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
total += statSync(child).size;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// Vanished mid-walk; the number is a report, not an invariant.
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return total;
|
|
29
|
+
}
|
|
30
|
+
static format(bytes) {
|
|
31
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
32
|
+
let value = bytes;
|
|
33
|
+
let unit = 0;
|
|
34
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
35
|
+
value /= 1024;
|
|
36
|
+
unit++;
|
|
37
|
+
}
|
|
38
|
+
return `${value < 10 && unit > 0 ? value.toFixed(1) : Math.round(value)}${units[unit]}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=DiskUsage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DiskUsage.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/DiskUsage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,0EAA0E;AAC1E,MAAM,OAAO,SAAS;IACrB,uEAAuE;IACvE,MAAM,CAAC,EAAE,CAAC,IAAY;QACrB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,OAAmC,CAAC;QACxC,IAAI,CAAC;YACJ,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,CAAC,CAAC;QACV,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACzB,KAAK,IAAI,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;gBAC7B,SAAS;YACV,CAAC;YACD,IAAI,CAAC;gBACJ,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACR,+DAA+D;YAChE,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,KAAa;QAC1B,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5C,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjD,KAAK,IAAI,IAAI,CAAC;YACd,IAAI,EAAE,CAAC;QACR,CAAC;QACD,OAAO,GAAG,KAAK,GAAG,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;IACzF,CAAC;CACD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ExtensionRules } from "../../domain/ports/WorkspacePort.js";
|
|
2
|
+
/**
|
|
3
|
+
* Decides which files are worth indexing.
|
|
4
|
+
*
|
|
5
|
+
* Two independent filters: an extension allow-list (is this even source?) and
|
|
6
|
+
* ignore patterns (should this source be skipped?). Ignore rules come from the
|
|
7
|
+
* built-in list, the user's config, `.gitignore` and `.lmgrepignore`, plus
|
|
8
|
+
* nested `.gitignore` files further down the tree.
|
|
9
|
+
*/
|
|
10
|
+
export declare class IndexableFileRules {
|
|
11
|
+
private readonly cwd;
|
|
12
|
+
static readonly DEFAULT_IGNORE: string[];
|
|
13
|
+
static readonly CODE_EXTENSIONS: Set<string>;
|
|
14
|
+
private readonly root;
|
|
15
|
+
private readonly extensions;
|
|
16
|
+
private readonly nested;
|
|
17
|
+
constructor(cwd: string, extraIgnore?: string[], extensionRules?: ExtensionRules);
|
|
18
|
+
/** Whether the path's extension is one we index at all. */
|
|
19
|
+
hasIndexableExtension(filePath: string): boolean;
|
|
20
|
+
/** Whether the root-level ignore rules exclude this path. */
|
|
21
|
+
isIgnored(filePath: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Load `.gitignore` files sitting in subdirectories, so a nested ignore
|
|
24
|
+
* applies to its own subtree the way git applies it.
|
|
25
|
+
*/
|
|
26
|
+
loadNestedIgnores(relativePaths: readonly string[]): void;
|
|
27
|
+
/** Whether any nested `.gitignore` excludes this path. */
|
|
28
|
+
isIgnoredByNested(filePath: string): boolean;
|
|
29
|
+
/** Full decision for a scanned path. */
|
|
30
|
+
admits(filePath: string): boolean;
|
|
31
|
+
private static buildIgnore;
|
|
32
|
+
private static buildExtensions;
|
|
33
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, extname, join } from "node:path";
|
|
3
|
+
import ignore from "ignore";
|
|
4
|
+
/**
|
|
5
|
+
* Decides which files are worth indexing.
|
|
6
|
+
*
|
|
7
|
+
* Two independent filters: an extension allow-list (is this even source?) and
|
|
8
|
+
* ignore patterns (should this source be skipped?). Ignore rules come from the
|
|
9
|
+
* built-in list, the user's config, `.gitignore` and `.lmgrepignore`, plus
|
|
10
|
+
* nested `.gitignore` files further down the tree.
|
|
11
|
+
*/
|
|
12
|
+
export class IndexableFileRules {
|
|
13
|
+
cwd;
|
|
14
|
+
static DEFAULT_IGNORE = [
|
|
15
|
+
"node_modules",
|
|
16
|
+
".git",
|
|
17
|
+
"dist",
|
|
18
|
+
"build",
|
|
19
|
+
".next",
|
|
20
|
+
"__pycache__",
|
|
21
|
+
".venv",
|
|
22
|
+
"vendor",
|
|
23
|
+
"target",
|
|
24
|
+
".lmgrep",
|
|
25
|
+
"*.min.js",
|
|
26
|
+
"*.min.css",
|
|
27
|
+
"*.map",
|
|
28
|
+
"*.lock",
|
|
29
|
+
"pnpm-lock.yaml",
|
|
30
|
+
"package-lock.json",
|
|
31
|
+
"yarn.lock",
|
|
32
|
+
"*.png",
|
|
33
|
+
"*.jpg",
|
|
34
|
+
"*.jpeg",
|
|
35
|
+
"*.gif",
|
|
36
|
+
"*.ico",
|
|
37
|
+
"*.woff",
|
|
38
|
+
"*.woff2",
|
|
39
|
+
"*.ttf",
|
|
40
|
+
"*.eot",
|
|
41
|
+
"*.svg",
|
|
42
|
+
"*.zip",
|
|
43
|
+
"*.tar",
|
|
44
|
+
"*.gz",
|
|
45
|
+
"*.bin",
|
|
46
|
+
"*.exe",
|
|
47
|
+
"*.dll",
|
|
48
|
+
"*.so",
|
|
49
|
+
"*.dylib",
|
|
50
|
+
"*.wasm",
|
|
51
|
+
];
|
|
52
|
+
static CODE_EXTENSIONS = new Set([
|
|
53
|
+
".js",
|
|
54
|
+
".ts",
|
|
55
|
+
".jsx",
|
|
56
|
+
".tsx",
|
|
57
|
+
".py",
|
|
58
|
+
".rs",
|
|
59
|
+
".go",
|
|
60
|
+
".rb",
|
|
61
|
+
".c",
|
|
62
|
+
".h",
|
|
63
|
+
".cpp",
|
|
64
|
+
".hpp",
|
|
65
|
+
".cc",
|
|
66
|
+
".swift",
|
|
67
|
+
".json",
|
|
68
|
+
".yaml",
|
|
69
|
+
".yml",
|
|
70
|
+
".toml",
|
|
71
|
+
".lua",
|
|
72
|
+
".scala",
|
|
73
|
+
".zig",
|
|
74
|
+
".md",
|
|
75
|
+
".markdown",
|
|
76
|
+
".mdx",
|
|
77
|
+
".sh",
|
|
78
|
+
".bash",
|
|
79
|
+
".sql",
|
|
80
|
+
".graphql",
|
|
81
|
+
".gql",
|
|
82
|
+
".proto",
|
|
83
|
+
".html",
|
|
84
|
+
".css",
|
|
85
|
+
".scss",
|
|
86
|
+
".vue",
|
|
87
|
+
".svelte",
|
|
88
|
+
".nix",
|
|
89
|
+
".tf",
|
|
90
|
+
".hcl",
|
|
91
|
+
".kt",
|
|
92
|
+
".java",
|
|
93
|
+
".php",
|
|
94
|
+
".cs",
|
|
95
|
+
".rst",
|
|
96
|
+
".adoc",
|
|
97
|
+
]);
|
|
98
|
+
root;
|
|
99
|
+
extensions;
|
|
100
|
+
nested = new Map();
|
|
101
|
+
constructor(cwd, extraIgnore, extensionRules) {
|
|
102
|
+
this.cwd = cwd;
|
|
103
|
+
this.root = IndexableFileRules.buildIgnore(cwd, extraIgnore);
|
|
104
|
+
this.extensions = IndexableFileRules.buildExtensions(extensionRules);
|
|
105
|
+
}
|
|
106
|
+
/** Whether the path's extension is one we index at all. */
|
|
107
|
+
hasIndexableExtension(filePath) {
|
|
108
|
+
return this.extensions.has(extname(filePath));
|
|
109
|
+
}
|
|
110
|
+
/** Whether the root-level ignore rules exclude this path. */
|
|
111
|
+
isIgnored(filePath) {
|
|
112
|
+
try {
|
|
113
|
+
return this.root.ignores(filePath);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// `ignore` rejects paths it considers malformed; treat those as
|
|
117
|
+
// ignorable rather than letting one bad name abort a whole scan.
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Load `.gitignore` files sitting in subdirectories, so a nested ignore
|
|
123
|
+
* applies to its own subtree the way git applies it.
|
|
124
|
+
*/
|
|
125
|
+
loadNestedIgnores(relativePaths) {
|
|
126
|
+
for (const f of relativePaths) {
|
|
127
|
+
if (f.endsWith("/.gitignore") || f === ".gitignore")
|
|
128
|
+
continue;
|
|
129
|
+
const dir = dirname(f);
|
|
130
|
+
if (dir === "." || this.nested.has(dir))
|
|
131
|
+
continue;
|
|
132
|
+
const nestedPath = join(this.cwd, dir, ".gitignore");
|
|
133
|
+
if (!existsSync(nestedPath))
|
|
134
|
+
continue;
|
|
135
|
+
const rules = ignore();
|
|
136
|
+
rules.add(readFileSync(nestedPath, "utf-8"));
|
|
137
|
+
this.nested.set(dir, rules);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** Whether any nested `.gitignore` excludes this path. */
|
|
141
|
+
isIgnoredByNested(filePath) {
|
|
142
|
+
for (const [dir, rules] of this.nested) {
|
|
143
|
+
if (!filePath.startsWith(`${dir}/`))
|
|
144
|
+
continue;
|
|
145
|
+
if (rules.ignores(filePath.slice(dir.length + 1)))
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
/** Full decision for a scanned path. */
|
|
151
|
+
admits(filePath) {
|
|
152
|
+
return (this.hasIndexableExtension(filePath) &&
|
|
153
|
+
!this.isIgnored(filePath) &&
|
|
154
|
+
!this.isIgnoredByNested(filePath));
|
|
155
|
+
}
|
|
156
|
+
static buildIgnore(cwd, extra) {
|
|
157
|
+
const rules = ignore();
|
|
158
|
+
rules.add([...IndexableFileRules.DEFAULT_IGNORE]);
|
|
159
|
+
if (extra)
|
|
160
|
+
rules.add(extra);
|
|
161
|
+
for (const name of [".gitignore", ".lmgrepignore"]) {
|
|
162
|
+
const path = join(cwd, name);
|
|
163
|
+
if (existsSync(path))
|
|
164
|
+
rules.add(readFileSync(path, "utf-8"));
|
|
165
|
+
}
|
|
166
|
+
return rules;
|
|
167
|
+
}
|
|
168
|
+
static buildExtensions(rules) {
|
|
169
|
+
const exts = new Set(IndexableFileRules.CODE_EXTENSIONS);
|
|
170
|
+
for (const e of rules?.include ?? [])
|
|
171
|
+
exts.add(e);
|
|
172
|
+
for (const e of rules?.exclude ?? [])
|
|
173
|
+
exts.delete(e);
|
|
174
|
+
return exts;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=IndexableFileRules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndexableFileRules.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/IndexableFileRules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LoggerPort } from "../../domain/ports/LoggerPort.js";
|
|
2
|
+
/** Timestamped output on stdout/stderr, for foreground commands. */
|
|
3
|
+
export declare class ConsoleLogger implements LoggerPort {
|
|
4
|
+
info(message: string): void;
|
|
5
|
+
error(message: string): void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Discards everything. Used by the MCP server, whose stdout is a protocol
|
|
9
|
+
* stream — a stray log line there corrupts the transport.
|
|
10
|
+
*/
|
|
11
|
+
export declare class SilentLogger implements LoggerPort {
|
|
12
|
+
info(): void;
|
|
13
|
+
error(): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Timestamped output on stdout/stderr, for foreground commands. */
|
|
2
|
+
export class ConsoleLogger {
|
|
3
|
+
info(message) {
|
|
4
|
+
console.log(`[${new Date().toISOString()}] ${message}`);
|
|
5
|
+
}
|
|
6
|
+
error(message) {
|
|
7
|
+
console.error(`[${new Date().toISOString()}] ${message}`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Discards everything. Used by the MCP server, whose stdout is a protocol
|
|
12
|
+
* stream — a stray log line there corrupts the transport.
|
|
13
|
+
*/
|
|
14
|
+
export class SilentLogger {
|
|
15
|
+
info() { }
|
|
16
|
+
error() { }
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=Loggers.js.map
|