@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 +73 -0
- package/README.md +386 -0
- package/dist/chunk-5ISZDDN7.js +80 -0
- package/dist/chunk-7SDODQZD.js +200 -0
- package/dist/chunk-SNG7R3UC.js +38 -0
- package/dist/chunk-WUVKW5JG.js +72 -0
- package/dist/index.js +4440 -0
- package/dist/ollama-3XCUZMZT-J6Z4WWWO.js +7 -0
- package/dist/openai-RC75RP4O-NSFZC5O6.js +8 -0
- package/dist/ulpi-KLKEAQC3-5ATUONU7.js +10 -0
- package/package.json +35 -0
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
|
+
[](https://www.npmjs.com/package/@ulpi/codemap) [](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
|
+
};
|