ctxloom-pro 1.7.6 → 1.7.8
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 +2 -2
- package/apps/dashboard/dist/server/index.js +34 -2
- package/dist/VectorStore-IHNQ3NOD.js +9 -0
- package/dist/{chunk-ISXDIRSN.js → chunk-7WLMI4AD.js} +39 -7
- package/dist/{chunk-JZOJC3S7.js → chunk-R32CUQAL.js} +2 -2
- package/dist/{chunk-XQEQLXY5.js → chunk-Z3NQHCWG.js} +112 -2
- package/dist/{embedder-4MM7D3UE.js → embedder-E2GDBGOH.js} +2 -2
- package/dist/index.js +10 -10
- package/dist/{src-FB2SJJZR.js → src-C5NS2JAW.js} +4 -4
- package/dist/workers/indexerWorker.js +2 -2
- package/package.json +1 -1
- package/dist/VectorStore-5ALWL6XF.js +0 -9
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ The full first-run flow is **one install + one trial + one init per project.** E
|
|
|
69
69
|
npm install -g ctxloom-pro
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
> **For local trial / dev use the unpinned command above is fine.** For unattended CI usage, pin to the exact version (`ctxloom-pro@1.7.
|
|
72
|
+
> **For local trial / dev use the unpinned command above is fine.** For unattended CI usage, pin to the exact version (`ctxloom-pro@1.7.8`) so future CLI releases don't silently desync your agent-spec coverage — see the workflow example below.
|
|
73
73
|
|
|
74
74
|
### 2 — Start your free trial (once per email)
|
|
75
75
|
|
|
@@ -383,7 +383,7 @@ jobs:
|
|
|
383
383
|
# Exact pin (not `@^1`) so future CLI releases that add/remove MCP
|
|
384
384
|
# tools don't silently desync your reviewer-agent specs. Bump on
|
|
385
385
|
# every release; see CHANGELOG.md for the live version table.
|
|
386
|
-
- run: npm install -g ctxloom-pro@1.7.
|
|
386
|
+
- run: npm install -g ctxloom-pro@1.7.8
|
|
387
387
|
- run: ctxloom index
|
|
388
388
|
- run: ctxloom rules check --json
|
|
389
389
|
```
|
|
@@ -2929,7 +2929,7 @@ var CallGraphIndex = class _CallGraphIndex {
|
|
|
2929
2929
|
var TS_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".vue"]);
|
|
2930
2930
|
var PY_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".ipynb"]);
|
|
2931
2931
|
var AST_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs", ".java", ".cs", ".rb", ".kt", ".kts", ".swift", ".ipynb", ".php", ".dart"]);
|
|
2932
|
-
var CTXLOOM_VERSION = "1.7.
|
|
2932
|
+
var CTXLOOM_VERSION = "1.7.8".length > 0 ? "1.7.8" : "dev";
|
|
2933
2933
|
var SNAPSHOT_SCHEMA_VERSION = 2;
|
|
2934
2934
|
function compareCtxloomVersions(snapshotVer, currentVer) {
|
|
2935
2935
|
if (snapshotVer === currentVer) return "same";
|
|
@@ -3112,6 +3112,7 @@ var DependencyGraph = class {
|
|
|
3112
3112
|
});
|
|
3113
3113
|
this.symbolIndex.set(node.name, existing);
|
|
3114
3114
|
}
|
|
3115
|
+
this.indexClassMethods(node, relPath);
|
|
3115
3116
|
}
|
|
3116
3117
|
if (TS_EXTENSIONS2.has(ext)) {
|
|
3117
3118
|
const callEdges = await this.parser.parseAllCallEdges(absPath);
|
|
@@ -3331,6 +3332,36 @@ var DependencyGraph = class {
|
|
|
3331
3332
|
getImporters(fileRel) {
|
|
3332
3333
|
return Array.from(this.reverseEdges.get(fileRel) ?? []);
|
|
3333
3334
|
}
|
|
3335
|
+
/**
|
|
3336
|
+
* Register each class method as its own symbol-index entry.
|
|
3337
|
+
*
|
|
3338
|
+
* TS/JS class methods are parsed as `methodRanges` on the class node,
|
|
3339
|
+
* not as standalone `method` nodes — so the `node.type === 'method'`
|
|
3340
|
+
* branch in the symbol-indexing loops never fired for them. That left
|
|
3341
|
+
* methods (e.g. DependencyGraph.getRootDir) unfindable by
|
|
3342
|
+
* `lookupSymbol`, which is why `ctx_get_call_graph {symbol: aMethod}`
|
|
3343
|
+
* returned "Symbol not found" even though the call-graph snapshot had
|
|
3344
|
+
* edges for it. Indexing methods here closes that gap.
|
|
3345
|
+
*
|
|
3346
|
+
* No-op for nodes without methodRanges (functions, imports, etc.).
|
|
3347
|
+
*/
|
|
3348
|
+
indexClassMethods(node, relPath) {
|
|
3349
|
+
if (!node.methodRanges) return;
|
|
3350
|
+
for (const m of node.methodRanges) {
|
|
3351
|
+
if (!m.name) continue;
|
|
3352
|
+
const existing = this.symbolIndex.get(m.name) ?? [];
|
|
3353
|
+
existing.push({
|
|
3354
|
+
filePath: relPath,
|
|
3355
|
+
type: "method",
|
|
3356
|
+
signature: `method ${m.name}`,
|
|
3357
|
+
// MethodRange only carries the signature line; use it as the
|
|
3358
|
+
// start and fall back to the enclosing class's end for the range.
|
|
3359
|
+
startLine: m.signatureLine,
|
|
3360
|
+
endLine: node.endLine ?? m.signatureLine
|
|
3361
|
+
});
|
|
3362
|
+
this.symbolIndex.set(m.name, existing);
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3334
3365
|
/**
|
|
3335
3366
|
* Look up a symbol by name. Returns all definitions across files.
|
|
3336
3367
|
*/
|
|
@@ -3518,6 +3549,7 @@ var DependencyGraph = class {
|
|
|
3518
3549
|
});
|
|
3519
3550
|
this.symbolIndex.set(node.name, existing);
|
|
3520
3551
|
}
|
|
3552
|
+
this.indexClassMethods(node, relPath);
|
|
3521
3553
|
}
|
|
3522
3554
|
if (TS_EXTENSIONS2.has(ext)) {
|
|
3523
3555
|
const callEdges = await this.parser.parseAllCallEdges(absPath);
|
|
@@ -12303,7 +12335,7 @@ function resolveTelemetryLevel() {
|
|
|
12303
12335
|
}
|
|
12304
12336
|
var TELEMETRY_LEVEL = resolveTelemetryLevel();
|
|
12305
12337
|
var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
|
|
12306
|
-
var CTXLOOM_VERSION2 = "1.7.
|
|
12338
|
+
var CTXLOOM_VERSION2 = "1.7.8".length > 0 ? "1.7.8" : "dev";
|
|
12307
12339
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
12308
12340
|
var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
|
|
12309
12341
|
var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VectorStore
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Z3NQHCWG.js";
|
|
4
4
|
import {
|
|
5
5
|
collectFiles,
|
|
6
6
|
generateEmbedding,
|
|
7
7
|
isIgnoredDir
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-R32CUQAL.js";
|
|
9
9
|
import {
|
|
10
10
|
diskSink,
|
|
11
11
|
readEvents
|
|
@@ -2705,7 +2705,7 @@ var CallGraphIndex = class _CallGraphIndex {
|
|
|
2705
2705
|
var TS_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".vue"]);
|
|
2706
2706
|
var PY_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".ipynb"]);
|
|
2707
2707
|
var AST_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs", ".java", ".cs", ".rb", ".kt", ".kts", ".swift", ".ipynb", ".php", ".dart"]);
|
|
2708
|
-
var CTXLOOM_VERSION = "1.7.
|
|
2708
|
+
var CTXLOOM_VERSION = "1.7.8".length > 0 ? "1.7.8" : "dev";
|
|
2709
2709
|
var SNAPSHOT_SCHEMA_VERSION = 2;
|
|
2710
2710
|
function compareCtxloomVersions(snapshotVer, currentVer) {
|
|
2711
2711
|
if (snapshotVer === currentVer) return "same";
|
|
@@ -2888,6 +2888,7 @@ var DependencyGraph = class {
|
|
|
2888
2888
|
});
|
|
2889
2889
|
this.symbolIndex.set(node.name, existing);
|
|
2890
2890
|
}
|
|
2891
|
+
this.indexClassMethods(node, relPath);
|
|
2891
2892
|
}
|
|
2892
2893
|
if (TS_EXTENSIONS2.has(ext)) {
|
|
2893
2894
|
const callEdges = await this.parser.parseAllCallEdges(absPath);
|
|
@@ -3107,6 +3108,36 @@ var DependencyGraph = class {
|
|
|
3107
3108
|
getImporters(fileRel) {
|
|
3108
3109
|
return Array.from(this.reverseEdges.get(fileRel) ?? []);
|
|
3109
3110
|
}
|
|
3111
|
+
/**
|
|
3112
|
+
* Register each class method as its own symbol-index entry.
|
|
3113
|
+
*
|
|
3114
|
+
* TS/JS class methods are parsed as `methodRanges` on the class node,
|
|
3115
|
+
* not as standalone `method` nodes — so the `node.type === 'method'`
|
|
3116
|
+
* branch in the symbol-indexing loops never fired for them. That left
|
|
3117
|
+
* methods (e.g. DependencyGraph.getRootDir) unfindable by
|
|
3118
|
+
* `lookupSymbol`, which is why `ctx_get_call_graph {symbol: aMethod}`
|
|
3119
|
+
* returned "Symbol not found" even though the call-graph snapshot had
|
|
3120
|
+
* edges for it. Indexing methods here closes that gap.
|
|
3121
|
+
*
|
|
3122
|
+
* No-op for nodes without methodRanges (functions, imports, etc.).
|
|
3123
|
+
*/
|
|
3124
|
+
indexClassMethods(node, relPath) {
|
|
3125
|
+
if (!node.methodRanges) return;
|
|
3126
|
+
for (const m of node.methodRanges) {
|
|
3127
|
+
if (!m.name) continue;
|
|
3128
|
+
const existing = this.symbolIndex.get(m.name) ?? [];
|
|
3129
|
+
existing.push({
|
|
3130
|
+
filePath: relPath,
|
|
3131
|
+
type: "method",
|
|
3132
|
+
signature: `method ${m.name}`,
|
|
3133
|
+
// MethodRange only carries the signature line; use it as the
|
|
3134
|
+
// start and fall back to the enclosing class's end for the range.
|
|
3135
|
+
startLine: m.signatureLine,
|
|
3136
|
+
endLine: node.endLine ?? m.signatureLine
|
|
3137
|
+
});
|
|
3138
|
+
this.symbolIndex.set(m.name, existing);
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3110
3141
|
/**
|
|
3111
3142
|
* Look up a symbol by name. Returns all definitions across files.
|
|
3112
3143
|
*/
|
|
@@ -3294,6 +3325,7 @@ var DependencyGraph = class {
|
|
|
3294
3325
|
});
|
|
3295
3326
|
this.symbolIndex.set(node.name, existing);
|
|
3296
3327
|
}
|
|
3328
|
+
this.indexClassMethods(node, relPath);
|
|
3297
3329
|
}
|
|
3298
3330
|
if (TS_EXTENSIONS2.has(ext)) {
|
|
3299
3331
|
const callEdges = await this.parser.parseAllCallEdges(absPath);
|
|
@@ -8835,7 +8867,7 @@ function registerFullTextSearchTool(registry, ctx) {
|
|
|
8835
8867
|
};
|
|
8836
8868
|
if (mode === "semantic") {
|
|
8837
8869
|
try {
|
|
8838
|
-
const { generateEmbedding: generateEmbedding2 } = await import("./embedder-
|
|
8870
|
+
const { generateEmbedding: generateEmbedding2 } = await import("./embedder-E2GDBGOH.js");
|
|
8839
8871
|
const store = await ctx.getStore(project_root);
|
|
8840
8872
|
const embedding = await generateEmbedding2(query);
|
|
8841
8873
|
const results = await store.search(embedding, limit);
|
|
@@ -8873,7 +8905,7 @@ function registerFullTextSearchTool(registry, ctx) {
|
|
|
8873
8905
|
let merged = keywordResults.slice(0, limit);
|
|
8874
8906
|
if (mode === "hybrid") {
|
|
8875
8907
|
try {
|
|
8876
|
-
const { generateEmbedding: generateEmbedding2 } = await import("./embedder-
|
|
8908
|
+
const { generateEmbedding: generateEmbedding2 } = await import("./embedder-E2GDBGOH.js");
|
|
8877
8909
|
const store = await ctx.getStore(project_root);
|
|
8878
8910
|
const embedding = await generateEmbedding2(query);
|
|
8879
8911
|
const vectorResults = await store.search(embedding, Math.ceil(limit / 2));
|
|
@@ -11110,7 +11142,7 @@ var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
|
|
|
11110
11142
|
function getTelemetryLevel() {
|
|
11111
11143
|
return TELEMETRY_LEVEL;
|
|
11112
11144
|
}
|
|
11113
|
-
var CTXLOOM_VERSION2 = "1.7.
|
|
11145
|
+
var CTXLOOM_VERSION2 = "1.7.8".length > 0 ? "1.7.8" : "dev";
|
|
11114
11146
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
11115
11147
|
var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
|
|
11116
11148
|
var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
|
|
@@ -12796,4 +12828,4 @@ export {
|
|
|
12796
12828
|
skillFilePath,
|
|
12797
12829
|
installHarness
|
|
12798
12830
|
};
|
|
12799
|
-
//# sourceMappingURL=chunk-
|
|
12831
|
+
//# sourceMappingURL=chunk-7WLMI4AD.js.map
|
|
@@ -253,7 +253,7 @@ var INDEX_SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
253
253
|
".ipynb"
|
|
254
254
|
]);
|
|
255
255
|
async function indexDirectory(rootDir, onProgress) {
|
|
256
|
-
const { VectorStore } = await import("./VectorStore-
|
|
256
|
+
const { VectorStore } = await import("./VectorStore-IHNQ3NOD.js");
|
|
257
257
|
const store = new VectorStore(path.join(rootDir, ".ctxloom", "vectors.lancedb"));
|
|
258
258
|
await store.init();
|
|
259
259
|
let indexed = 0;
|
|
@@ -366,4 +366,4 @@ export {
|
|
|
366
366
|
EMBEDDING_MODEL_ID,
|
|
367
367
|
getActiveEmbeddingModel
|
|
368
368
|
};
|
|
369
|
-
//# sourceMappingURL=chunk-
|
|
369
|
+
//# sourceMappingURL=chunk-R32CUQAL.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EMBEDDING_DIMENSION,
|
|
3
3
|
EMBEDDING_MODEL_ID
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-R32CUQAL.js";
|
|
5
5
|
import {
|
|
6
6
|
logger
|
|
7
7
|
} from "./chunk-TYDMSHV7.js";
|
|
@@ -26,6 +26,27 @@ var VectorStore = class {
|
|
|
26
26
|
upsertsSinceCompact = 0;
|
|
27
27
|
compactEvery;
|
|
28
28
|
cleanupOlderThanMs;
|
|
29
|
+
/**
|
|
30
|
+
* Hot-reload bookkeeping (v1.7.8). A live MCP server pins one open
|
|
31
|
+
* LanceDB table handle. When a terminal `ctxloom index` rewrites the
|
|
32
|
+
* store on the same path, the pinned handle keeps serving the OLD
|
|
33
|
+
* version — `ctx_search` returns stale/empty results until restart
|
|
34
|
+
* (the vector analogue of the graph hot-reload shipped in v1.7.5).
|
|
35
|
+
*
|
|
36
|
+
* Fix: before each read we cheaply stat the LanceDB `_versions`
|
|
37
|
+
* directory mtime. If it advanced past the last write WE made, an
|
|
38
|
+
* external writer touched the store → call `table.checkoutLatest()`
|
|
39
|
+
* to re-point the handle at the newest version. The mtime gate makes
|
|
40
|
+
* idle searches free and — critically — prevents the server's OWN
|
|
41
|
+
* continuous upserts (incremental file-watch indexing) from
|
|
42
|
+
* triggering a refresh storm: every own write updates
|
|
43
|
+
* `lastKnownMtime`, so the next read sees no advance.
|
|
44
|
+
*
|
|
45
|
+
* `externalRefreshCount` is exposed for tests + telemetry to prove
|
|
46
|
+
* own-writes don't cause redundant refreshes.
|
|
47
|
+
*/
|
|
48
|
+
lastKnownMtimeMs = 0;
|
|
49
|
+
externalRefreshCount = 0;
|
|
29
50
|
constructor(dbPath, options = {}) {
|
|
30
51
|
this.dbPath = dbPath ?? path.join(process.cwd(), ".ctxloom", "vectors.lancedb");
|
|
31
52
|
this.compactEvery = options.compactEvery ?? 200;
|
|
@@ -60,6 +81,87 @@ var VectorStore = class {
|
|
|
60
81
|
await this.table.delete("id = '__seed__'");
|
|
61
82
|
}
|
|
62
83
|
this.initialized = true;
|
|
84
|
+
this.markSynced();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Absolute path to the LanceDB table's `_versions` manifest directory.
|
|
88
|
+
* A new manifest file lands here on every committed write, so the
|
|
89
|
+
* directory's mtime is a cheap external-change signal.
|
|
90
|
+
*/
|
|
91
|
+
versionsDir() {
|
|
92
|
+
return path.join(this.dbPath, "code_embeddings.lance", "_versions");
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Newest mtime (ms) among the manifest FILES inside `_versions`, or 0
|
|
96
|
+
* if unreadable. We scan files, NOT the directory itself: LanceDB does
|
|
97
|
+
* NOT bump the `_versions` directory's own mtime when it adds a new
|
|
98
|
+
* manifest (verified empirically against @lancedb/lancedb 0.27.x —
|
|
99
|
+
* the dir mtime stays frozen at creation time), so statting the dir is
|
|
100
|
+
* a dead signal. Each committed version writes a fresh manifest file,
|
|
101
|
+
* so max-file-mtime advances monotonically per version and survives
|
|
102
|
+
* compaction (which writes new manifests with current timestamps).
|
|
103
|
+
*/
|
|
104
|
+
versionsMtimeMs() {
|
|
105
|
+
const dir = this.versionsDir();
|
|
106
|
+
let newest = 0;
|
|
107
|
+
try {
|
|
108
|
+
for (const name of fs.readdirSync(dir)) {
|
|
109
|
+
if (name.startsWith(".")) continue;
|
|
110
|
+
try {
|
|
111
|
+
const st = fs.statSync(path.join(dir, name));
|
|
112
|
+
if (st.isFile() && st.mtimeMs > newest) newest = st.mtimeMs;
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
return newest;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Mark the store as in-sync with the current on-disk state. Called
|
|
123
|
+
* after init and after every mutation WE perform (upsert, upsertBatch,
|
|
124
|
+
* remove, compact) so a subsequent refreshIfStale() does not mistake
|
|
125
|
+
* our own write for an external one.
|
|
126
|
+
*/
|
|
127
|
+
markSynced() {
|
|
128
|
+
this.lastKnownMtimeMs = this.versionsMtimeMs();
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Re-point the pinned table handle at the newest on-disk version IF an
|
|
132
|
+
* external writer (a terminal `ctxloom index` on the same path) has
|
|
133
|
+
* advanced the store since our last write. Cheap mtime gate first; the
|
|
134
|
+
* LanceDB `checkoutLatest()` call only happens on a real external
|
|
135
|
+
* change. Best-effort — a failed refresh keeps the current handle and
|
|
136
|
+
* logs a warning rather than breaking the read.
|
|
137
|
+
*/
|
|
138
|
+
async refreshIfStale() {
|
|
139
|
+
if (!this.table) return;
|
|
140
|
+
const diskMtime = this.versionsMtimeMs();
|
|
141
|
+
if (diskMtime === 0 || diskMtime <= this.lastKnownMtimeMs) return;
|
|
142
|
+
try {
|
|
143
|
+
const table = this.table;
|
|
144
|
+
if (typeof table.checkoutLatest === "function") {
|
|
145
|
+
await table.checkoutLatest();
|
|
146
|
+
}
|
|
147
|
+
this.lastKnownMtimeMs = this.versionsMtimeMs();
|
|
148
|
+
this.externalRefreshCount += 1;
|
|
149
|
+
logger.info("VectorStore: external write detected, handle refreshed", {
|
|
150
|
+
refreshCount: this.externalRefreshCount
|
|
151
|
+
});
|
|
152
|
+
} catch (err) {
|
|
153
|
+
logger.warn("VectorStore.refreshIfStale failed; keeping current handle", {
|
|
154
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Number of times the pinned handle was refreshed due to an EXTERNAL
|
|
160
|
+
* write. Exposed for tests (own-writes must not increment this) and
|
|
161
|
+
* for telemetry. @internal
|
|
162
|
+
*/
|
|
163
|
+
getExternalRefreshCount() {
|
|
164
|
+
return this.externalRefreshCount;
|
|
63
165
|
}
|
|
64
166
|
/**
|
|
65
167
|
* Compare the active embedding model against the marker file written
|
|
@@ -125,6 +227,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
125
227
|
this.db = null;
|
|
126
228
|
this.table = null;
|
|
127
229
|
this.initialized = false;
|
|
230
|
+
this.lastKnownMtimeMs = 0;
|
|
128
231
|
}
|
|
129
232
|
/**
|
|
130
233
|
* Insert or update a code record.
|
|
@@ -144,6 +247,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
144
247
|
content: content.slice(0, 512)
|
|
145
248
|
};
|
|
146
249
|
await this.table.add([record]);
|
|
250
|
+
this.markSynced();
|
|
147
251
|
this.upsertsSinceCompact++;
|
|
148
252
|
if (this.upsertsSinceCompact >= this.compactEvery) {
|
|
149
253
|
this.upsertsSinceCompact = 0;
|
|
@@ -186,6 +290,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
186
290
|
content: r.content.slice(0, 512)
|
|
187
291
|
}));
|
|
188
292
|
await this.table.add(rows);
|
|
293
|
+
this.markSynced();
|
|
189
294
|
this.upsertsSinceCompact += records.length;
|
|
190
295
|
if (this.upsertsSinceCompact >= this.compactEvery) {
|
|
191
296
|
this.upsertsSinceCompact = 0;
|
|
@@ -216,6 +321,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
216
321
|
bytesRemoved: result.prune?.bytesRemoved ?? 0
|
|
217
322
|
});
|
|
218
323
|
}
|
|
324
|
+
this.markSynced();
|
|
219
325
|
} catch (err) {
|
|
220
326
|
logger.warn("VectorStore.compact failed (non-fatal)", {
|
|
221
327
|
detail: err instanceof Error ? err.message : String(err)
|
|
@@ -230,6 +336,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
230
336
|
*/
|
|
231
337
|
async findEmbeddingByPath(filePath) {
|
|
232
338
|
if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
|
|
339
|
+
await this.refreshIfStale();
|
|
233
340
|
try {
|
|
234
341
|
const safe = sanitizeFilterPath(filePath);
|
|
235
342
|
const rows = await this.table.query().where(`filePath = '${safe}'`).limit(1).toArray();
|
|
@@ -256,6 +363,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
256
363
|
*/
|
|
257
364
|
async search(queryEmbedding, limit = 10) {
|
|
258
365
|
if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
|
|
366
|
+
await this.refreshIfStale();
|
|
259
367
|
try {
|
|
260
368
|
const results = await this.table.vectorSearch(queryEmbedding).limit(limit).toArray();
|
|
261
369
|
return results.filter((r) => r.id !== "__seed__").map((r) => ({
|
|
@@ -286,6 +394,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
286
394
|
const safe = sanitizeFilterPath(filePath);
|
|
287
395
|
try {
|
|
288
396
|
await this.table.delete(`filePath = '${safe}'`);
|
|
397
|
+
this.markSynced();
|
|
289
398
|
} catch (err) {
|
|
290
399
|
logger.error("Remove failed", { detail: err instanceof Error ? err.message : String(err) });
|
|
291
400
|
}
|
|
@@ -295,6 +404,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
295
404
|
*/
|
|
296
405
|
async count() {
|
|
297
406
|
if (!this.table) return 0;
|
|
407
|
+
await this.refreshIfStale();
|
|
298
408
|
try {
|
|
299
409
|
return await this.table.countRows();
|
|
300
410
|
} catch (err) {
|
|
@@ -307,4 +417,4 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
307
417
|
export {
|
|
308
418
|
VectorStore
|
|
309
419
|
};
|
|
310
|
-
//# sourceMappingURL=chunk-
|
|
420
|
+
//# sourceMappingURL=chunk-Z3NQHCWG.js.map
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
indexDirectory,
|
|
11
11
|
isIgnoredDir,
|
|
12
12
|
resolveEmbeddingModel
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-R32CUQAL.js";
|
|
14
14
|
import "./chunk-TYDMSHV7.js";
|
|
15
15
|
export {
|
|
16
16
|
EMBEDDING_DIMENSION,
|
|
@@ -25,4 +25,4 @@ export {
|
|
|
25
25
|
isIgnoredDir,
|
|
26
26
|
resolveEmbeddingModel
|
|
27
27
|
};
|
|
28
|
-
//# sourceMappingURL=embedder-
|
|
28
|
+
//# sourceMappingURL=embedder-E2GDBGOH.js.map
|
package/dist/index.js
CHANGED
|
@@ -47,19 +47,19 @@ import {
|
|
|
47
47
|
validateDefaultRoot,
|
|
48
48
|
wrapWithIndexingEnvelope,
|
|
49
49
|
writeCODEOWNERS
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-7WLMI4AD.js";
|
|
51
51
|
import {
|
|
52
52
|
addCtxloomToConfig,
|
|
53
53
|
detectInstalledClients
|
|
54
54
|
} from "./chunk-YHLMQVBV.js";
|
|
55
55
|
import {
|
|
56
56
|
VectorStore
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-Z3NQHCWG.js";
|
|
58
58
|
import {
|
|
59
59
|
collectFiles,
|
|
60
60
|
generateEmbedding,
|
|
61
61
|
indexDirectory
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-R32CUQAL.js";
|
|
63
63
|
import "./chunk-5I6CJITG.js";
|
|
64
64
|
import {
|
|
65
65
|
logger
|
|
@@ -1068,7 +1068,7 @@ try {
|
|
|
1068
1068
|
} catch {
|
|
1069
1069
|
}
|
|
1070
1070
|
var args = process.argv.slice(2);
|
|
1071
|
-
var ctxloomVersion = "1.7.
|
|
1071
|
+
var ctxloomVersion = "1.7.8".length > 0 ? "1.7.8" : "dev";
|
|
1072
1072
|
if (args.includes("--version") || args.includes("-v")) {
|
|
1073
1073
|
process.stdout.write(`ctxloom ${ctxloomVersion}
|
|
1074
1074
|
`);
|
|
@@ -1163,7 +1163,7 @@ async function checkLicense() {
|
|
|
1163
1163
|
if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
|
|
1164
1164
|
const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
|
|
1165
1165
|
if (ciKey) {
|
|
1166
|
-
const { ApiClient } = await import("./src-
|
|
1166
|
+
const { ApiClient } = await import("./src-C5NS2JAW.js");
|
|
1167
1167
|
const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
|
|
1168
1168
|
try {
|
|
1169
1169
|
const result = await client.validate(ciKey, "ci-ephemeral");
|
|
@@ -1556,7 +1556,7 @@ async function main() {
|
|
|
1556
1556
|
}
|
|
1557
1557
|
if (!skipHarness) {
|
|
1558
1558
|
process.stdout.write("\n");
|
|
1559
|
-
const { installHarness } = await import("./src-
|
|
1559
|
+
const { installHarness } = await import("./src-C5NS2JAW.js");
|
|
1560
1560
|
const h = installHarness({ cwd: initRoot, dryRun, force, extraHosts });
|
|
1561
1561
|
const harnessFiles = [
|
|
1562
1562
|
h.claudeMd,
|
|
@@ -1619,7 +1619,7 @@ async function main() {
|
|
|
1619
1619
|
process.exit(1);
|
|
1620
1620
|
}
|
|
1621
1621
|
if (alias !== void 0) {
|
|
1622
|
-
const { validateAlias } = await import("./src-
|
|
1622
|
+
const { validateAlias } = await import("./src-C5NS2JAW.js");
|
|
1623
1623
|
const v = validateAlias(alias);
|
|
1624
1624
|
if (!v.ok) {
|
|
1625
1625
|
console.error(`[ctxloom] Invalid alias: ${v.reason}`);
|
|
@@ -1978,7 +1978,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
1978
1978
|
process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
|
|
1979
1979
|
process.exit(2);
|
|
1980
1980
|
}
|
|
1981
|
-
const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-
|
|
1981
|
+
const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-C5NS2JAW.js");
|
|
1982
1982
|
let config;
|
|
1983
1983
|
try {
|
|
1984
1984
|
config = await loadRulesConfig(root);
|
|
@@ -2002,7 +2002,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
2002
2002
|
}
|
|
2003
2003
|
let graph;
|
|
2004
2004
|
if (useSnapshot) {
|
|
2005
|
-
const { DependencyGraph: DG } = await import("./src-
|
|
2005
|
+
const { DependencyGraph: DG } = await import("./src-C5NS2JAW.js");
|
|
2006
2006
|
graph = new DG();
|
|
2007
2007
|
const loaded = await graph.loadSnapshotOnly(root);
|
|
2008
2008
|
if (!loaded) {
|
|
@@ -2011,7 +2011,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
2011
2011
|
}
|
|
2012
2012
|
} else {
|
|
2013
2013
|
process.stderr.write("[ctxloom] Building dependency graph...\n");
|
|
2014
|
-
const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-
|
|
2014
|
+
const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-C5NS2JAW.js");
|
|
2015
2015
|
let parser;
|
|
2016
2016
|
try {
|
|
2017
2017
|
parser = new ASTParser2();
|
|
@@ -132,10 +132,10 @@ import {
|
|
|
132
132
|
wrapBlock,
|
|
133
133
|
wrapWithIndexingEnvelope,
|
|
134
134
|
writeCODEOWNERS
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-7WLMI4AD.js";
|
|
136
136
|
import {
|
|
137
137
|
VectorStore
|
|
138
|
-
} from "./chunk-
|
|
138
|
+
} from "./chunk-Z3NQHCWG.js";
|
|
139
139
|
import {
|
|
140
140
|
EMBEDDING_DIMENSION,
|
|
141
141
|
INDEXER_IGNORED_DIRS,
|
|
@@ -143,7 +143,7 @@ import {
|
|
|
143
143
|
generateEmbedding,
|
|
144
144
|
indexDirectory,
|
|
145
145
|
isIgnoredDir
|
|
146
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-R32CUQAL.js";
|
|
147
147
|
import {
|
|
148
148
|
filenameForDate,
|
|
149
149
|
readEvents,
|
|
@@ -304,4 +304,4 @@ export {
|
|
|
304
304
|
wrapWithIndexingEnvelope,
|
|
305
305
|
writeCODEOWNERS
|
|
306
306
|
};
|
|
307
|
-
//# sourceMappingURL=src-
|
|
307
|
+
//# sourceMappingURL=src-C5NS2JAW.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VectorStore
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-Z3NQHCWG.js";
|
|
4
4
|
import {
|
|
5
5
|
generateEmbedding
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-R32CUQAL.js";
|
|
7
7
|
import "../chunk-TYDMSHV7.js";
|
|
8
8
|
|
|
9
9
|
// packages/core/src/workers/indexerWorker.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctxloom-pro",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.8",
|
|
4
4
|
"description": "ctxloom — The Universal Code Context Engine. A local-first MCP server providing intelligent code context via hybrid Vector + AST + Graph search with Skeletonization (92% token reduction).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|