@ulpi/codemap 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,73 @@
1
+ ULPI Codemap License
2
+
3
+ Copyright (c) 2025-present ULPI Inc. All rights reserved.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to use
7
+ the Software for local, non-commercial and commercial purposes on machines
8
+ owned or controlled by the licensee, subject to the following conditions:
9
+
10
+ 1. GRANT OF USE
11
+
12
+ You may install, run, and use the Software on any number of machines you
13
+ own or control, for any purpose including personal, educational, and
14
+ commercial use.
15
+
16
+ 2. RESTRICTIONS
17
+
18
+ You may NOT:
19
+
20
+ a. Modify, adapt, translate, reverse engineer, decompile, disassemble,
21
+ or create derivative works based on the Software.
22
+
23
+ b. Redistribute, sublicense, sell, lease, rent, or otherwise transfer
24
+ the Software or any portion thereof to any third party, whether in
25
+ source code, binary, or any other form.
26
+
27
+ c. Remove, alter, or obscure any proprietary notices, labels, or marks
28
+ on the Software.
29
+
30
+ d. Use the Software to build a competing product or service that
31
+ replicates the core functionality of the Software.
32
+
33
+ e. Host, offer, or operate the Software as a service (SaaS) for third
34
+ parties, whether or not for compensation.
35
+
36
+ 3. INTELLECTUAL PROPERTY
37
+
38
+ The Software and all copies thereof are proprietary to ULPI Inc. and
39
+ title thereto remains in ULPI Inc. All rights in the Software not
40
+ specifically granted in this license are reserved to ULPI Inc.
41
+
42
+ 4. NO WARRANTY
43
+
44
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
45
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
46
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
47
+ IN NO EVENT SHALL ULPI INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
49
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
50
+ DEALINGS IN THE SOFTWARE.
51
+
52
+ 5. TERMINATION
53
+
54
+ This license is effective until terminated. ULPI Inc. may terminate this
55
+ license at any time if you fail to comply with any term of this license.
56
+ Upon termination, you must destroy all copies of the Software in your
57
+ possession.
58
+
59
+ 6. CHANGES TO LICENSE TERMS
60
+
61
+ ULPI Inc. reserves the right to change the terms of this license in
62
+ future versions of the Software. Continued use of a version of the
63
+ Software is governed by the license terms that accompanied that version.
64
+ Updated license terms apply only to new versions released after the
65
+ change.
66
+
67
+ 7. GOVERNING LAW
68
+
69
+ This license shall be governed by and construed in accordance with the
70
+ laws of the State of Delaware, United States, without regard to its
71
+ conflict of laws provisions.
72
+
73
+ For licensing inquiries, contact: legal@ulpi.dev
package/README.md ADDED
@@ -0,0 +1,386 @@
1
+ # @ulpi/codemap
2
+
3
+ Code intelligence CLI — hybrid vector + BM25 semantic search, dependency analysis, and PageRank for any codebase.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@ulpi/codemap.svg)](https://www.npmjs.com/package/@ulpi/codemap) [![node](https://img.shields.io/node/v/@ulpi/codemap.svg)](https://nodejs.org)
6
+
7
+ ## Features
8
+
9
+ - **Hybrid search** — combines vector similarity with BM25 keyword scoring for accurate code search
10
+ - **Symbol lookup** — find functions, classes, types, and interfaces by name
11
+ - **Dependency graph** — trace imports and dependents across your codebase
12
+ - **PageRank** — identify the most important files by connectivity
13
+ - **Cycle detection** — find circular dependencies automatically
14
+ - **Coupling metrics** — measure afferent/efferent coupling and instability per file
15
+ - **Real-time watching** — incremental re-indexing on file changes
16
+ - **MCP server** — 12 tools for AI agent integration (Claude, Cursor, VS Code, etc.)
17
+ - **Per-branch indexing** — separate indexes for each git branch
18
+ - **Multiple providers** — works with Ollama (free, local), OpenAI, or ULPI Cloud embeddings
19
+
20
+ ## Quick Start
21
+
22
+ ```bash
23
+ npm install -g @ulpi/codemap
24
+
25
+ codemap init # Choose provider + model
26
+ codemap index # Index your project
27
+ codemap search "authentication middleware"
28
+ ```
29
+
30
+ ## Embedding Providers
31
+
32
+ | Provider | Models | Dims | Cost | Requires |
33
+ |----------|--------|------|------|----------|
34
+ | **Ollama** | `nomic-embed-text` (768), `mxbai-embed-large` (1024), `all-minilm` (384) | varies | Free | Ollama running locally |
35
+ | **OpenAI** | `text-embedding-3-small` (1536), `text-embedding-3-large` (3072) | varies | Paid | `OPENAI_API_KEY` |
36
+ | **ULPI Cloud** | `code` (1024) | 1024 | Managed | `ULPI_API_KEY` |
37
+
38
+ `codemap init` walks you through provider and model selection interactively.
39
+
40
+ ## Command Reference
41
+
42
+ ### `codemap init`
43
+
44
+ Interactive first-time setup. Prompts for embedding provider, model, and API key.
45
+
46
+ ```bash
47
+ codemap init
48
+ codemap init --provider ollama # Skip interactive prompt
49
+ codemap init --provider openai
50
+ codemap init --provider ulpi
51
+ ```
52
+
53
+ ### `codemap index`
54
+
55
+ Index the current project for code search. Scans files, chunks with AST awareness, generates embeddings, and builds the dependency graph.
56
+
57
+ ```bash
58
+ codemap index
59
+ codemap index --full # Force full re-index (ignore incremental state)
60
+ ```
61
+
62
+ ### `codemap search <query>`
63
+
64
+ Search code using hybrid vector + BM25 scoring.
65
+
66
+ ```bash
67
+ codemap search "database connection pool"
68
+ codemap search "error handling" --limit 20
69
+ codemap search "auth middleware" --json
70
+ ```
71
+
72
+ | Option | Description | Default |
73
+ |--------|-------------|---------|
74
+ | `-l, --limit <n>` | Max results | `10` |
75
+ | `--json` | Output as JSON | — |
76
+
77
+ ### `codemap symbols <query>`
78
+
79
+ Find functions, classes, and types by name.
80
+
81
+ ```bash
82
+ codemap symbols "createUser"
83
+ codemap symbols "Router" --limit 5
84
+ codemap symbols "Handler" --json
85
+ ```
86
+
87
+ | Option | Description | Default |
88
+ |--------|-------------|---------|
89
+ | `-l, --limit <n>` | Max results | `20` |
90
+ | `--json` | Output as JSON | — |
91
+
92
+ ### `codemap status`
93
+
94
+ Show index statistics for the current project.
95
+
96
+ ```bash
97
+ codemap status
98
+ codemap status --json
99
+ ```
100
+
101
+ ### `codemap watch`
102
+
103
+ Watch for file changes and update the index in real-time.
104
+
105
+ ```bash
106
+ codemap watch
107
+ codemap watch --debounce 500
108
+ ```
109
+
110
+ | Option | Description | Default |
111
+ |--------|-------------|---------|
112
+ | `--debounce <ms>` | Debounce interval | `300` |
113
+
114
+ ### `codemap deps <file>`
115
+
116
+ Show files this file depends on (outgoing imports).
117
+
118
+ ```bash
119
+ codemap deps src/routes/auth.ts
120
+ codemap deps src/index.ts --json
121
+ ```
122
+
123
+ ### `codemap dependents <file>`
124
+
125
+ Show files that depend on this file (incoming imports).
126
+
127
+ ```bash
128
+ codemap dependents src/utils/db.ts
129
+ codemap dependents src/config.ts --json
130
+ ```
131
+
132
+ ### `codemap rank [file]`
133
+
134
+ Show PageRank importance scores. Without a file argument, lists top-ranked files.
135
+
136
+ ```bash
137
+ codemap rank # Top 20 files by importance
138
+ codemap rank --limit 50
139
+ codemap rank src/index.ts # Single file score
140
+ codemap rank --json
141
+ ```
142
+
143
+ | Option | Description | Default |
144
+ |--------|-------------|---------|
145
+ | `-l, --limit <n>` | Number of top files | `20` |
146
+ | `--json` | Output as JSON | — |
147
+
148
+ ### `codemap cycles`
149
+
150
+ Detect circular dependencies in the codebase.
151
+
152
+ ```bash
153
+ codemap cycles
154
+ codemap cycles --json
155
+ ```
156
+
157
+ ### `codemap ignore`
158
+
159
+ Generate or reset `.codemapignore` with default exclusion patterns.
160
+
161
+ ```bash
162
+ codemap ignore
163
+ codemap ignore --force # Overwrite existing .codemapignore
164
+ ```
165
+
166
+ ### `codemap config`
167
+
168
+ Get, set, or list configuration values.
169
+
170
+ ```bash
171
+ codemap config list
172
+ codemap config get embedding.provider
173
+ codemap config set embedding.provider openai
174
+ codemap config set embedding.apiKey sk-...
175
+ ```
176
+
177
+ ### `codemap serve`
178
+
179
+ Start an MCP server over stdio for AI agent integration.
180
+
181
+ ```bash
182
+ codemap serve
183
+ ```
184
+
185
+ ### Global Options
186
+
187
+ All commands support:
188
+
189
+ | Option | Description |
190
+ |--------|-------------|
191
+ | `--cwd <dir>` | Override project directory |
192
+ | `--version` | Show version |
193
+ | `--help` | Show help |
194
+
195
+ ## MCP Integration
196
+
197
+ `codemap serve` starts an [MCP](https://modelcontextprotocol.io/) server over stdio, exposing 12 code intelligence tools to any compatible AI agent or editor.
198
+
199
+ ### Claude Code
200
+
201
+ Add to `.mcp.json` in your project root:
202
+
203
+ ```json
204
+ {
205
+ "mcpServers": {
206
+ "codemap": {
207
+ "command": "codemap",
208
+ "args": ["serve"]
209
+ }
210
+ }
211
+ }
212
+ ```
213
+
214
+ ### Claude Desktop
215
+
216
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
217
+
218
+ ```json
219
+ {
220
+ "mcpServers": {
221
+ "codemap": {
222
+ "command": "codemap",
223
+ "args": ["serve"],
224
+ "type": "stdio"
225
+ }
226
+ }
227
+ }
228
+ ```
229
+
230
+ ### Cursor
231
+
232
+ Add to `.cursor/mcp.json` in your project root:
233
+
234
+ ```json
235
+ {
236
+ "mcpServers": {
237
+ "codemap": {
238
+ "command": "codemap",
239
+ "args": ["serve"]
240
+ }
241
+ }
242
+ }
243
+ ```
244
+
245
+ ### Kiro
246
+
247
+ Add to `.kiro/settings/mcp.json` in your project root:
248
+
249
+ ```json
250
+ {
251
+ "mcpServers": {
252
+ "codemap": {
253
+ "command": "codemap",
254
+ "args": ["serve"]
255
+ }
256
+ }
257
+ }
258
+ ```
259
+
260
+ ### VS Code (Copilot)
261
+
262
+ Add to `.vscode/mcp.json` in your project root:
263
+
264
+ ```json
265
+ {
266
+ "servers": {
267
+ "codemap": {
268
+ "command": "codemap",
269
+ "args": ["serve"],
270
+ "type": "stdio"
271
+ }
272
+ }
273
+ }
274
+ ```
275
+
276
+ ### JetBrains (IntelliJ, WebStorm, etc.)
277
+
278
+ Go to Settings > Tools > AI Assistant > MCP Servers, add:
279
+
280
+ ```json
281
+ {
282
+ "mcpServers": {
283
+ "codemap": {
284
+ "command": "codemap",
285
+ "args": ["serve"]
286
+ }
287
+ }
288
+ }
289
+ ```
290
+
291
+ ### Windsurf
292
+
293
+ Add to `~/.codeium/windsurf/mcp_config.json`:
294
+
295
+ ```json
296
+ {
297
+ "mcpServers": {
298
+ "codemap": {
299
+ "command": "codemap",
300
+ "args": ["serve"]
301
+ }
302
+ }
303
+ }
304
+ ```
305
+
306
+ ### Zed
307
+
308
+ Add to `~/.config/zed/settings.json`:
309
+
310
+ ```json
311
+ {
312
+ "context_servers": {
313
+ "codemap": {
314
+ "command": {
315
+ "path": "codemap",
316
+ "args": ["serve"]
317
+ }
318
+ }
319
+ }
320
+ }
321
+ ```
322
+
323
+ ## MCP Tools Reference
324
+
325
+ | Tool | Description |
326
+ |------|-------------|
327
+ | `search_code` | Search code using hybrid vector + BM25 |
328
+ | `search_symbols` | Find functions, classes, and types by name |
329
+ | `get_file_summary` | Get file overview with symbols and size |
330
+ | `get_index_stats` | Get code search index statistics |
331
+ | `reindex` | Trigger a full code search re-index |
332
+ | `get_dependencies` | Get files this file imports (outgoing edges) |
333
+ | `get_dependents` | Get files that import this file (incoming edges) |
334
+ | `get_file_rank` | Get PageRank importance score for files |
335
+ | `find_cycles` | Detect circular dependencies |
336
+ | `get_coupling_metrics` | Analyze afferent/efferent coupling and instability |
337
+ | `get_depgraph_stats` | Get aggregate dependency graph statistics |
338
+ | `rebuild_depgraph` | Recompute PageRank and dependency metrics |
339
+
340
+ ## Environment Variables
341
+
342
+ | Variable | Purpose | Default |
343
+ |----------|---------|---------|
344
+ | `CODEMAP_DATA_DIR` | Override data directory | `~/.codemap` |
345
+ | `OPENAI_API_KEY` | OpenAI API key | — |
346
+ | `OLLAMA_HOST` | Ollama server URL | `http://localhost:11434` |
347
+ | `ULPI_API_KEY` | ULPI Cloud API key | — |
348
+ | `CODEMAP_PROJECT_DIR` | Override project directory (MCP mode) | `cwd` |
349
+
350
+ ## Configuration
351
+
352
+ Configuration is loaded in order of precedence (highest first):
353
+
354
+ 1. **Project config** — `.codemap.json` in project root
355
+ 2. **Global config** — `~/.codemap/config.json`
356
+ 3. **Defaults**
357
+
358
+ Manage with the `config` command:
359
+
360
+ ```bash
361
+ codemap config list # Show all values
362
+ codemap config get embedding.provider # Get a value
363
+ codemap config set embedding.model nomic-embed-text # Set a value
364
+ ```
365
+
366
+ ## How It Works
367
+
368
+ 1. **Scan** — discovers source files respecting `.gitignore` and deny patterns
369
+ 2. **Chunk** — splits files into AST-aware chunks (functions, classes, blocks)
370
+ 3. **Embed** — generates vector embeddings via your chosen provider
371
+ 4. **Store** — writes vectors to LanceDB and builds a BM25 index
372
+ 5. **Graph** — extracts import/export edges with tree-sitter, computes PageRank
373
+ 6. **Search** — combines vector similarity, BM25 keyword scoring, symbol boosting, and graph rank
374
+
375
+ Data is stored per-project and per-branch at `~/.codemap/{projectSlug}/{branchSlug}/`.
376
+
377
+ ## Requirements
378
+
379
+ - **Node.js** 18+
380
+ - **Ollama** provider: running Ollama instance with model pulled (`ollama pull nomic-embed-text`)
381
+ - **OpenAI** provider: valid `OPENAI_API_KEY`
382
+ - **ULPI Cloud** provider: valid `ULPI_API_KEY`
383
+
384
+ ## License
385
+
386
+ See [LICENSE](./LICENSE).
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveApiKey
4
+ } from "./chunk-SNG7R3UC.js";
5
+
6
+ // ../../packages/intelligence/embed-engine/dist/chunk-WX74CUTY.js
7
+ var OPENAI_EMBEDDINGS_URL = "https://api.openai.com/v1/embeddings";
8
+ var MAX_RETRIES = 3;
9
+ var RETRY_BASE_MS = 1e3;
10
+ var OpenAIEmbedder = class {
11
+ provider = "openai";
12
+ model;
13
+ dimensions;
14
+ apiKey;
15
+ constructor(model = "text-embedding-3-small", dimensions = 1536) {
16
+ this.model = model;
17
+ this.dimensions = dimensions;
18
+ const key = resolveApiKey("openai");
19
+ if (!key) {
20
+ throw new Error(
21
+ "OpenAI API key not found. Set it with:\n ulpi config set openai-key <your-key>\nOr switch to Ollama (local, no key needed):\n ulpi codemap config embedding.provider ollama"
22
+ );
23
+ }
24
+ this.apiKey = key;
25
+ }
26
+ async embed(texts) {
27
+ if (texts.length === 0) return [];
28
+ const body = {
29
+ input: texts,
30
+ model: this.model,
31
+ dimensions: this.dimensions
32
+ };
33
+ let lastError = null;
34
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
35
+ try {
36
+ const response = await fetch(OPENAI_EMBEDDINGS_URL, {
37
+ method: "POST",
38
+ headers: {
39
+ "Content-Type": "application/json",
40
+ Authorization: `Bearer ${this.apiKey}`
41
+ },
42
+ body: JSON.stringify(body)
43
+ });
44
+ if (!response.ok) {
45
+ const errorText = await response.text();
46
+ if (response.status === 401 || response.status === 403) {
47
+ throw new Error(`OpenAI API authentication error (${response.status}): check your OPENAI_API_KEY`);
48
+ }
49
+ if (response.status === 429 || response.status >= 500) {
50
+ lastError = new Error(`OpenAI API error (${response.status}): ${errorText.slice(0, 200)}`);
51
+ const delay = RETRY_BASE_MS * Math.pow(2, attempt);
52
+ await sleep(delay);
53
+ continue;
54
+ }
55
+ throw new Error(`OpenAI API error (${response.status}): ${errorText.slice(0, 200)}`);
56
+ }
57
+ const data = await response.json();
58
+ const sorted = data.data.sort((a, b) => a.index - b.index);
59
+ return sorted.map((item) => item.embedding);
60
+ } catch (err) {
61
+ if (err instanceof Error && (err.message.includes("authentication") || err.message.includes("Unknown"))) {
62
+ throw err;
63
+ }
64
+ lastError = err instanceof Error ? err : new Error(String(err));
65
+ if (attempt < MAX_RETRIES - 1) {
66
+ const delay = RETRY_BASE_MS * Math.pow(2, attempt);
67
+ await sleep(delay);
68
+ }
69
+ }
70
+ }
71
+ throw lastError ?? new Error("OpenAI embedding failed after retries");
72
+ }
73
+ };
74
+ function sleep(ms) {
75
+ return new Promise((resolve) => setTimeout(resolve, ms));
76
+ }
77
+
78
+ export {
79
+ OpenAIEmbedder
80
+ };