directory-indexer 0.0.10 → 0.0.12

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 CHANGED
@@ -3,9 +3,7 @@
3
3
  **Turn your directories into an AI-powered knowledge base.**
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/directory-indexer)](https://npmjs.com/package/directory-indexer)
6
- [![Crates.io](https://img.shields.io/crates/v/directory-indexer)](https://crates.io/crates/directory-indexer)
7
6
  [![codecov](https://codecov.io/gh/peteretelej/directory-indexer/graph/badge.svg?token=j6aBBpfqkN)](https://codecov.io/gh/peteretelej/directory-indexer)
8
- [![Rust](https://img.shields.io/badge/rust-1.70+-blue.svg)](https://www.rust-lang.org)
9
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
10
8
  [![CI](https://github.com/peteretelej/directory-indexer/workflows/CI/badge.svg)](https://github.com/peteretelej/directory-indexer/actions)
11
9
 
@@ -73,104 +71,81 @@ curl http://localhost:11434/api/tags
73
71
 
74
72
  If either fails, directory-indexer will show a helpful error with setup guidance.
75
73
 
76
- ## Installation
77
-
78
- ```bash
79
- npm install -g directory-indexer
80
- ```
81
-
82
74
  ## Usage
83
75
 
84
76
  ### MCP Integration
85
77
 
86
- Configure with Claude Desktop:
78
+ Configure with AI assistants (Claude Desktop, Cline, etc.) using npx:
87
79
 
88
80
  ```json
89
81
  {
90
82
  "mcpServers": {
91
83
  "directory-indexer": {
92
- "command": "directory-indexer",
93
- "args": ["serve"]
84
+ "command": "npx",
85
+ "args": ["directory-indexer", "serve"]
94
86
  }
95
87
  }
96
88
  }
97
89
  ```
98
90
 
99
- Start the MCP server:
91
+ Index your directories and start using with your AI assistant:
100
92
 
101
93
  ```bash
102
- directory-indexer serve
103
- ```
94
+ # Index your directories first
95
+ npx directory-indexer index /home/user/projects/docs /home/user/work/reports
104
96
 
105
- Your AI assistant (Claude, Cline, Copilot, etc.) can now search your indexed documents semantically. Ask: _"Find API authentication examples"_, _"Show me incidents similar to this"_, or _"Find troubleshooting guides on SQL deadlocks"_.
106
-
107
- ### CLI Commands
108
-
109
- ```bash
110
- # Index your directories
111
- # Linux/macOS
112
- directory-indexer index /home/user/projects/api-docs /mnt/work/incident-reports
113
- # Windows
114
- directory-indexer index "C:\work\documentation" "D:\projects\my-app\docs"
115
-
116
- # Search semantically
117
- directory-indexer search "database timeout errors"
118
-
119
- # Find similar files
120
- # Linux/macOS
121
- directory-indexer similar /mnt/work/incident-reports/redis-outage.md
122
- # Windows
123
- directory-indexer similar "C:\work\incidents\redis-outage.md"
124
-
125
- # Get file content
126
- directory-indexer get /home/user/projects/api-docs/auth-guide.md
127
-
128
- # Show status
129
- directory-indexer status
97
+ # Start MCP server (usually done automatically by your AI assistant)
98
+ npx directory-indexer serve
130
99
  ```
131
100
 
132
- ## Configuration
101
+ ### Using with AI Assistant
133
102
 
134
- Directory Indexer uses environment variables for configuration. Set these if your services run on different ports or require API keys:
103
+ Once configured, your AI assistant can search your indexed documents semantically:
135
104
 
136
- ```bash
137
- # Service endpoints (defaults shown)
138
- export QDRANT_ENDPOINT="http://localhost:6333"
139
- export OLLAMA_ENDPOINT="http://localhost:11434"
140
-
141
- # Optional data directory (default: ~/.directory-indexer)
142
- # Linux/macOS
143
- export DIRECTORY_INDEXER_DATA_DIR="/opt/directory-indexer-data"
144
- # Windows
145
- set DIRECTORY_INDEXER_DATA_DIR=D:\data\directory-indexer
146
-
147
- # Optional Qdrant collection name (default: directory-indexer)
148
- # Note: Setting to "test" enables auto-cleanup for testing
149
- export DIRECTORY_INDEXER_QDRANT_COLLECTION="my-custom-collection"
105
+ - _"Find API authentication examples"_
106
+ - _"Show me incidents similar to this outage report"_
107
+ - _"Find troubleshooting guides on SQL deadlocks"_
108
+ - _"What files contain database configuration?"_
150
109
 
151
- # Optional API keys
152
- export QDRANT_API_KEY="your-qdrant-key"
153
- export OLLAMA_API_KEY="your-ollama-key" # if using hosted Ollama
154
- ```
110
+ ### Custom Configuration
155
111
 
156
- **For MCP clients** (like Claude Desktop), configure with environment variables:
112
+ Configure with custom endpoints and data directory:
157
113
 
158
114
  ```json
159
115
  {
160
116
  "mcpServers": {
161
117
  "directory-indexer": {
162
- "command": "directory-indexer",
163
- "args": ["serve"],
118
+ "command": "npx",
119
+ "args": ["directory-indexer", "serve"],
164
120
  "env": {
121
+ "DIRECTORY_INDEXER_DATA_DIR": "/opt/ai-knowledge-base",
165
122
  "QDRANT_ENDPOINT": "http://localhost:6333",
166
- "OLLAMA_ENDPOINT": "http://localhost:11434",
167
- "DIRECTORY_INDEXER_DATA_DIR": "/opt/directory-indexer-data"
123
+ "OLLAMA_ENDPOINT": "http://localhost:11434"
168
124
  }
169
125
  }
170
126
  }
171
127
  }
172
128
  ```
173
129
 
130
+ ### CLI Usage
131
+
132
+ For advanced users who prefer command-line usage, see [CLI Documentation](./docs/design.md#cli-usage).
133
+
134
+ ## Configuration
135
+
136
+ Environment variables for MCP configuration:
137
+
138
+ ```bash
139
+ # Data directory (default: ~/.directory-indexer)
140
+ export DIRECTORY_INDEXER_DATA_DIR="/opt/ai-knowledge-base"
141
+
142
+ # Service endpoints (defaults shown)
143
+ export QDRANT_ENDPOINT="http://localhost:6333"
144
+ export OLLAMA_ENDPOINT="http://localhost:11434"
145
+ ```
146
+
147
+ For all configuration options, see [Environment Variables](./docs/design.md#environment-variables).
148
+
174
149
  ## Supported Files
175
150
 
176
151
  - **Text**: `.md`, `.txt`
@@ -180,7 +155,8 @@ export OLLAMA_API_KEY="your-ollama-key" # if using hosted Ollama
180
155
 
181
156
  ## Documentation
182
157
 
183
- - **[API Reference](docs/designs/API.md)**: Complete CLI and MCP tool documentation
158
+ - **[API Reference](docs/API.md)**: CLI commands and MCP tools
159
+ - **[Flow Diagrams](docs/flows.md)**: System architecture and process flows
184
160
  - **[Contributing](docs/CONTRIBUTING.md)**: Development setup and guidelines
185
161
  - **[Design](docs/design.md)**: Architecture and technical decisions
186
162
 
@@ -189,16 +165,19 @@ export OLLAMA_API_KEY="your-ollama-key" # if using hosted Ollama
189
165
  Once indexed, try these queries with your AI assistant:
190
166
 
191
167
  **Search by concept:**
168
+
192
169
  - _"Find API authentication examples"_
193
170
  - _"Show me error handling patterns"_
194
171
  - _"Find configuration for Redis"_
195
172
 
196
173
  **Find similar content:**
197
- - _"Show me incidents similar to this outage report"_ *(when you have an incident file open)*
198
- - _"Find documentation like this API guide"_ *(when viewing an API doc)*
174
+
175
+ - _"Show me incidents similar to this outage report"_ _(when you have an incident file open)_
176
+ - _"Find documentation like this API guide"_ _(when viewing an API doc)_
199
177
  - _"What files are similar to my deployment script?"_
200
178
 
201
179
  **Troubleshoot issues:**
180
+
202
181
  - _"Find troubleshooting guides on SQL deadlocks"_
203
182
  - _"Show me solutions for timeout errors"_
204
183
  - _"Find debugging tips for performance issues"_
package/dist/cli.js ADDED
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { indexDirectories } from "./indexing.js";
4
+ import { getFileContent, findSimilarFiles, searchContent } from "./search.js";
5
+ import { loadConfig } from "./config.js";
6
+ import { getIndexStatus } from "./storage.js";
7
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
+ import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
10
+ const MCP_TOOLS = [
11
+ {
12
+ name: "index",
13
+ description: "Index directories for semantic search",
14
+ inputSchema: {
15
+ type: "object",
16
+ properties: {
17
+ directory_path: {
18
+ type: "string",
19
+ description: "Comma-separated list of directory paths to index"
20
+ }
21
+ },
22
+ required: ["directory_path"]
23
+ }
24
+ },
25
+ {
26
+ name: "search",
27
+ description: "Search indexed content semantically",
28
+ inputSchema: {
29
+ type: "object",
30
+ properties: {
31
+ query: {
32
+ type: "string",
33
+ description: "Search query"
34
+ },
35
+ limit: {
36
+ type: "number",
37
+ description: "Maximum number of results (default: 10)",
38
+ default: 10
39
+ }
40
+ },
41
+ required: ["query"]
42
+ }
43
+ },
44
+ {
45
+ name: "similar_files",
46
+ description: "Find files similar to a given file",
47
+ inputSchema: {
48
+ type: "object",
49
+ properties: {
50
+ file_path: {
51
+ type: "string",
52
+ description: "Path to the file to find similar files for"
53
+ },
54
+ limit: {
55
+ type: "number",
56
+ description: "Maximum number of results (default: 10)",
57
+ default: 10
58
+ }
59
+ },
60
+ required: ["file_path"]
61
+ }
62
+ },
63
+ {
64
+ name: "get_content",
65
+ description: "Get file content",
66
+ inputSchema: {
67
+ type: "object",
68
+ properties: {
69
+ file_path: {
70
+ type: "string",
71
+ description: "Path to the file to retrieve"
72
+ },
73
+ chunks: {
74
+ type: "string",
75
+ description: 'Optional chunk range (e.g., "2-5")'
76
+ }
77
+ },
78
+ required: ["file_path"]
79
+ }
80
+ },
81
+ {
82
+ name: "server_info",
83
+ description: "Get server information and status",
84
+ inputSchema: {
85
+ type: "object",
86
+ properties: {}
87
+ }
88
+ }
89
+ ];
90
+ async function startMcpServer(config) {
91
+ const server = new Server(
92
+ {
93
+ name: "directory-indexer",
94
+ version: "0.0.10"
95
+ },
96
+ {
97
+ capabilities: {
98
+ tools: {}
99
+ }
100
+ }
101
+ );
102
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
103
+ return {
104
+ tools: MCP_TOOLS
105
+ };
106
+ });
107
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
108
+ const { name, arguments: args } = request.params;
109
+ try {
110
+ switch (name) {
111
+ case "index": {
112
+ if (!args || typeof args.directory_path !== "string") {
113
+ throw new Error("directory_path is required");
114
+ }
115
+ const paths = args.directory_path.split(",").map((p) => p.trim());
116
+ const result = await indexDirectories(paths, config);
117
+ return {
118
+ content: [
119
+ {
120
+ type: "text",
121
+ text: `Indexed ${result.indexed} files, skipped ${result.skipped} files, ${result.errors.length} errors`
122
+ }
123
+ ]
124
+ };
125
+ }
126
+ case "search": {
127
+ if (!args || typeof args.query !== "string") {
128
+ throw new Error("query is required");
129
+ }
130
+ const results = await searchContent(args.query, { limit: args.limit || 10 });
131
+ return {
132
+ content: [
133
+ {
134
+ type: "text",
135
+ text: JSON.stringify(results, null, 2)
136
+ }
137
+ ]
138
+ };
139
+ }
140
+ case "similar_files": {
141
+ if (!args || typeof args.file_path !== "string") {
142
+ throw new Error("file_path is required");
143
+ }
144
+ const results = await findSimilarFiles(args.file_path, args.limit || 10);
145
+ return {
146
+ content: [
147
+ {
148
+ type: "text",
149
+ text: JSON.stringify(results, null, 2)
150
+ }
151
+ ]
152
+ };
153
+ }
154
+ case "get_content": {
155
+ if (!args || typeof args.file_path !== "string") {
156
+ throw new Error("file_path is required");
157
+ }
158
+ const content = await getFileContent(args.file_path, args.chunks);
159
+ return {
160
+ content: [
161
+ {
162
+ type: "text",
163
+ text: content
164
+ }
165
+ ]
166
+ };
167
+ }
168
+ case "server_info": {
169
+ const status = await getIndexStatus();
170
+ return {
171
+ content: [
172
+ {
173
+ type: "text",
174
+ text: JSON.stringify({
175
+ name: "directory-indexer",
176
+ version: "0.0.10",
177
+ status
178
+ }, null, 2)
179
+ }
180
+ ]
181
+ };
182
+ }
183
+ default:
184
+ throw new Error(`Unknown tool: ${name}`);
185
+ }
186
+ } catch (error) {
187
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
188
+ return {
189
+ content: [
190
+ {
191
+ type: "text",
192
+ text: `Error: ${errorMessage}`
193
+ }
194
+ ],
195
+ isError: true
196
+ };
197
+ }
198
+ });
199
+ const transport = new StdioServerTransport();
200
+ await server.connect(transport);
201
+ if (config.verbose) {
202
+ console.error("MCP server started successfully");
203
+ }
204
+ }
205
+ async function main() {
206
+ const program = new Command();
207
+ program.name("directory-indexer").description("AI-powered directory indexing with semantic search").version("0.0.10");
208
+ program.command("index").description("Index directories for semantic search").argument("<paths...>", "Directory paths to index").option("-v, --verbose", "Enable verbose logging").action(async (paths, options) => {
209
+ try {
210
+ const config = await loadConfig({ verbose: options.verbose });
211
+ console.log(`Indexing ${paths.length} directories...`);
212
+ const result = await indexDirectories(paths, config);
213
+ console.log(`Indexed ${result.indexed} files, skipped ${result.skipped} files, ${result.errors.length} errors`);
214
+ if (result.errors.length > 0 && config.verbose) {
215
+ console.log("Errors:", result.errors);
216
+ }
217
+ } catch (error) {
218
+ console.error("Error indexing directories:", error);
219
+ process.exit(1);
220
+ }
221
+ });
222
+ program.command("search").description("Search indexed content semantically").argument("<query>", "Search query").option("-l, --limit <number>", "Maximum number of results", "10").option("-v, --verbose", "Enable verbose logging").action(async (query, options) => {
223
+ try {
224
+ await loadConfig({ verbose: options.verbose });
225
+ const results = await searchContent(query, { limit: parseInt(options.limit) });
226
+ if (results.length === 0) {
227
+ console.log("No results found");
228
+ return;
229
+ }
230
+ console.log(`Found ${results.length} results:
231
+ `);
232
+ results.forEach((result, index) => {
233
+ console.log(`${index + 1}. ${result.filePath}`);
234
+ console.log(` Score: ${result.score.toFixed(3)}`);
235
+ if (result.content) {
236
+ console.log(` Content: ${result.content.substring(0, 150)}...`);
237
+ }
238
+ console.log();
239
+ });
240
+ } catch (error) {
241
+ console.error("Error searching content:", error);
242
+ process.exit(1);
243
+ }
244
+ });
245
+ program.command("similar").description("Find files similar to a given file").argument("<file>", "File path to find similar files for").option("-l, --limit <number>", "Maximum number of results", "10").option("-v, --verbose", "Enable verbose logging").action(async (filePath, options) => {
246
+ try {
247
+ await loadConfig({ verbose: options.verbose });
248
+ const results = await findSimilarFiles(filePath, parseInt(options.limit));
249
+ if (results.length === 0) {
250
+ console.log("No similar files found");
251
+ return;
252
+ }
253
+ console.log(`Found ${results.length} similar files:
254
+ `);
255
+ results.forEach((result, index) => {
256
+ console.log(`${index + 1}. ${result.filePath}`);
257
+ console.log(` Similarity: ${result.score.toFixed(3)}`);
258
+ console.log();
259
+ });
260
+ } catch (error) {
261
+ console.error("Error finding similar files:", error);
262
+ process.exit(1);
263
+ }
264
+ });
265
+ program.command("get").description("Get file content").argument("<file>", "File path to retrieve").option("-c, --chunks <range>", 'Chunk range (e.g., "2-5")').option("-v, --verbose", "Enable verbose logging").action(async (filePath, options) => {
266
+ try {
267
+ await loadConfig({ verbose: options.verbose });
268
+ const content = await getFileContent(filePath, options.chunks);
269
+ console.log(content);
270
+ } catch (error) {
271
+ console.error("Error getting file content:", error);
272
+ process.exit(1);
273
+ }
274
+ });
275
+ program.command("serve").description("Start MCP server").option("-v, --verbose", "Enable verbose logging").action(async (options) => {
276
+ try {
277
+ const config = await loadConfig({ verbose: options.verbose });
278
+ await startMcpServer(config);
279
+ } catch (error) {
280
+ console.error("Error starting MCP server:", error);
281
+ process.exit(1);
282
+ }
283
+ });
284
+ program.command("status").description("Show indexing status").option("-v, --verbose", "Enable verbose logging").action(async (options) => {
285
+ try {
286
+ await loadConfig({ verbose: options.verbose });
287
+ const status = await getIndexStatus();
288
+ console.log("Indexing Status:");
289
+ console.log(` Directories indexed: ${status.directoriesIndexed}`);
290
+ console.log(` Files indexed: ${status.filesIndexed}`);
291
+ console.log(` Total chunks: ${status.chunksIndexed}`);
292
+ console.log(` Database size: ${status.databaseSize}`);
293
+ console.log(` Last indexed: ${status.lastIndexed || "Never"}`);
294
+ if (status.errors.length > 0) {
295
+ console.log(` Errors: ${status.errors.length}`);
296
+ if (options.verbose) {
297
+ console.log(" Recent errors:");
298
+ status.errors.slice(0, 5).forEach((error) => {
299
+ console.log(` - ${error}`);
300
+ });
301
+ }
302
+ }
303
+ } catch (error) {
304
+ console.error("Error getting status:", error);
305
+ process.exit(1);
306
+ }
307
+ });
308
+ await program.parseAsync();
309
+ }
310
+ if (import.meta.url === `file://${process.argv[1]}`) {
311
+ main().catch(console.error);
312
+ }
313
+ export {
314
+ main
315
+ };
316
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sources":["../src/mcp.ts","../src/cli.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { \n CallToolRequestSchema, \n ListToolsRequestSchema,\n Tool\n} from '@modelcontextprotocol/sdk/types.js';\nimport { Config } from './config.js';\nimport { indexDirectories } from './indexing.js';\nimport { searchContent, findSimilarFiles, getFileContent } from './search.js';\nimport { getIndexStatus } from './storage.js';\n\nconst MCP_TOOLS: Tool[] = [\n {\n name: 'index',\n description: 'Index directories for semantic search',\n inputSchema: {\n type: 'object',\n properties: {\n directory_path: {\n type: 'string',\n description: 'Comma-separated list of directory paths to index'\n }\n },\n required: ['directory_path']\n }\n },\n {\n name: 'search',\n description: 'Search indexed content semantically',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query'\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 10)',\n default: 10\n }\n },\n required: ['query']\n }\n },\n {\n name: 'similar_files',\n description: 'Find files similar to a given file',\n inputSchema: {\n type: 'object',\n properties: {\n file_path: {\n type: 'string',\n description: 'Path to the file to find similar files for'\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 10)',\n default: 10\n }\n },\n required: ['file_path']\n }\n },\n {\n name: 'get_content',\n description: 'Get file content',\n inputSchema: {\n type: 'object',\n properties: {\n file_path: {\n type: 'string',\n description: 'Path to the file to retrieve'\n },\n chunks: {\n type: 'string',\n description: 'Optional chunk range (e.g., \"2-5\")'\n }\n },\n required: ['file_path']\n }\n },\n {\n name: 'server_info',\n description: 'Get server information and status',\n inputSchema: {\n type: 'object',\n properties: {}\n }\n }\n];\n\nexport async function startMcpServer(config: Config): Promise<void> {\n const server = new Server(\n {\n name: 'directory-indexer',\n version: '0.0.10'\n },\n {\n capabilities: {\n tools: {}\n }\n }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: MCP_TOOLS\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n switch (name) {\n case 'index': {\n if (!args || typeof args.directory_path !== 'string') {\n throw new Error('directory_path is required');\n }\n const paths = args.directory_path.split(',').map((p: string) => p.trim());\n const result = await indexDirectories(paths, config);\n return {\n content: [\n {\n type: 'text',\n text: `Indexed ${result.indexed} files, skipped ${result.skipped} files, ${result.errors.length} errors`\n }\n ]\n };\n }\n\n case 'search': {\n if (!args || typeof args.query !== 'string') {\n throw new Error('query is required');\n }\n const results = await searchContent(args.query, { limit: (args.limit as number) || 10 });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(results, null, 2)\n }\n ]\n };\n }\n\n case 'similar_files': {\n if (!args || typeof args.file_path !== 'string') {\n throw new Error('file_path is required');\n }\n const results = await findSimilarFiles(args.file_path, (args.limit as number) || 10);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(results, null, 2)\n }\n ]\n };\n }\n\n case 'get_content': {\n if (!args || typeof args.file_path !== 'string') {\n throw new Error('file_path is required');\n }\n const content = await getFileContent(args.file_path, args.chunks as string);\n return {\n content: [\n {\n type: 'text',\n text: content\n }\n ]\n };\n }\n\n case 'server_info': {\n const status = await getIndexStatus();\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n name: 'directory-indexer',\n version: '0.0.10',\n status: status\n }, null, 2)\n }\n ]\n };\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${errorMessage}`\n }\n ],\n isError: true\n };\n }\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n \n if (config.verbose) {\n console.error('MCP server started successfully');\n }\n}","#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { indexDirectories } from './indexing.js';\nimport { searchContent, findSimilarFiles, getFileContent } from './search.js';\nimport { loadConfig } from './config.js';\nimport { getIndexStatus } from './storage.js';\nimport { startMcpServer } from './mcp.js';\n\nexport async function main() {\n const program = new Command();\n \n program\n .name('directory-indexer')\n .description('AI-powered directory indexing with semantic search')\n .version('0.0.10');\n\n program\n .command('index')\n .description('Index directories for semantic search')\n .argument('<paths...>', 'Directory paths to index')\n .option('-v, --verbose', 'Enable verbose logging')\n .action(async (paths: string[], options) => {\n try {\n const config = await loadConfig({ verbose: options.verbose });\n console.log(`Indexing ${paths.length} directories...`);\n const result = await indexDirectories(paths, config);\n console.log(`Indexed ${result.indexed} files, skipped ${result.skipped} files, ${result.errors.length} errors`);\n if (result.errors.length > 0 && config.verbose) {\n console.log('Errors:', result.errors);\n }\n } catch (error) {\n console.error('Error indexing directories:', error);\n process.exit(1);\n }\n });\n\n program\n .command('search')\n .description('Search indexed content semantically')\n .argument('<query>', 'Search query')\n .option('-l, --limit <number>', 'Maximum number of results', '10')\n .option('-v, --verbose', 'Enable verbose logging')\n .action(async (query: string, options) => {\n try {\n await loadConfig({ verbose: options.verbose });\n const results = await searchContent(query, { limit: parseInt(options.limit) });\n \n if (results.length === 0) {\n console.log('No results found');\n return;\n }\n\n console.log(`Found ${results.length} results:\\n`);\n results.forEach((result, index) => {\n console.log(`${index + 1}. ${result.filePath}`);\n console.log(` Score: ${result.score.toFixed(3)}`);\n if (result.content) {\n console.log(` Content: ${result.content.substring(0, 150)}...`);\n }\n console.log();\n });\n } catch (error) {\n console.error('Error searching content:', error);\n process.exit(1);\n }\n });\n\n program\n .command('similar')\n .description('Find files similar to a given file')\n .argument('<file>', 'File path to find similar files for')\n .option('-l, --limit <number>', 'Maximum number of results', '10')\n .option('-v, --verbose', 'Enable verbose logging')\n .action(async (filePath: string, options) => {\n try {\n await loadConfig({ verbose: options.verbose });\n const results = await findSimilarFiles(filePath, parseInt(options.limit));\n \n if (results.length === 0) {\n console.log('No similar files found');\n return;\n }\n\n console.log(`Found ${results.length} similar files:\\n`);\n results.forEach((result, index) => {\n console.log(`${index + 1}. ${result.filePath}`);\n console.log(` Similarity: ${result.score.toFixed(3)}`);\n console.log();\n });\n } catch (error) {\n console.error('Error finding similar files:', error);\n process.exit(1);\n }\n });\n\n program\n .command('get')\n .description('Get file content')\n .argument('<file>', 'File path to retrieve')\n .option('-c, --chunks <range>', 'Chunk range (e.g., \"2-5\")')\n .option('-v, --verbose', 'Enable verbose logging')\n .action(async (filePath: string, options) => {\n try {\n await loadConfig({ verbose: options.verbose });\n const content = await getFileContent(filePath, options.chunks);\n console.log(content);\n } catch (error) {\n console.error('Error getting file content:', error);\n process.exit(1);\n }\n });\n\n program\n .command('serve')\n .description('Start MCP server')\n .option('-v, --verbose', 'Enable verbose logging')\n .action(async (options) => {\n try {\n const config = await loadConfig({ verbose: options.verbose });\n await startMcpServer(config);\n } catch (error) {\n console.error('Error starting MCP server:', error);\n process.exit(1);\n }\n });\n\n program\n .command('status')\n .description('Show indexing status')\n .option('-v, --verbose', 'Enable verbose logging')\n .action(async (options) => {\n try {\n await loadConfig({ verbose: options.verbose });\n const status = await getIndexStatus();\n \n console.log('Indexing Status:');\n console.log(` Directories indexed: ${status.directoriesIndexed}`);\n console.log(` Files indexed: ${status.filesIndexed}`);\n console.log(` Total chunks: ${status.chunksIndexed}`);\n console.log(` Database size: ${status.databaseSize}`);\n console.log(` Last indexed: ${status.lastIndexed || 'Never'}`);\n \n if (status.errors.length > 0) {\n console.log(` Errors: ${status.errors.length}`);\n if (options.verbose) {\n console.log(' Recent errors:');\n status.errors.slice(0, 5).forEach(error => {\n console.log(` - ${error}`);\n });\n }\n }\n } catch (error) {\n console.error('Error getting status:', error);\n process.exit(1);\n }\n });\n\n await program.parseAsync();\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch(console.error);\n}"],"names":[],"mappings":"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"}
package/dist/config.js ADDED
@@ -0,0 +1,67 @@
1
+ import { homedir } from "os";
2
+ import { join } from "path";
3
+ import { z } from "zod";
4
+ const ConfigSchema = z.object({
5
+ storage: z.object({
6
+ sqlitePath: z.string(),
7
+ qdrantEndpoint: z.string().url(),
8
+ qdrantCollection: z.string()
9
+ }),
10
+ embedding: z.object({
11
+ provider: z.enum(["ollama", "openai", "mock"]),
12
+ model: z.string(),
13
+ endpoint: z.string().url()
14
+ }),
15
+ indexing: z.object({
16
+ chunkSize: z.number().positive(),
17
+ chunkOverlap: z.number().nonnegative(),
18
+ maxFileSize: z.number().positive(),
19
+ ignorePatterns: z.array(z.string())
20
+ }),
21
+ dataDir: z.string(),
22
+ verbose: z.boolean()
23
+ });
24
+ class ConfigError extends Error {
25
+ constructor(message, cause) {
26
+ super(message);
27
+ this.cause = cause;
28
+ this.name = "ConfigError";
29
+ }
30
+ }
31
+ function loadConfig(options = {}) {
32
+ const dataDir = process.env.DIRECTORY_INDEXER_DATA_DIR || join(homedir(), ".directory-indexer");
33
+ const config = {
34
+ storage: {
35
+ sqlitePath: join(dataDir, "data.db"),
36
+ qdrantEndpoint: process.env.QDRANT_ENDPOINT || "http://localhost:6333",
37
+ qdrantCollection: process.env.DIRECTORY_INDEXER_QDRANT_COLLECTION || "directory-indexer"
38
+ },
39
+ embedding: {
40
+ provider: process.env.EMBEDDING_PROVIDER || "ollama",
41
+ model: process.env.EMBEDDING_MODEL || "nomic-embed-text",
42
+ endpoint: process.env.OLLAMA_ENDPOINT || "http://localhost:11434"
43
+ },
44
+ indexing: {
45
+ chunkSize: parseInt(process.env.CHUNK_SIZE || "512"),
46
+ chunkOverlap: parseInt(process.env.CHUNK_OVERLAP || "50"),
47
+ maxFileSize: parseInt(process.env.MAX_FILE_SIZE || "10485760"),
48
+ ignorePatterns: [".git", "node_modules", "target", ".DS_Store"]
49
+ },
50
+ dataDir,
51
+ verbose: options.verbose ?? process.env.VERBOSE === "true"
52
+ };
53
+ try {
54
+ return ConfigSchema.parse(config);
55
+ } catch (error) {
56
+ if (error instanceof z.ZodError) {
57
+ const messages = error.errors.map((e) => `${e.path.join(".")}: ${e.message}`);
58
+ throw new ConfigError(`Configuration validation failed: ${messages.join(", ")}`, error);
59
+ }
60
+ throw new ConfigError("Failed to load configuration", error);
61
+ }
62
+ }
63
+ export {
64
+ ConfigError,
65
+ loadConfig
66
+ };
67
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sources":["../src/config.ts"],"sourcesContent":["import { homedir } from 'os';\nimport { join } from 'path';\nimport { z } from 'zod';\n\nconst ConfigSchema = z.object({\n storage: z.object({\n sqlitePath: z.string(),\n qdrantEndpoint: z.string().url(),\n qdrantCollection: z.string(),\n }),\n embedding: z.object({\n provider: z.enum(['ollama', 'openai', 'mock']),\n model: z.string(),\n endpoint: z.string().url(),\n }),\n indexing: z.object({\n chunkSize: z.number().positive(),\n chunkOverlap: z.number().nonnegative(),\n maxFileSize: z.number().positive(),\n ignorePatterns: z.array(z.string()),\n }),\n dataDir: z.string(),\n verbose: z.boolean(),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\nexport class ConfigError extends Error {\n constructor(message: string, public override cause?: Error) {\n super(message);\n this.name = 'ConfigError';\n }\n}\n\nexport function loadConfig(options: { verbose?: boolean } = {}): Config {\n const dataDir = process.env.DIRECTORY_INDEXER_DATA_DIR || join(homedir(), '.directory-indexer');\n \n const config = {\n storage: {\n sqlitePath: join(dataDir, 'data.db'),\n qdrantEndpoint: process.env.QDRANT_ENDPOINT || 'http://localhost:6333',\n qdrantCollection: process.env.DIRECTORY_INDEXER_QDRANT_COLLECTION || 'directory-indexer',\n },\n embedding: {\n provider: (process.env.EMBEDDING_PROVIDER as Config['embedding']['provider']) || 'ollama',\n model: process.env.EMBEDDING_MODEL || 'nomic-embed-text',\n endpoint: process.env.OLLAMA_ENDPOINT || 'http://localhost:11434',\n },\n indexing: {\n chunkSize: parseInt(process.env.CHUNK_SIZE || '512'),\n chunkOverlap: parseInt(process.env.CHUNK_OVERLAP || '50'),\n maxFileSize: parseInt(process.env.MAX_FILE_SIZE || '10485760'),\n ignorePatterns: ['.git', 'node_modules', 'target', '.DS_Store'],\n },\n dataDir,\n verbose: options.verbose ?? (process.env.VERBOSE === 'true'),\n };\n\n try {\n return ConfigSchema.parse(config);\n } catch (error) {\n if (error instanceof z.ZodError) {\n const messages = error.errors.map(e => `${e.path.join('.')}: ${e.message}`);\n throw new ConfigError(`Configuration validation failed: ${messages.join(', ')}`, error);\n }\n throw new ConfigError('Failed to load configuration', error as Error);\n }\n}"],"names":[],"mappings":";;;AAIA,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,SAAS,EAAE,OAAO;AAAA,IAChB,YAAY,EAAE,OAAA;AAAA,IACd,gBAAgB,EAAE,OAAA,EAAS,IAAA;AAAA,IAC3B,kBAAkB,EAAE,OAAA;AAAA,EAAO,CAC5B;AAAA,EACD,WAAW,EAAE,OAAO;AAAA,IAClB,UAAU,EAAE,KAAK,CAAC,UAAU,UAAU,MAAM,CAAC;AAAA,IAC7C,OAAO,EAAE,OAAA;AAAA,IACT,UAAU,EAAE,OAAA,EAAS,IAAA;AAAA,EAAI,CAC1B;AAAA,EACD,UAAU,EAAE,OAAO;AAAA,IACjB,WAAW,EAAE,OAAA,EAAS,SAAA;AAAA,IACtB,cAAc,EAAE,OAAA,EAAS,YAAA;AAAA,IACzB,aAAa,EAAE,OAAA,EAAS,SAAA;AAAA,IACxB,gBAAgB,EAAE,MAAM,EAAE,QAAQ;AAAA,EAAA,CACnC;AAAA,EACD,SAAS,EAAE,OAAA;AAAA,EACX,SAAS,EAAE,QAAA;AACb,CAAC;AAIM,MAAM,oBAAoB,MAAM;AAAA,EACrC,YAAY,SAAiC,OAAe;AAC1D,UAAM,OAAO;AAD8B,SAAA,QAAA;AAE3C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,WAAW,UAAiC,IAAY;AACtE,QAAM,UAAU,QAAQ,IAAI,8BAA8B,KAAK,QAAA,GAAW,oBAAoB;AAE9F,QAAM,SAAS;AAAA,IACb,SAAS;AAAA,MACP,YAAY,KAAK,SAAS,SAAS;AAAA,MACnC,gBAAgB,QAAQ,IAAI,mBAAmB;AAAA,MAC/C,kBAAkB,QAAQ,IAAI,uCAAuC;AAAA,IAAA;AAAA,IAEvE,WAAW;AAAA,MACT,UAAW,QAAQ,IAAI,sBAA0D;AAAA,MACjF,OAAO,QAAQ,IAAI,mBAAmB;AAAA,MACtC,UAAU,QAAQ,IAAI,mBAAmB;AAAA,IAAA;AAAA,IAE3C,UAAU;AAAA,MACR,WAAW,SAAS,QAAQ,IAAI,cAAc,KAAK;AAAA,MACnD,cAAc,SAAS,QAAQ,IAAI,iBAAiB,IAAI;AAAA,MACxD,aAAa,SAAS,QAAQ,IAAI,iBAAiB,UAAU;AAAA,MAC7D,gBAAgB,CAAC,QAAQ,gBAAgB,UAAU,WAAW;AAAA,IAAA;AAAA,IAEhE;AAAA,IACA,SAAS,QAAQ,WAAY,QAAQ,IAAI,YAAY;AAAA,EAAA;AAGvD,MAAI;AACF,WAAO,aAAa,MAAM,MAAM;AAAA,EAClC,SAAS,OAAO;AACd,QAAI,iBAAiB,EAAE,UAAU;AAC/B,YAAM,WAAW,MAAM,OAAO,IAAI,OAAK,GAAG,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE;AAC1E,YAAM,IAAI,YAAY,oCAAoC,SAAS,KAAK,IAAI,CAAC,IAAI,KAAK;AAAA,IACxF;AACA,UAAM,IAAI,YAAY,gCAAgC,KAAc;AAAA,EACtE;AACF;"}