ctxloom-pro 1.7.3 → 1.7.5
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 +202 -53
- package/dist/VectorStore-5ALWL6XF.js +9 -0
- package/dist/{chunk-KQ5CQLIA.js → chunk-2YELCPTS.js} +144 -10
- package/dist/{chunk-6FGTNOCP.js → chunk-JZOJC3S7.js} +27 -55
- package/dist/{chunk-7S2ELKNU.js → chunk-XQEQLXY5.js} +2 -2
- package/dist/{embedder-2JWDJUE2.js → embedder-4MM7D3UE.js} +4 -2
- package/dist/index.js +11 -10
- package/dist/{src-Y4TTG5HV.js → src-NCWA7NVW.js} +9 -5
- package/dist/workers/indexerWorker.js +2 -2
- package/package.json +1 -1
- package/dist/VectorStore-WDL3H7QT.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.5`) 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.5
|
|
387
387
|
- run: ctxloom index
|
|
388
388
|
- run: ctxloom rules check --json
|
|
389
389
|
```
|
|
@@ -101,71 +101,28 @@ function resolveEmbeddingModel(env = process.env) {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
function collectFiles(dir, results = []) {
|
|
104
|
-
const IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
105
|
-
// Build artifacts + dependency caches
|
|
106
|
-
"node_modules",
|
|
107
|
-
"dist",
|
|
108
|
-
"build",
|
|
109
|
-
"out",
|
|
110
|
-
"target",
|
|
111
|
-
"coverage",
|
|
112
|
-
".cache",
|
|
113
|
-
".turbo",
|
|
114
|
-
".next",
|
|
115
|
-
".nuxt",
|
|
116
|
-
// Version control + ctxloom state
|
|
117
|
-
".git",
|
|
118
|
-
".ctxloom",
|
|
119
|
-
// Other tools' working state (often contains duplicated source)
|
|
120
|
-
".claude",
|
|
121
|
-
".code-review-graph",
|
|
122
|
-
".vscode-test"
|
|
123
|
-
]);
|
|
124
|
-
const SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
125
|
-
".ts",
|
|
126
|
-
".tsx",
|
|
127
|
-
".js",
|
|
128
|
-
".jsx",
|
|
129
|
-
".mjs",
|
|
130
|
-
".vue",
|
|
131
|
-
".py",
|
|
132
|
-
".rs",
|
|
133
|
-
".go",
|
|
134
|
-
".java",
|
|
135
|
-
".cs",
|
|
136
|
-
".rb",
|
|
137
|
-
".kt",
|
|
138
|
-
".kts",
|
|
139
|
-
".swift",
|
|
140
|
-
".php",
|
|
141
|
-
".dart",
|
|
142
|
-
".c",
|
|
143
|
-
".cpp",
|
|
144
|
-
".h",
|
|
145
|
-
".md",
|
|
146
|
-
".json",
|
|
147
|
-
".yaml",
|
|
148
|
-
".yml",
|
|
149
|
-
".toml",
|
|
150
|
-
".ipynb"
|
|
151
|
-
]);
|
|
152
104
|
const entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
153
105
|
for (const entry of entries) {
|
|
154
106
|
const fullPath = path3.join(dir, entry.name);
|
|
155
107
|
if (entry.isDirectory()) {
|
|
156
|
-
if (!
|
|
108
|
+
if (!isIgnoredDir(entry.name)) {
|
|
157
109
|
collectFiles(fullPath, results);
|
|
158
110
|
}
|
|
159
111
|
} else if (entry.isFile()) {
|
|
160
112
|
const ext = path3.extname(entry.name);
|
|
161
|
-
if (
|
|
113
|
+
if (INDEX_SUPPORTED_EXTENSIONS.has(ext)) {
|
|
162
114
|
results.push(fullPath);
|
|
163
115
|
}
|
|
164
116
|
}
|
|
165
117
|
}
|
|
166
118
|
return results;
|
|
167
119
|
}
|
|
168
|
-
|
|
120
|
+
function isIgnoredDir(name) {
|
|
121
|
+
if (INDEXER_IGNORED_DIRS.has(name)) return true;
|
|
122
|
+
if (name.endsWith(".egg-info") || name.endsWith(".dist-info")) return true;
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
var MODEL_REGISTRY, ACTIVE_MODEL, EMBEDDING_DIMENSION, MODEL_ID, MIN_MODEL_BYTES, INDEXER_IGNORED_DIRS, INDEX_SUPPORTED_EXTENSIONS;
|
|
169
126
|
var init_embedder = __esm({
|
|
170
127
|
"../../packages/core/src/indexer/embedder.ts"() {
|
|
171
128
|
"use strict";
|
|
@@ -196,6 +153,69 @@ var init_embedder = __esm({
|
|
|
196
153
|
EMBEDDING_DIMENSION = ACTIVE_MODEL.dim;
|
|
197
154
|
MODEL_ID = ACTIVE_MODEL.hfId;
|
|
198
155
|
MIN_MODEL_BYTES = ACTIVE_MODEL.minBytes;
|
|
156
|
+
INDEXER_IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
157
|
+
// Build artifacts + dependency caches (JS/TS, Rust, Java)
|
|
158
|
+
"node_modules",
|
|
159
|
+
"dist",
|
|
160
|
+
"build",
|
|
161
|
+
"out",
|
|
162
|
+
"target",
|
|
163
|
+
"coverage",
|
|
164
|
+
".cache",
|
|
165
|
+
".turbo",
|
|
166
|
+
".next",
|
|
167
|
+
".nuxt",
|
|
168
|
+
// Python virtualenvs + caches. Real-world repro: EasyMoney (a 63-
|
|
169
|
+
// source-file FastAPI project) had a `.venv/` with 8,192 installed-
|
|
170
|
+
// package files. Pre-fix, `ctxloom index` reported 8,120 files /
|
|
171
|
+
// 14,138 edges instead of the expected 63 / 97, because none of the
|
|
172
|
+
// standard Python virtualenv/cache directory names were in this set.
|
|
173
|
+
// The `__pycache__` + `.pytest_cache` + `.ruff_cache` + `.mypy_cache`
|
|
174
|
+
// additions catch the bulk of Python noise on top of the venv.
|
|
175
|
+
".venv",
|
|
176
|
+
"venv",
|
|
177
|
+
"env",
|
|
178
|
+
"__pycache__",
|
|
179
|
+
".pytest_cache",
|
|
180
|
+
".ruff_cache",
|
|
181
|
+
".mypy_cache",
|
|
182
|
+
".tox",
|
|
183
|
+
// Version control + ctxloom state
|
|
184
|
+
".git",
|
|
185
|
+
".ctxloom",
|
|
186
|
+
// Other tools' working state (often contains duplicated source)
|
|
187
|
+
".claude",
|
|
188
|
+
".code-review-graph",
|
|
189
|
+
".vscode-test"
|
|
190
|
+
]);
|
|
191
|
+
INDEX_SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
192
|
+
".ts",
|
|
193
|
+
".tsx",
|
|
194
|
+
".js",
|
|
195
|
+
".jsx",
|
|
196
|
+
".mjs",
|
|
197
|
+
".vue",
|
|
198
|
+
".py",
|
|
199
|
+
".rs",
|
|
200
|
+
".go",
|
|
201
|
+
".java",
|
|
202
|
+
".cs",
|
|
203
|
+
".rb",
|
|
204
|
+
".kt",
|
|
205
|
+
".kts",
|
|
206
|
+
".swift",
|
|
207
|
+
".php",
|
|
208
|
+
".dart",
|
|
209
|
+
".c",
|
|
210
|
+
".cpp",
|
|
211
|
+
".h",
|
|
212
|
+
".md",
|
|
213
|
+
".json",
|
|
214
|
+
".yaml",
|
|
215
|
+
".yml",
|
|
216
|
+
".toml",
|
|
217
|
+
".ipynb"
|
|
218
|
+
]);
|
|
199
219
|
}
|
|
200
220
|
});
|
|
201
221
|
|
|
@@ -2909,7 +2929,7 @@ var CallGraphIndex = class _CallGraphIndex {
|
|
|
2909
2929
|
var TS_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".vue"]);
|
|
2910
2930
|
var PY_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".ipynb"]);
|
|
2911
2931
|
var AST_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs", ".java", ".cs", ".rb", ".kt", ".kts", ".swift", ".ipynb", ".php", ".dart"]);
|
|
2912
|
-
var CTXLOOM_VERSION = "1.7.
|
|
2932
|
+
var CTXLOOM_VERSION = "1.7.5".length > 0 ? "1.7.5" : "dev";
|
|
2913
2933
|
var SNAPSHOT_SCHEMA_VERSION = 2;
|
|
2914
2934
|
function compareCtxloomVersions(snapshotVer, currentVer) {
|
|
2915
2935
|
if (snapshotVer === currentVer) return "same";
|
|
@@ -2966,6 +2986,28 @@ var DependencyGraph = class {
|
|
|
2966
2986
|
rootDir = "";
|
|
2967
2987
|
snapshotDir = "";
|
|
2968
2988
|
tsPathsResolver = null;
|
|
2989
|
+
/**
|
|
2990
|
+
* fs.watch handle on `.ctxloom/graph-snapshot.json`. When the file is
|
|
2991
|
+
* rewritten externally (e.g. the user runs `ctxloom index` from a
|
|
2992
|
+
* terminal while an MCP server is live), this watcher triggers an
|
|
2993
|
+
* in-memory rehydrate so subsequent tool calls reflect the new graph
|
|
2994
|
+
* without needing the user to restart their MCP client.
|
|
2995
|
+
*
|
|
2996
|
+
* Real repro that motivated this (v1.7.5): EasyMoney user ran
|
|
2997
|
+
* `rm -rf .ctxloom && ctxloom index` from the terminal but the
|
|
2998
|
+
* Claude Desktop MCP server kept serving the pre-wipe in-memory
|
|
2999
|
+
* graph (`Files: 2`) because there was no mechanism to detect the
|
|
3000
|
+
* fresh snapshot on disk. Confusing diagnostic loop.
|
|
3001
|
+
*/
|
|
3002
|
+
snapshotWatcher = null;
|
|
3003
|
+
/** Debounce timer for snapshot-change events. */
|
|
3004
|
+
snapshotReloadTimer = null;
|
|
3005
|
+
/**
|
|
3006
|
+
* Tracks the snapshot mtime we last loaded from disk so the watcher
|
|
3007
|
+
* can suppress its own-write echo. saveSnapshot() updates this just
|
|
3008
|
+
* before writing; the watcher ignores any change whose mtime <= this.
|
|
3009
|
+
*/
|
|
3010
|
+
lastLoadedSnapshotMtimeMs = 0;
|
|
2969
3011
|
/**
|
|
2970
3012
|
* Build the graph from all supported files in rootDir using AST parsing.
|
|
2971
3013
|
*/
|
|
@@ -3165,6 +3207,105 @@ var DependencyGraph = class {
|
|
|
3165
3207
|
this.snapshotDir = path7.join(rootDir, ".ctxloom");
|
|
3166
3208
|
return this.loadSnapshot();
|
|
3167
3209
|
}
|
|
3210
|
+
/**
|
|
3211
|
+
* Start watching `.ctxloom/graph-snapshot.json` for external rewrites.
|
|
3212
|
+
* When the user runs `ctxloom index` (or any other tool) from a
|
|
3213
|
+
* terminal against the same project root, the watcher detects the
|
|
3214
|
+
* new mtime, reloads the snapshot, and atomically swaps the
|
|
3215
|
+
* in-memory graph — so subsequent MCP tool calls see the fresh
|
|
3216
|
+
* graph without requiring an MCP client restart.
|
|
3217
|
+
*
|
|
3218
|
+
* Own writes (via saveSnapshot) update lastLoadedSnapshotMtimeMs
|
|
3219
|
+
* BEFORE the rename completes, so the watcher's own-write echo is
|
|
3220
|
+
* filtered out by the mtime check.
|
|
3221
|
+
*
|
|
3222
|
+
* Debounced 200 ms — matches the FileWatcher cadence and absorbs
|
|
3223
|
+
* the burst of fs.watch events some platforms emit for a single
|
|
3224
|
+
* write (Linux can fire `rename` + `change`, macOS sometimes
|
|
3225
|
+
* fires multiple `change` for atomic rename).
|
|
3226
|
+
*
|
|
3227
|
+
* Idempotent: calling twice is harmless (re-uses the existing
|
|
3228
|
+
* watcher). Call stopSnapshotWatcher() before disposing the graph
|
|
3229
|
+
* to release the FD.
|
|
3230
|
+
*/
|
|
3231
|
+
startSnapshotWatcher(debounceMs = 200) {
|
|
3232
|
+
if (this.snapshotWatcher) return;
|
|
3233
|
+
if (!this.snapshotDir) {
|
|
3234
|
+
logger.warn("startSnapshotWatcher: no snapshotDir set, call buildFromDirectory first");
|
|
3235
|
+
return;
|
|
3236
|
+
}
|
|
3237
|
+
const snapshotPath = this.getSnapshotPath();
|
|
3238
|
+
if (!fs7.existsSync(snapshotPath)) {
|
|
3239
|
+
logger.warn("startSnapshotWatcher: snapshot file does not exist yet", { path: snapshotPath });
|
|
3240
|
+
return;
|
|
3241
|
+
}
|
|
3242
|
+
try {
|
|
3243
|
+
this.snapshotWatcher = fs7.watch(snapshotPath, { persistent: false }, (eventType) => {
|
|
3244
|
+
if (this.snapshotReloadTimer) clearTimeout(this.snapshotReloadTimer);
|
|
3245
|
+
this.snapshotReloadTimer = setTimeout(() => {
|
|
3246
|
+
this.snapshotReloadTimer = null;
|
|
3247
|
+
void this.maybeReloadSnapshot(eventType);
|
|
3248
|
+
}, debounceMs);
|
|
3249
|
+
});
|
|
3250
|
+
this.snapshotWatcher.on("error", (err) => {
|
|
3251
|
+
logger.warn("snapshot watcher error", { detail: err instanceof Error ? err.message : String(err) });
|
|
3252
|
+
});
|
|
3253
|
+
logger.info("Graph snapshot hot-reload watcher started", { path: snapshotPath });
|
|
3254
|
+
} catch (err) {
|
|
3255
|
+
logger.warn("startSnapshotWatcher: failed to attach fs.watch", {
|
|
3256
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
3257
|
+
});
|
|
3258
|
+
this.snapshotWatcher = null;
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
/**
|
|
3262
|
+
* Stop the snapshot watcher and clear any pending debounce timer.
|
|
3263
|
+
* Call before disposing the graph to release the FD held by fs.watch.
|
|
3264
|
+
* Idempotent.
|
|
3265
|
+
*/
|
|
3266
|
+
stopSnapshotWatcher() {
|
|
3267
|
+
if (this.snapshotReloadTimer) {
|
|
3268
|
+
clearTimeout(this.snapshotReloadTimer);
|
|
3269
|
+
this.snapshotReloadTimer = null;
|
|
3270
|
+
}
|
|
3271
|
+
if (this.snapshotWatcher) {
|
|
3272
|
+
try {
|
|
3273
|
+
this.snapshotWatcher.close();
|
|
3274
|
+
} catch {
|
|
3275
|
+
}
|
|
3276
|
+
this.snapshotWatcher = null;
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
/**
|
|
3280
|
+
* Internal: called from the debounced watcher. Compares on-disk
|
|
3281
|
+
* mtime against `lastLoadedSnapshotMtimeMs` to filter own-write
|
|
3282
|
+
* echoes, then re-hydrates the in-memory maps from disk via
|
|
3283
|
+
* loadSnapshot(). Atomic from the perspective of MCP tool calls
|
|
3284
|
+
* because Node's event loop ensures loadSnapshot's map assignments
|
|
3285
|
+
* happen in a single tick (no other code interleaves).
|
|
3286
|
+
*/
|
|
3287
|
+
async maybeReloadSnapshot(eventType) {
|
|
3288
|
+
const snapshotPath = this.getSnapshotPath();
|
|
3289
|
+
let currentMtime = 0;
|
|
3290
|
+
try {
|
|
3291
|
+
currentMtime = fs7.statSync(snapshotPath).mtimeMs;
|
|
3292
|
+
} catch {
|
|
3293
|
+
return;
|
|
3294
|
+
}
|
|
3295
|
+
if (currentMtime <= this.lastLoadedSnapshotMtimeMs) {
|
|
3296
|
+
return;
|
|
3297
|
+
}
|
|
3298
|
+
const ok = await this.loadSnapshot();
|
|
3299
|
+
if (ok) {
|
|
3300
|
+
logger.info("Graph snapshot hot-reloaded", {
|
|
3301
|
+
event: eventType,
|
|
3302
|
+
files: this.forwardEdges.size,
|
|
3303
|
+
edges: this.edgeCount()
|
|
3304
|
+
});
|
|
3305
|
+
} else {
|
|
3306
|
+
logger.warn("Graph snapshot hot-reload skipped (snapshot invalid or version-stale)");
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3168
3309
|
/**
|
|
3169
3310
|
* Get files that the given file directly imports.
|
|
3170
3311
|
*/
|
|
@@ -3439,6 +3580,10 @@ var DependencyGraph = class {
|
|
|
3439
3580
|
const tmpPath = `${snapshotPath}.${process.pid}.tmp`;
|
|
3440
3581
|
fs7.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
|
|
3441
3582
|
fs7.renameSync(tmpPath, snapshotPath);
|
|
3583
|
+
try {
|
|
3584
|
+
this.lastLoadedSnapshotMtimeMs = fs7.statSync(snapshotPath).mtimeMs;
|
|
3585
|
+
} catch {
|
|
3586
|
+
}
|
|
3442
3587
|
const callData = this.callGraphIndex.toJSON();
|
|
3443
3588
|
const callPath = path7.join(this.snapshotDir, "call-graph-snapshot.json");
|
|
3444
3589
|
const callTmp = `${callPath}.${process.pid}.tmp`;
|
|
@@ -3516,6 +3661,10 @@ var DependencyGraph = class {
|
|
|
3516
3661
|
this.callGraphIndex = new CallGraphIndex();
|
|
3517
3662
|
}
|
|
3518
3663
|
}
|
|
3664
|
+
try {
|
|
3665
|
+
this.lastLoadedSnapshotMtimeMs = fs7.statSync(snapshotPath).mtimeMs;
|
|
3666
|
+
} catch {
|
|
3667
|
+
}
|
|
3519
3668
|
return true;
|
|
3520
3669
|
} catch (err) {
|
|
3521
3670
|
logger.error("Failed to load graph snapshot, will rebuild", { detail: err instanceof Error ? err.message : String(err) });
|
|
@@ -12141,7 +12290,7 @@ function resolveTelemetryLevel() {
|
|
|
12141
12290
|
}
|
|
12142
12291
|
var TELEMETRY_LEVEL = resolveTelemetryLevel();
|
|
12143
12292
|
var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
|
|
12144
|
-
var CTXLOOM_VERSION2 = "1.7.
|
|
12293
|
+
var CTXLOOM_VERSION2 = "1.7.5".length > 0 ? "1.7.5" : "dev";
|
|
12145
12294
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
12146
12295
|
var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
|
|
12147
12296
|
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-XQEQLXY5.js";
|
|
4
4
|
import {
|
|
5
|
-
INDEXER_IGNORED_DIRS,
|
|
6
5
|
collectFiles,
|
|
7
|
-
generateEmbedding
|
|
8
|
-
|
|
6
|
+
generateEmbedding,
|
|
7
|
+
isIgnoredDir
|
|
8
|
+
} from "./chunk-JZOJC3S7.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.5".length > 0 ? "1.7.5" : "dev";
|
|
2709
2709
|
var SNAPSHOT_SCHEMA_VERSION = 2;
|
|
2710
2710
|
function compareCtxloomVersions(snapshotVer, currentVer) {
|
|
2711
2711
|
if (snapshotVer === currentVer) return "same";
|
|
@@ -2762,6 +2762,28 @@ var DependencyGraph = class {
|
|
|
2762
2762
|
rootDir = "";
|
|
2763
2763
|
snapshotDir = "";
|
|
2764
2764
|
tsPathsResolver = null;
|
|
2765
|
+
/**
|
|
2766
|
+
* fs.watch handle on `.ctxloom/graph-snapshot.json`. When the file is
|
|
2767
|
+
* rewritten externally (e.g. the user runs `ctxloom index` from a
|
|
2768
|
+
* terminal while an MCP server is live), this watcher triggers an
|
|
2769
|
+
* in-memory rehydrate so subsequent tool calls reflect the new graph
|
|
2770
|
+
* without needing the user to restart their MCP client.
|
|
2771
|
+
*
|
|
2772
|
+
* Real repro that motivated this (v1.7.5): EasyMoney user ran
|
|
2773
|
+
* `rm -rf .ctxloom && ctxloom index` from the terminal but the
|
|
2774
|
+
* Claude Desktop MCP server kept serving the pre-wipe in-memory
|
|
2775
|
+
* graph (`Files: 2`) because there was no mechanism to detect the
|
|
2776
|
+
* fresh snapshot on disk. Confusing diagnostic loop.
|
|
2777
|
+
*/
|
|
2778
|
+
snapshotWatcher = null;
|
|
2779
|
+
/** Debounce timer for snapshot-change events. */
|
|
2780
|
+
snapshotReloadTimer = null;
|
|
2781
|
+
/**
|
|
2782
|
+
* Tracks the snapshot mtime we last loaded from disk so the watcher
|
|
2783
|
+
* can suppress its own-write echo. saveSnapshot() updates this just
|
|
2784
|
+
* before writing; the watcher ignores any change whose mtime <= this.
|
|
2785
|
+
*/
|
|
2786
|
+
lastLoadedSnapshotMtimeMs = 0;
|
|
2765
2787
|
/**
|
|
2766
2788
|
* Build the graph from all supported files in rootDir using AST parsing.
|
|
2767
2789
|
*/
|
|
@@ -2961,6 +2983,105 @@ var DependencyGraph = class {
|
|
|
2961
2983
|
this.snapshotDir = path6.join(rootDir, ".ctxloom");
|
|
2962
2984
|
return this.loadSnapshot();
|
|
2963
2985
|
}
|
|
2986
|
+
/**
|
|
2987
|
+
* Start watching `.ctxloom/graph-snapshot.json` for external rewrites.
|
|
2988
|
+
* When the user runs `ctxloom index` (or any other tool) from a
|
|
2989
|
+
* terminal against the same project root, the watcher detects the
|
|
2990
|
+
* new mtime, reloads the snapshot, and atomically swaps the
|
|
2991
|
+
* in-memory graph — so subsequent MCP tool calls see the fresh
|
|
2992
|
+
* graph without requiring an MCP client restart.
|
|
2993
|
+
*
|
|
2994
|
+
* Own writes (via saveSnapshot) update lastLoadedSnapshotMtimeMs
|
|
2995
|
+
* BEFORE the rename completes, so the watcher's own-write echo is
|
|
2996
|
+
* filtered out by the mtime check.
|
|
2997
|
+
*
|
|
2998
|
+
* Debounced 200 ms — matches the FileWatcher cadence and absorbs
|
|
2999
|
+
* the burst of fs.watch events some platforms emit for a single
|
|
3000
|
+
* write (Linux can fire `rename` + `change`, macOS sometimes
|
|
3001
|
+
* fires multiple `change` for atomic rename).
|
|
3002
|
+
*
|
|
3003
|
+
* Idempotent: calling twice is harmless (re-uses the existing
|
|
3004
|
+
* watcher). Call stopSnapshotWatcher() before disposing the graph
|
|
3005
|
+
* to release the FD.
|
|
3006
|
+
*/
|
|
3007
|
+
startSnapshotWatcher(debounceMs = 200) {
|
|
3008
|
+
if (this.snapshotWatcher) return;
|
|
3009
|
+
if (!this.snapshotDir) {
|
|
3010
|
+
logger.warn("startSnapshotWatcher: no snapshotDir set, call buildFromDirectory first");
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
3013
|
+
const snapshotPath = this.getSnapshotPath();
|
|
3014
|
+
if (!fs6.existsSync(snapshotPath)) {
|
|
3015
|
+
logger.warn("startSnapshotWatcher: snapshot file does not exist yet", { path: snapshotPath });
|
|
3016
|
+
return;
|
|
3017
|
+
}
|
|
3018
|
+
try {
|
|
3019
|
+
this.snapshotWatcher = fs6.watch(snapshotPath, { persistent: false }, (eventType) => {
|
|
3020
|
+
if (this.snapshotReloadTimer) clearTimeout(this.snapshotReloadTimer);
|
|
3021
|
+
this.snapshotReloadTimer = setTimeout(() => {
|
|
3022
|
+
this.snapshotReloadTimer = null;
|
|
3023
|
+
void this.maybeReloadSnapshot(eventType);
|
|
3024
|
+
}, debounceMs);
|
|
3025
|
+
});
|
|
3026
|
+
this.snapshotWatcher.on("error", (err) => {
|
|
3027
|
+
logger.warn("snapshot watcher error", { detail: err instanceof Error ? err.message : String(err) });
|
|
3028
|
+
});
|
|
3029
|
+
logger.info("Graph snapshot hot-reload watcher started", { path: snapshotPath });
|
|
3030
|
+
} catch (err) {
|
|
3031
|
+
logger.warn("startSnapshotWatcher: failed to attach fs.watch", {
|
|
3032
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
3033
|
+
});
|
|
3034
|
+
this.snapshotWatcher = null;
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
/**
|
|
3038
|
+
* Stop the snapshot watcher and clear any pending debounce timer.
|
|
3039
|
+
* Call before disposing the graph to release the FD held by fs.watch.
|
|
3040
|
+
* Idempotent.
|
|
3041
|
+
*/
|
|
3042
|
+
stopSnapshotWatcher() {
|
|
3043
|
+
if (this.snapshotReloadTimer) {
|
|
3044
|
+
clearTimeout(this.snapshotReloadTimer);
|
|
3045
|
+
this.snapshotReloadTimer = null;
|
|
3046
|
+
}
|
|
3047
|
+
if (this.snapshotWatcher) {
|
|
3048
|
+
try {
|
|
3049
|
+
this.snapshotWatcher.close();
|
|
3050
|
+
} catch {
|
|
3051
|
+
}
|
|
3052
|
+
this.snapshotWatcher = null;
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
/**
|
|
3056
|
+
* Internal: called from the debounced watcher. Compares on-disk
|
|
3057
|
+
* mtime against `lastLoadedSnapshotMtimeMs` to filter own-write
|
|
3058
|
+
* echoes, then re-hydrates the in-memory maps from disk via
|
|
3059
|
+
* loadSnapshot(). Atomic from the perspective of MCP tool calls
|
|
3060
|
+
* because Node's event loop ensures loadSnapshot's map assignments
|
|
3061
|
+
* happen in a single tick (no other code interleaves).
|
|
3062
|
+
*/
|
|
3063
|
+
async maybeReloadSnapshot(eventType) {
|
|
3064
|
+
const snapshotPath = this.getSnapshotPath();
|
|
3065
|
+
let currentMtime = 0;
|
|
3066
|
+
try {
|
|
3067
|
+
currentMtime = fs6.statSync(snapshotPath).mtimeMs;
|
|
3068
|
+
} catch {
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3071
|
+
if (currentMtime <= this.lastLoadedSnapshotMtimeMs) {
|
|
3072
|
+
return;
|
|
3073
|
+
}
|
|
3074
|
+
const ok = await this.loadSnapshot();
|
|
3075
|
+
if (ok) {
|
|
3076
|
+
logger.info("Graph snapshot hot-reloaded", {
|
|
3077
|
+
event: eventType,
|
|
3078
|
+
files: this.forwardEdges.size,
|
|
3079
|
+
edges: this.edgeCount()
|
|
3080
|
+
});
|
|
3081
|
+
} else {
|
|
3082
|
+
logger.warn("Graph snapshot hot-reload skipped (snapshot invalid or version-stale)");
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
2964
3085
|
/**
|
|
2965
3086
|
* Get files that the given file directly imports.
|
|
2966
3087
|
*/
|
|
@@ -3235,6 +3356,10 @@ var DependencyGraph = class {
|
|
|
3235
3356
|
const tmpPath = `${snapshotPath}.${process.pid}.tmp`;
|
|
3236
3357
|
fs6.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
|
|
3237
3358
|
fs6.renameSync(tmpPath, snapshotPath);
|
|
3359
|
+
try {
|
|
3360
|
+
this.lastLoadedSnapshotMtimeMs = fs6.statSync(snapshotPath).mtimeMs;
|
|
3361
|
+
} catch {
|
|
3362
|
+
}
|
|
3238
3363
|
const callData = this.callGraphIndex.toJSON();
|
|
3239
3364
|
const callPath = path6.join(this.snapshotDir, "call-graph-snapshot.json");
|
|
3240
3365
|
const callTmp = `${callPath}.${process.pid}.tmp`;
|
|
@@ -3312,6 +3437,10 @@ var DependencyGraph = class {
|
|
|
3312
3437
|
this.callGraphIndex = new CallGraphIndex();
|
|
3313
3438
|
}
|
|
3314
3439
|
}
|
|
3440
|
+
try {
|
|
3441
|
+
this.lastLoadedSnapshotMtimeMs = fs6.statSync(snapshotPath).mtimeMs;
|
|
3442
|
+
} catch {
|
|
3443
|
+
}
|
|
3315
3444
|
return true;
|
|
3316
3445
|
} catch (err) {
|
|
3317
3446
|
logger.error("Failed to load graph snapshot, will rebuild", { detail: err instanceof Error ? err.message : String(err) });
|
|
@@ -8687,7 +8816,7 @@ function registerFullTextSearchTool(registry, ctx) {
|
|
|
8687
8816
|
};
|
|
8688
8817
|
if (mode === "semantic") {
|
|
8689
8818
|
try {
|
|
8690
|
-
const { generateEmbedding: generateEmbedding2 } = await import("./embedder-
|
|
8819
|
+
const { generateEmbedding: generateEmbedding2 } = await import("./embedder-4MM7D3UE.js");
|
|
8691
8820
|
const store = await ctx.getStore(project_root);
|
|
8692
8821
|
const embedding = await generateEmbedding2(query);
|
|
8693
8822
|
const results = await store.search(embedding, limit);
|
|
@@ -8724,7 +8853,7 @@ function registerFullTextSearchTool(registry, ctx) {
|
|
|
8724
8853
|
let merged = keywordResults.slice(0, limit);
|
|
8725
8854
|
if (mode === "hybrid") {
|
|
8726
8855
|
try {
|
|
8727
|
-
const { generateEmbedding: generateEmbedding2 } = await import("./embedder-
|
|
8856
|
+
const { generateEmbedding: generateEmbedding2 } = await import("./embedder-4MM7D3UE.js");
|
|
8728
8857
|
const store = await ctx.getStore(project_root);
|
|
8729
8858
|
const embedding = await generateEmbedding2(query);
|
|
8730
8859
|
const vectorResults = await store.search(embedding, Math.ceil(limit / 2));
|
|
@@ -10599,7 +10728,7 @@ import chokidar from "chokidar";
|
|
|
10599
10728
|
function isIgnoredPath(absPath) {
|
|
10600
10729
|
const segments = absPath.split(/[\\/]/);
|
|
10601
10730
|
for (const seg of segments) {
|
|
10602
|
-
if (
|
|
10731
|
+
if (isIgnoredDir(seg)) return true;
|
|
10603
10732
|
}
|
|
10604
10733
|
return false;
|
|
10605
10734
|
}
|
|
@@ -10959,7 +11088,7 @@ var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
|
|
|
10959
11088
|
function getTelemetryLevel() {
|
|
10960
11089
|
return TELEMETRY_LEVEL;
|
|
10961
11090
|
}
|
|
10962
|
-
var CTXLOOM_VERSION2 = "1.7.
|
|
11091
|
+
var CTXLOOM_VERSION2 = "1.7.5".length > 0 ? "1.7.5" : "dev";
|
|
10963
11092
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
10964
11093
|
var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
|
|
10965
11094
|
var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
|
|
@@ -11294,6 +11423,11 @@ async function disposeProjectState(state) {
|
|
|
11294
11423
|
await state.watcher?.stop();
|
|
11295
11424
|
} catch {
|
|
11296
11425
|
}
|
|
11426
|
+
try {
|
|
11427
|
+
const graph = state.graphPromise ? await state.graphPromise.catch(() => null) : null;
|
|
11428
|
+
graph?.stopSnapshotWatcher();
|
|
11429
|
+
} catch {
|
|
11430
|
+
}
|
|
11297
11431
|
try {
|
|
11298
11432
|
const store = state.storePromise ? await state.storePromise : null;
|
|
11299
11433
|
await store?.close();
|
|
@@ -12640,4 +12774,4 @@ export {
|
|
|
12640
12774
|
skillFilePath,
|
|
12641
12775
|
installHarness
|
|
12642
12776
|
};
|
|
12643
|
-
//# sourceMappingURL=chunk-
|
|
12777
|
+
//# sourceMappingURL=chunk-2YELCPTS.js.map
|
|
@@ -153,64 +153,16 @@ async function generateEmbeddingBatch(texts) {
|
|
|
153
153
|
return data;
|
|
154
154
|
}
|
|
155
155
|
function collectFiles(dir, results = []) {
|
|
156
|
-
const IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
157
|
-
// Build artifacts + dependency caches
|
|
158
|
-
"node_modules",
|
|
159
|
-
"dist",
|
|
160
|
-
"build",
|
|
161
|
-
"out",
|
|
162
|
-
"target",
|
|
163
|
-
"coverage",
|
|
164
|
-
".cache",
|
|
165
|
-
".turbo",
|
|
166
|
-
".next",
|
|
167
|
-
".nuxt",
|
|
168
|
-
// Version control + ctxloom state
|
|
169
|
-
".git",
|
|
170
|
-
".ctxloom",
|
|
171
|
-
// Other tools' working state (often contains duplicated source)
|
|
172
|
-
".claude",
|
|
173
|
-
".code-review-graph",
|
|
174
|
-
".vscode-test"
|
|
175
|
-
]);
|
|
176
|
-
const SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
177
|
-
".ts",
|
|
178
|
-
".tsx",
|
|
179
|
-
".js",
|
|
180
|
-
".jsx",
|
|
181
|
-
".mjs",
|
|
182
|
-
".vue",
|
|
183
|
-
".py",
|
|
184
|
-
".rs",
|
|
185
|
-
".go",
|
|
186
|
-
".java",
|
|
187
|
-
".cs",
|
|
188
|
-
".rb",
|
|
189
|
-
".kt",
|
|
190
|
-
".kts",
|
|
191
|
-
".swift",
|
|
192
|
-
".php",
|
|
193
|
-
".dart",
|
|
194
|
-
".c",
|
|
195
|
-
".cpp",
|
|
196
|
-
".h",
|
|
197
|
-
".md",
|
|
198
|
-
".json",
|
|
199
|
-
".yaml",
|
|
200
|
-
".yml",
|
|
201
|
-
".toml",
|
|
202
|
-
".ipynb"
|
|
203
|
-
]);
|
|
204
156
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
205
157
|
for (const entry of entries) {
|
|
206
158
|
const fullPath = path.join(dir, entry.name);
|
|
207
159
|
if (entry.isDirectory()) {
|
|
208
|
-
if (!
|
|
160
|
+
if (!isIgnoredDir(entry.name)) {
|
|
209
161
|
collectFiles(fullPath, results);
|
|
210
162
|
}
|
|
211
163
|
} else if (entry.isFile()) {
|
|
212
164
|
const ext = path.extname(entry.name);
|
|
213
|
-
if (
|
|
165
|
+
if (INDEX_SUPPORTED_EXTENSIONS.has(ext)) {
|
|
214
166
|
results.push(fullPath);
|
|
215
167
|
}
|
|
216
168
|
}
|
|
@@ -222,7 +174,7 @@ async function* collectFilesStream(dir) {
|
|
|
222
174
|
for (const entry of entries) {
|
|
223
175
|
const fullPath = path.join(dir, entry.name);
|
|
224
176
|
if (entry.isDirectory()) {
|
|
225
|
-
if (!
|
|
177
|
+
if (!isIgnoredDir(entry.name)) {
|
|
226
178
|
yield* collectFilesStream(fullPath);
|
|
227
179
|
}
|
|
228
180
|
} else if (entry.isFile()) {
|
|
@@ -233,7 +185,7 @@ async function* collectFilesStream(dir) {
|
|
|
233
185
|
}
|
|
234
186
|
}
|
|
235
187
|
var INDEXER_IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
236
|
-
// Build artifacts + dependency caches
|
|
188
|
+
// Build artifacts + dependency caches (JS/TS, Rust, Java)
|
|
237
189
|
"node_modules",
|
|
238
190
|
"dist",
|
|
239
191
|
"build",
|
|
@@ -244,6 +196,21 @@ var INDEXER_IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
|
244
196
|
".turbo",
|
|
245
197
|
".next",
|
|
246
198
|
".nuxt",
|
|
199
|
+
// Python virtualenvs + caches. Real-world repro: EasyMoney (a 63-
|
|
200
|
+
// source-file FastAPI project) had a `.venv/` with 8,192 installed-
|
|
201
|
+
// package files. Pre-fix, `ctxloom index` reported 8,120 files /
|
|
202
|
+
// 14,138 edges instead of the expected 63 / 97, because none of the
|
|
203
|
+
// standard Python virtualenv/cache directory names were in this set.
|
|
204
|
+
// The `__pycache__` + `.pytest_cache` + `.ruff_cache` + `.mypy_cache`
|
|
205
|
+
// additions catch the bulk of Python noise on top of the venv.
|
|
206
|
+
".venv",
|
|
207
|
+
"venv",
|
|
208
|
+
"env",
|
|
209
|
+
"__pycache__",
|
|
210
|
+
".pytest_cache",
|
|
211
|
+
".ruff_cache",
|
|
212
|
+
".mypy_cache",
|
|
213
|
+
".tox",
|
|
247
214
|
// Version control + ctxloom state
|
|
248
215
|
".git",
|
|
249
216
|
".ctxloom",
|
|
@@ -252,7 +219,11 @@ var INDEXER_IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
|
252
219
|
".code-review-graph",
|
|
253
220
|
".vscode-test"
|
|
254
221
|
]);
|
|
255
|
-
|
|
222
|
+
function isIgnoredDir(name) {
|
|
223
|
+
if (INDEXER_IGNORED_DIRS.has(name)) return true;
|
|
224
|
+
if (name.endsWith(".egg-info") || name.endsWith(".dist-info")) return true;
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
256
227
|
var INDEX_SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
257
228
|
".ts",
|
|
258
229
|
".tsx",
|
|
@@ -282,7 +253,7 @@ var INDEX_SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
282
253
|
".ipynb"
|
|
283
254
|
]);
|
|
284
255
|
async function indexDirectory(rootDir, onProgress) {
|
|
285
|
-
const { VectorStore } = await import("./VectorStore-
|
|
256
|
+
const { VectorStore } = await import("./VectorStore-5ALWL6XF.js");
|
|
286
257
|
const store = new VectorStore(path.join(rootDir, ".ctxloom", "vectors.lancedb"));
|
|
287
258
|
await store.init();
|
|
288
259
|
let indexed = 0;
|
|
@@ -390,8 +361,9 @@ export {
|
|
|
390
361
|
collectFiles,
|
|
391
362
|
collectFilesStream,
|
|
392
363
|
INDEXER_IGNORED_DIRS,
|
|
364
|
+
isIgnoredDir,
|
|
393
365
|
indexDirectory,
|
|
394
366
|
EMBEDDING_MODEL_ID,
|
|
395
367
|
getActiveEmbeddingModel
|
|
396
368
|
};
|
|
397
|
-
//# sourceMappingURL=chunk-
|
|
369
|
+
//# sourceMappingURL=chunk-JZOJC3S7.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EMBEDDING_DIMENSION,
|
|
3
3
|
EMBEDDING_MODEL_ID
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JZOJC3S7.js";
|
|
5
5
|
import {
|
|
6
6
|
logger
|
|
7
7
|
} from "./chunk-TYDMSHV7.js";
|
|
@@ -307,4 +307,4 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
|
|
|
307
307
|
export {
|
|
308
308
|
VectorStore
|
|
309
309
|
};
|
|
310
|
-
//# sourceMappingURL=chunk-
|
|
310
|
+
//# sourceMappingURL=chunk-XQEQLXY5.js.map
|
|
@@ -8,8 +8,9 @@ import {
|
|
|
8
8
|
generateEmbeddingBatch,
|
|
9
9
|
getActiveEmbeddingModel,
|
|
10
10
|
indexDirectory,
|
|
11
|
+
isIgnoredDir,
|
|
11
12
|
resolveEmbeddingModel
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-JZOJC3S7.js";
|
|
13
14
|
import "./chunk-TYDMSHV7.js";
|
|
14
15
|
export {
|
|
15
16
|
EMBEDDING_DIMENSION,
|
|
@@ -21,6 +22,7 @@ export {
|
|
|
21
22
|
generateEmbeddingBatch,
|
|
22
23
|
getActiveEmbeddingModel,
|
|
23
24
|
indexDirectory,
|
|
25
|
+
isIgnoredDir,
|
|
24
26
|
resolveEmbeddingModel
|
|
25
27
|
};
|
|
26
|
-
//# sourceMappingURL=embedder-
|
|
28
|
+
//# sourceMappingURL=embedder-4MM7D3UE.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-2YELCPTS.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-XQEQLXY5.js";
|
|
58
58
|
import {
|
|
59
59
|
collectFiles,
|
|
60
60
|
generateEmbedding,
|
|
61
61
|
indexDirectory
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-JZOJC3S7.js";
|
|
63
63
|
import "./chunk-5I6CJITG.js";
|
|
64
64
|
import {
|
|
65
65
|
logger
|
|
@@ -127,6 +127,7 @@ async function initGraph(state) {
|
|
|
127
127
|
const graph = new DependencyGraph();
|
|
128
128
|
graph.setParser(parser);
|
|
129
129
|
await graph.buildFromDirectory(state.projectRoot);
|
|
130
|
+
graph.startSnapshotWatcher();
|
|
130
131
|
state.graphInitialized = true;
|
|
131
132
|
return graph;
|
|
132
133
|
} catch (err) {
|
|
@@ -1067,7 +1068,7 @@ try {
|
|
|
1067
1068
|
} catch {
|
|
1068
1069
|
}
|
|
1069
1070
|
var args = process.argv.slice(2);
|
|
1070
|
-
var ctxloomVersion = "1.7.
|
|
1071
|
+
var ctxloomVersion = "1.7.5".length > 0 ? "1.7.5" : "dev";
|
|
1071
1072
|
if (args.includes("--version") || args.includes("-v")) {
|
|
1072
1073
|
process.stdout.write(`ctxloom ${ctxloomVersion}
|
|
1073
1074
|
`);
|
|
@@ -1162,7 +1163,7 @@ async function checkLicense() {
|
|
|
1162
1163
|
if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
|
|
1163
1164
|
const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
|
|
1164
1165
|
if (ciKey) {
|
|
1165
|
-
const { ApiClient } = await import("./src-
|
|
1166
|
+
const { ApiClient } = await import("./src-NCWA7NVW.js");
|
|
1166
1167
|
const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
|
|
1167
1168
|
try {
|
|
1168
1169
|
const result = await client.validate(ciKey, "ci-ephemeral");
|
|
@@ -1555,7 +1556,7 @@ async function main() {
|
|
|
1555
1556
|
}
|
|
1556
1557
|
if (!skipHarness) {
|
|
1557
1558
|
process.stdout.write("\n");
|
|
1558
|
-
const { installHarness } = await import("./src-
|
|
1559
|
+
const { installHarness } = await import("./src-NCWA7NVW.js");
|
|
1559
1560
|
const h = installHarness({ cwd: initRoot, dryRun, force, extraHosts });
|
|
1560
1561
|
const harnessFiles = [
|
|
1561
1562
|
h.claudeMd,
|
|
@@ -1618,7 +1619,7 @@ async function main() {
|
|
|
1618
1619
|
process.exit(1);
|
|
1619
1620
|
}
|
|
1620
1621
|
if (alias !== void 0) {
|
|
1621
|
-
const { validateAlias } = await import("./src-
|
|
1622
|
+
const { validateAlias } = await import("./src-NCWA7NVW.js");
|
|
1622
1623
|
const v = validateAlias(alias);
|
|
1623
1624
|
if (!v.ok) {
|
|
1624
1625
|
console.error(`[ctxloom] Invalid alias: ${v.reason}`);
|
|
@@ -1977,7 +1978,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
1977
1978
|
process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
|
|
1978
1979
|
process.exit(2);
|
|
1979
1980
|
}
|
|
1980
|
-
const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-
|
|
1981
|
+
const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-NCWA7NVW.js");
|
|
1981
1982
|
let config;
|
|
1982
1983
|
try {
|
|
1983
1984
|
config = await loadRulesConfig(root);
|
|
@@ -2001,7 +2002,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
2001
2002
|
}
|
|
2002
2003
|
let graph;
|
|
2003
2004
|
if (useSnapshot) {
|
|
2004
|
-
const { DependencyGraph: DG } = await import("./src-
|
|
2005
|
+
const { DependencyGraph: DG } = await import("./src-NCWA7NVW.js");
|
|
2005
2006
|
graph = new DG();
|
|
2006
2007
|
const loaded = await graph.loadSnapshotOnly(root);
|
|
2007
2008
|
if (!loaded) {
|
|
@@ -2010,7 +2011,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
2010
2011
|
}
|
|
2011
2012
|
} else {
|
|
2012
2013
|
process.stderr.write("[ctxloom] Building dependency graph...\n");
|
|
2013
|
-
const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-
|
|
2014
|
+
const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-NCWA7NVW.js");
|
|
2014
2015
|
let parser;
|
|
2015
2016
|
try {
|
|
2016
2017
|
parser = new ASTParser2();
|
|
@@ -132,16 +132,18 @@ import {
|
|
|
132
132
|
wrapBlock,
|
|
133
133
|
wrapWithIndexingEnvelope,
|
|
134
134
|
writeCODEOWNERS
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-2YELCPTS.js";
|
|
136
136
|
import {
|
|
137
137
|
VectorStore
|
|
138
|
-
} from "./chunk-
|
|
138
|
+
} from "./chunk-XQEQLXY5.js";
|
|
139
139
|
import {
|
|
140
140
|
EMBEDDING_DIMENSION,
|
|
141
|
+
INDEXER_IGNORED_DIRS,
|
|
141
142
|
collectFiles,
|
|
142
143
|
generateEmbedding,
|
|
143
|
-
indexDirectory
|
|
144
|
-
|
|
144
|
+
indexDirectory,
|
|
145
|
+
isIgnoredDir
|
|
146
|
+
} from "./chunk-JZOJC3S7.js";
|
|
145
147
|
import {
|
|
146
148
|
filenameForDate,
|
|
147
149
|
readEvents,
|
|
@@ -182,6 +184,7 @@ export {
|
|
|
182
184
|
GrammarLoader,
|
|
183
185
|
GraphExporter,
|
|
184
186
|
HOST_ADAPTERS,
|
|
187
|
+
INDEXER_IGNORED_DIRS,
|
|
185
188
|
InvalidKeyError,
|
|
186
189
|
LicenseRequiredError,
|
|
187
190
|
LicenseRevokedError,
|
|
@@ -256,6 +259,7 @@ export {
|
|
|
256
259
|
inspectVectorsDb,
|
|
257
260
|
installHarness,
|
|
258
261
|
isActive,
|
|
262
|
+
isIgnoredDir,
|
|
259
263
|
isSiloed,
|
|
260
264
|
learnSuggestionsFromTelemetry,
|
|
261
265
|
listNamedSnapshots,
|
|
@@ -300,4 +304,4 @@ export {
|
|
|
300
304
|
wrapWithIndexingEnvelope,
|
|
301
305
|
writeCODEOWNERS
|
|
302
306
|
};
|
|
303
|
-
//# sourceMappingURL=src-
|
|
307
|
+
//# sourceMappingURL=src-NCWA7NVW.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VectorStore
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-XQEQLXY5.js";
|
|
4
4
|
import {
|
|
5
5
|
generateEmbedding
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-JZOJC3S7.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.5",
|
|
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",
|