Skip to content

Commit 6308ca2

Browse files
committed
packaging: npm package entrypoint fixes
1 parent 308b6b0 commit 6308ca2

File tree

6 files changed

+198
-9
lines changed

6 files changed

+198
-9
lines changed

bin/directory-indexer.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env node
2+
import('../dist/cli.js').then(({ main }) => {
3+
main().catch((error) => {
4+
console.error('CLI Error:', error);
5+
process.exit(1);
6+
});
7+
}).catch((error) => {
8+
console.error('Failed to load CLI:', error);
9+
process.exit(1);
10+
});

docs/bugs/cli-usage.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# CLI Usage Issue
2+
3+
## Problem Statement
4+
5+
The directory-indexer CLI commands fail to execute properly when installed via npm or used with npx. Commands hang indefinitely and produce no output, including basic help and version commands.
6+
7+
## Symptoms
8+
9+
- `directory-indexer --help` hangs with no output
10+
- `directory-indexer --version` hangs with no output
11+
- `npx directory-indexer --help` hangs with no output
12+
- All CLI commands hang indefinitely (tested with 3-5 second timeouts)
13+
- Commands exit with code 0 but produce no stdout or stderr
14+
- Issue occurs both with global npm install and npx usage
15+
16+
## Expected Behavior
17+
18+
CLI commands should execute normally and display output:
19+
```bash
20+
$ directory-indexer --help
21+
Usage: directory-indexer [options] [command]
22+
23+
AI-powered directory indexing with semantic search
24+
...
25+
```
26+
27+
## Current Status - RESOLVED ✅
28+
29+
-**Package structure**: Correct `bin` configuration in package.json
30+
-**Shebang**: Proper `#!/usr/bin/env node` in CLI script
31+
-**Symlink**: npm creates `/usr/bin/directory-indexer` symlink correctly
32+
-**Permissions**: CLI script has execute permissions
33+
-**Dependencies**: Qdrant and Ollama services running
34+
-**Execution**: Commands now work properly with CLI launcher pattern
35+
36+
## Resolution Implemented (v0.0.13)
37+
38+
### Root Cause Identified
39+
The CLI script called `main()` unconditionally at module load time, causing hanging when the module was imported/executed via npm symlinks.
40+
41+
### Solution Applied
42+
Implemented industry-standard CLI launcher pattern used by Vite ecosystem:
43+
44+
1. **CLI Launcher**: Created `bin/directory-indexer.js` that dynamically imports the CLI module
45+
2. **Clean Module Structure**: Removed unconditional execution from CLI module
46+
3. **Dynamic Version**: Both CLI and MCP server now read version from package.json
47+
4. **Updated Package Config**: Changed bin path and added proper file includes
48+
49+
### New Package Configuration
50+
```json
51+
{
52+
"bin": {
53+
"directory-indexer": "bin/directory-indexer.js"
54+
},
55+
"files": ["dist/", "bin/"],
56+
"type": "module"
57+
}
58+
```
59+
60+
### CLI Launcher (`bin/directory-indexer.js`)
61+
```javascript
62+
#!/usr/bin/env node
63+
import('../dist/cli.js').then(({ main }) => {
64+
main().catch((error) => {
65+
console.error('CLI Error:', error);
66+
process.exit(1);
67+
});
68+
}).catch((error) => {
69+
console.error('Failed to load CLI:', error);
70+
process.exit(1);
71+
});
72+
```
73+
74+
### CLI Module (`src/cli.ts`)
75+
```typescript
76+
// No unconditional execution - safely importable
77+
export async function main() {
78+
// CLI logic here
79+
}
80+
// Main function is exported for launcher to use
81+
```
82+
83+
## Reproduction Steps
84+
85+
### Prerequisites
86+
1. Start development services:
87+
```bash
88+
./scripts/start-dev-services.sh
89+
```
90+
91+
2. Set up debug container:
92+
```bash
93+
./scripts/docker-debug/setup-debug-container.sh
94+
```
95+
96+
### Test Commands
97+
```bash
98+
# Test direct CLI usage (hangs)
99+
docker exec test-directory-indexer directory-indexer --help
100+
101+
# Test npx usage (hangs)
102+
docker exec test-directory-indexer timeout 5 npx directory-indexer --help
103+
104+
# Test with timeout to confirm hanging
105+
docker exec test-directory-indexer timeout 3 directory-indexer --version
106+
```
107+
108+
### Debug Information
109+
```bash
110+
# Check symlink
111+
docker exec test-directory-indexer ls -la /usr/bin/directory-indexer
112+
113+
# Check package structure
114+
docker exec test-directory-indexer ls -la /usr/lib/node_modules/directory-indexer/
115+
116+
# Check mounted dist
117+
docker exec test-directory-indexer ls -la /usr/lib/node_modules/directory-indexer/dist/
118+
```
119+
120+
## Development Workflow
121+
122+
The debug container allows live code iteration:
123+
124+
1. **Make changes** to `src/cli.ts`
125+
2. **Rebuild**: `npm run build`
126+
3. **Test immediately**: `docker exec test-directory-indexer directory-indexer --help`
127+
128+
No container restart needed due to mounted dist directory.
129+
130+
## Environment
131+
132+
- **Container**: Ubuntu 22.04 with Node.js 20.19.3
133+
- **Package**: directory-indexer@0.0.12 installed globally
134+
- **Services**: Qdrant (localhost:6333) and Ollama (localhost:11434) running
135+
- **Test Data**: Available at `/test-data` in container
136+
137+
## Testing After v0.0.13 Publication
138+
139+
Once version 0.0.13 is published to npm:
140+
141+
1. **Test with Docker container**:
142+
```bash
143+
./scripts/docker-debug/setup-debug-container.sh
144+
docker exec test-directory-indexer directory-indexer --help
145+
```
146+
147+
2. **Test npx usage**:
148+
```bash
149+
npx directory-indexer@0.0.13 --help
150+
npx directory-indexer@0.0.13 --version
151+
```
152+
153+
3. **Test global install**:
154+
```bash
155+
npm install -g directory-indexer@0.0.13
156+
directory-indexer --help
157+
```
158+
159+
## Known Issues Post-Fix
160+
161+
- Integration tests need updates to work with new CLI launcher pattern
162+
- Test setup may need adjustment for CLI execution testing

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"name": "directory-indexer",
3-
"version": "0.0.12",
3+
"version": "0.0.13",
44
"description": "AI-powered directory indexing with semantic search for MCP servers",
55
"main": "dist/cli.js",
66
"bin": {
7-
"directory-indexer": "dist/cli.js"
7+
"directory-indexer": "bin/directory-indexer.js"
88
},
99
"type": "module",
1010
"scripts": {
@@ -42,7 +42,8 @@
4242
"node": ">=18.0.0"
4343
},
4444
"files": [
45-
"dist/"
45+
"dist/",
46+
"bin/"
4647
],
4748
"dependencies": {
4849
"@modelcontextprotocol/sdk": "^0.6.0",

src/cli.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,27 @@
22

33
import { Command } from 'commander';
44
import { fileURLToPath } from 'url';
5+
import { readFileSync } from 'fs';
6+
import { join, dirname } from 'path';
57
import { indexDirectories } from './indexing.js';
68
import { searchContent, findSimilarFiles, getFileContent } from './search.js';
79
import { loadConfig } from './config.js';
810
import { getIndexStatus } from './storage.js';
911
import { startMcpServer } from './mcp.js';
1012

13+
// Read version from package.json
14+
const __dirname = dirname(fileURLToPath(import.meta.url));
15+
const packageJsonPath = join(__dirname, '../package.json');
16+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
17+
const VERSION = packageJson.version;
18+
1119
export async function main() {
1220
const program = new Command();
1321

1422
program
1523
.name('directory-indexer')
1624
.description('AI-powered directory indexing with semantic search')
17-
.version('0.0.10');
25+
.version(VERSION);
1826

1927
program
2028
.command('index')
@@ -160,5 +168,4 @@ export async function main() {
160168
await program.parseAsync();
161169
}
162170

163-
// For CLI scripts, we can call main directly since this file is only used as an executable
164-
main().catch(console.error);
171+
// Main function is already exported above

src/mcp.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@ import {
55
ListToolsRequestSchema,
66
Tool
77
} from '@modelcontextprotocol/sdk/types.js';
8+
import { readFileSync } from 'fs';
9+
import { join, dirname } from 'path';
10+
import { fileURLToPath } from 'url';
811
import { Config } from './config.js';
912
import { indexDirectories } from './indexing.js';
1013
import { searchContent, findSimilarFiles, getFileContent } from './search.js';
1114
import { getIndexStatus } from './storage.js';
1215

16+
// Read version from package.json
17+
const __dirname = dirname(fileURLToPath(import.meta.url));
18+
const packageJsonPath = join(__dirname, '../package.json');
19+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
20+
const VERSION = packageJson.version;
21+
1322
const MCP_TOOLS: Tool[] = [
1423
{
1524
name: 'index',
@@ -95,7 +104,7 @@ export async function startMcpServer(config: Config): Promise<void> {
95104
const server = new Server(
96105
{
97106
name: 'directory-indexer',
98-
version: '0.0.10'
107+
version: VERSION
99108
},
100109
{
101110
capabilities: {
@@ -184,7 +193,7 @@ export async function startMcpServer(config: Config): Promise<void> {
184193
type: 'text',
185194
text: JSON.stringify({
186195
name: 'directory-indexer',
187-
version: '0.0.10',
196+
version: VERSION,
188197
status: status
189198
}, null, 2)
190199
}

tests/integration.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ async function checkOllamaHealth(): Promise<boolean> {
5656

5757
function runCLI(args: string[], timeout = 30000): Promise<{ stdout: string; stderr: string; exitCode: number }> {
5858
return new Promise((resolve, reject) => {
59-
const child = spawn('node', ['dist/cli.js', ...args], {
59+
const child = spawn('node', ['bin/directory-indexer.js', ...args], {
6060
env: {
6161
...process.env,
6262
DIRECTORY_INDEXER_QDRANT_COLLECTION: 'directory-indexer-test-node'

0 commit comments

Comments
 (0)