@neuralsea/workspace-indexer 0.5.1 → 0.6.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/README.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  A **local-first**, **multi-repo** workspace indexer for AI agents (e.g. your custom agent “Damocles”).
4
4
 
5
+
6
+ ## Default backends
7
+
8
+ - **Indexing DB**: SQLite via **sql.js (WASM)** (runs in VS Code extension hosts; no native binaries).
9
+ - **Vector backend**: `bruteforce` by default (zero-config). For enterprise persistence and scalability, configure `qdrant`.
10
+
5
11
  It provides:
6
12
 
7
13
  - **Whole-workspace indexing** (multiple Git repos under a workspace root)
@@ -9,7 +15,7 @@ It provides:
9
15
  - **Semantic embeddings** (pluggable: **Ollama local**, **OpenAI**, or deterministic offline **hash**)
10
16
  - **Hybrid retrieval**: vector similarity **plus** lexical search (SQLite FTS5) with configurable weights
11
17
  - **Pluggable vector backends**: `bruteforce`, `hnswlib` (HNSW), `qdrant` (local/remote), `faiss`, or a custom provider
12
- - **Branch/commit isolation**: a separate index per repo per Git **HEAD** commit (reduces stale-context errors)
18
+ - **Head-synchronised indexing (enterprise-safe invalidation)**: each repo index is keyed by `(repo_id, head_commit, embedder_id, index_fingerprint)`. Any change invalidates and forces a clean rebuild to avoid stale or mixed-context results.
13
19
  - **Fast incremental updates**: file watching + `.git/HEAD` switch detection
14
20
  - **Security controls**: respects `.gitignore` via `git ls-files`, plus `.petriignore/.augmentignore`, plus redaction hooks
15
21
 
@@ -30,8 +30,36 @@ var OpenAIEmbeddingsProvider = class {
30
30
  }
31
31
  };
32
32
 
33
+ // src/limit.ts
34
+ function createLimit(concurrency) {
35
+ const n = Math.max(1, Math.floor(concurrency || 1));
36
+ let active = 0;
37
+ const queue = [];
38
+ const runNext = () => {
39
+ active--;
40
+ const next = queue.shift();
41
+ if (next) next();
42
+ };
43
+ return (fn) => new Promise((resolve, reject) => {
44
+ const run = () => {
45
+ active++;
46
+ Promise.resolve().then(fn).then(
47
+ (v) => {
48
+ resolve(v);
49
+ runNext();
50
+ },
51
+ (e) => {
52
+ reject(e);
53
+ runNext();
54
+ }
55
+ );
56
+ };
57
+ if (active < n) run();
58
+ else queue.push(run);
59
+ });
60
+ }
61
+
33
62
  // src/embeddings/ollama.ts
34
- import pLimit from "p-limit";
35
63
  var OllamaEmbeddingsProvider = class {
36
64
  id;
37
65
  dimension = null;
@@ -76,14 +104,14 @@ var OllamaEmbeddingsProvider = class {
76
104
  async embed(texts) {
77
105
  const batch = await this.tryBatchEndpoint(texts);
78
106
  if (batch) return batch;
79
- const limit = pLimit(this.concurrency);
107
+ const limit = createLimit(this.concurrency);
80
108
  const out = await Promise.all(texts.map((t) => limit(() => this.embedOne(t))));
81
109
  return out;
82
110
  }
83
111
  };
84
112
 
85
113
  // src/embeddings/hash.ts
86
- import { sha256 } from "@noble/hashes/sha256";
114
+ import { sha256 } from "@noble/hashes/sha2.js";
87
115
  var HashEmbeddingsProvider = class {
88
116
  id;
89
117
  dimension;
@@ -170,8 +198,8 @@ function deepMergeProfile(base, patch) {
170
198
  }
171
199
 
172
200
  // src/util.ts
173
- import { sha256 as sha2562 } from "@noble/hashes/sha256";
174
- import { bytesToHex } from "@noble/hashes/utils";
201
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
202
+ import { bytesToHex } from "@noble/hashes/utils.js";
175
203
  function toBytes(data) {
176
204
  return typeof data === "string" ? new TextEncoder().encode(data) : data;
177
205
  }