@prom.codes/context-mcp 0.4.1 → 0.4.3
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/dist/bin.js +240 -31
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -3484,6 +3484,153 @@ function isSensitivePath(path) {
|
|
|
3484
3484
|
}
|
|
3485
3485
|
var SENSITIVE_PATH_ERROR = "path matches the sensitive-file deny-list";
|
|
3486
3486
|
|
|
3487
|
+
// ../shared/dist/update-check.js
|
|
3488
|
+
import { mkdir, readFile as readFile2, writeFile } from "node:fs/promises";
|
|
3489
|
+
import { homedir } from "node:os";
|
|
3490
|
+
import { join } from "node:path";
|
|
3491
|
+
import { fileURLToPath } from "node:url";
|
|
3492
|
+
async function packageIdentity(binImportMetaUrl) {
|
|
3493
|
+
try {
|
|
3494
|
+
const binPath = fileURLToPath(binImportMetaUrl);
|
|
3495
|
+
const pkgPath = join(binPath, "..", "..", "package.json");
|
|
3496
|
+
const raw = await readFile2(pkgPath, "utf8");
|
|
3497
|
+
const parsed = JSON.parse(raw);
|
|
3498
|
+
if (typeof parsed.name !== "string" || typeof parsed.version !== "string") {
|
|
3499
|
+
return null;
|
|
3500
|
+
}
|
|
3501
|
+
return { name: parsed.name, version: parsed.version };
|
|
3502
|
+
} catch {
|
|
3503
|
+
return null;
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
async function maybeNotifyUpdate(binImportMetaUrl, env = process.env) {
|
|
3507
|
+
try {
|
|
3508
|
+
const id = await packageIdentity(binImportMetaUrl);
|
|
3509
|
+
if (id === null)
|
|
3510
|
+
return;
|
|
3511
|
+
await checkForUpdate({ name: id.name, version: id.version, env });
|
|
3512
|
+
} catch {
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
3516
|
+
var DEFAULT_TIMEOUT_MS = 1500;
|
|
3517
|
+
var OPT_OUT_RE = /^(1|true|yes|on)$/i;
|
|
3518
|
+
function parseSemver(v) {
|
|
3519
|
+
const m = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/.exec(v.trim());
|
|
3520
|
+
if (m === null)
|
|
3521
|
+
return null;
|
|
3522
|
+
return {
|
|
3523
|
+
core: [Number(m[1]), Number(m[2]), Number(m[3])],
|
|
3524
|
+
pre: m[4] ?? null
|
|
3525
|
+
};
|
|
3526
|
+
}
|
|
3527
|
+
function isNewerVersion(latest, current) {
|
|
3528
|
+
const a = parseSemver(latest);
|
|
3529
|
+
const b = parseSemver(current);
|
|
3530
|
+
if (a === null || b === null)
|
|
3531
|
+
return false;
|
|
3532
|
+
for (let i = 0; i < 3; i++) {
|
|
3533
|
+
if (a.core[i] > b.core[i])
|
|
3534
|
+
return true;
|
|
3535
|
+
if (a.core[i] < b.core[i])
|
|
3536
|
+
return false;
|
|
3537
|
+
}
|
|
3538
|
+
if (a.pre === null && b.pre !== null)
|
|
3539
|
+
return true;
|
|
3540
|
+
return false;
|
|
3541
|
+
}
|
|
3542
|
+
function cachePath(dir, name) {
|
|
3543
|
+
const safe = name.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
3544
|
+
return join(dir, `.update-check-${safe}.json`);
|
|
3545
|
+
}
|
|
3546
|
+
async function readCache(path) {
|
|
3547
|
+
try {
|
|
3548
|
+
const raw = await readFile2(path, "utf8");
|
|
3549
|
+
const parsed = JSON.parse(raw);
|
|
3550
|
+
if (typeof parsed.checkedAt !== "number")
|
|
3551
|
+
return null;
|
|
3552
|
+
return {
|
|
3553
|
+
checkedAt: parsed.checkedAt,
|
|
3554
|
+
latest: typeof parsed.latest === "string" ? parsed.latest : null
|
|
3555
|
+
};
|
|
3556
|
+
} catch {
|
|
3557
|
+
return null;
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
async function writeCache(path, data) {
|
|
3561
|
+
try {
|
|
3562
|
+
await writeFile(path, JSON.stringify(data), "utf8");
|
|
3563
|
+
} catch {
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
async function fetchLatest(name, fetchImpl, timeoutMs) {
|
|
3567
|
+
const controller = new AbortController();
|
|
3568
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3569
|
+
timer.unref?.();
|
|
3570
|
+
try {
|
|
3571
|
+
const url = `https://registry.npmjs.org/${name.replace("/", "%2F")}/latest`;
|
|
3572
|
+
const res = await fetchImpl(url, {
|
|
3573
|
+
signal: controller.signal,
|
|
3574
|
+
headers: { accept: "application/vnd.npm.install-v1+json" }
|
|
3575
|
+
});
|
|
3576
|
+
if (!res.ok)
|
|
3577
|
+
return null;
|
|
3578
|
+
const body = await res.json();
|
|
3579
|
+
return typeof body.version === "string" ? body.version : null;
|
|
3580
|
+
} catch {
|
|
3581
|
+
return null;
|
|
3582
|
+
} finally {
|
|
3583
|
+
clearTimeout(timer);
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
async function checkForUpdate(options) {
|
|
3587
|
+
const { name, version, env = process.env, log = (line) => process.stderr.write(line), fetch: fetchImpl = globalThis.fetch, cacheDir = join(homedir(), ".prometheus"), cacheTtlMs = DEFAULT_TTL_MS, timeoutMs = DEFAULT_TIMEOUT_MS, force = false } = options;
|
|
3588
|
+
const base = {
|
|
3589
|
+
latest: null,
|
|
3590
|
+
current: version
|
|
3591
|
+
};
|
|
3592
|
+
if (OPT_OUT_RE.test(env.PROMETHEUS_NO_UPDATE_CHECK ?? "")) {
|
|
3593
|
+
return { ...base, checked: false, updateAvailable: false, reason: "opted-out" };
|
|
3594
|
+
}
|
|
3595
|
+
if (parseSemver(version) === null || version === "0.0.0") {
|
|
3596
|
+
return { ...base, checked: false, updateAvailable: false, reason: "invalid-version" };
|
|
3597
|
+
}
|
|
3598
|
+
if (typeof fetchImpl !== "function") {
|
|
3599
|
+
return { ...base, checked: false, updateAvailable: false, reason: "error" };
|
|
3600
|
+
}
|
|
3601
|
+
const file = cachePath(cacheDir, name);
|
|
3602
|
+
const now = Date.now();
|
|
3603
|
+
if (!force) {
|
|
3604
|
+
const cached = await readCache(file);
|
|
3605
|
+
if (cached !== null && now - cached.checkedAt < cacheTtlMs) {
|
|
3606
|
+
const updateAvailable2 = cached.latest !== null && isNewerVersion(cached.latest, version);
|
|
3607
|
+
if (updateAvailable2)
|
|
3608
|
+
notify(log, name, version, cached.latest);
|
|
3609
|
+
return {
|
|
3610
|
+
...base,
|
|
3611
|
+
latest: cached.latest,
|
|
3612
|
+
checked: false,
|
|
3613
|
+
updateAvailable: updateAvailable2,
|
|
3614
|
+
reason: "throttled"
|
|
3615
|
+
};
|
|
3616
|
+
}
|
|
3617
|
+
}
|
|
3618
|
+
await mkdir(cacheDir, { recursive: true }).catch(() => void 0);
|
|
3619
|
+
const latest = await fetchLatest(name, fetchImpl, timeoutMs);
|
|
3620
|
+
await writeCache(file, { checkedAt: now, latest });
|
|
3621
|
+
if (latest === null) {
|
|
3622
|
+
return { ...base, checked: true, updateAvailable: false, reason: "error" };
|
|
3623
|
+
}
|
|
3624
|
+
const updateAvailable = isNewerVersion(latest, version);
|
|
3625
|
+
if (updateAvailable)
|
|
3626
|
+
notify(log, name, version, latest);
|
|
3627
|
+
return { ...base, latest, checked: true, updateAvailable };
|
|
3628
|
+
}
|
|
3629
|
+
function notify(log, name, current, latest) {
|
|
3630
|
+
log(`${name}: a newer version (${latest}) is available \u2014 you are on ${current}. npx users get it automatically on the next restart; for a global install run \`npm update -g ${name}\`. (Set PROMETHEUS_NO_UPDATE_CHECK=1 to silence.)
|
|
3631
|
+
`);
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3487
3634
|
// ../shared/dist/index.js
|
|
3488
3635
|
var PROMETHEUS_VERSION = "0.1.0";
|
|
3489
3636
|
|
|
@@ -3542,6 +3689,8 @@ var WorkspaceWatcher = class extends EventEmitter {
|
|
|
3542
3689
|
#root;
|
|
3543
3690
|
#ignored;
|
|
3544
3691
|
#debounceMs;
|
|
3692
|
+
#usePolling;
|
|
3693
|
+
#pollIntervalMs;
|
|
3545
3694
|
#watcher = null;
|
|
3546
3695
|
#pending = /* @__PURE__ */ new Map();
|
|
3547
3696
|
constructor(options) {
|
|
@@ -3549,6 +3698,10 @@ var WorkspaceWatcher = class extends EventEmitter {
|
|
|
3549
3698
|
this.#root = resolve(options.root);
|
|
3550
3699
|
this.#ignored = options.ignored ?? DEFAULT_IGNORED;
|
|
3551
3700
|
this.#debounceMs = options.debounceMs ?? 50;
|
|
3701
|
+
const envPolling = process.env.CHOKIDAR_USEPOLLING === "true" || process.env.CHOKIDAR_USEPOLLING === "1";
|
|
3702
|
+
this.#usePolling = options.usePolling ?? envPolling;
|
|
3703
|
+
const envInterval = Number.parseInt(process.env.CHOKIDAR_INTERVAL ?? "", 10);
|
|
3704
|
+
this.#pollIntervalMs = options.pollIntervalMs ?? (Number.isInteger(envInterval) && envInterval > 0 ? envInterval : 80);
|
|
3552
3705
|
}
|
|
3553
3706
|
/** Absolute workspace root. */
|
|
3554
3707
|
get root() {
|
|
@@ -3558,14 +3711,25 @@ var WorkspaceWatcher = class extends EventEmitter {
|
|
|
3558
3711
|
async start() {
|
|
3559
3712
|
if (this.#watcher !== null)
|
|
3560
3713
|
return;
|
|
3714
|
+
const relativeMatch = (pat) => (abs) => {
|
|
3715
|
+
const rel = toRelative(this.#root, abs);
|
|
3716
|
+
if (rel === abs)
|
|
3717
|
+
return false;
|
|
3718
|
+
if (typeof pat === "string") {
|
|
3719
|
+
return rel === pat || rel.startsWith(`${pat}/`);
|
|
3720
|
+
}
|
|
3721
|
+
return pat.test(rel);
|
|
3722
|
+
};
|
|
3561
3723
|
const denySensitive = (abs) => {
|
|
3562
3724
|
const rel = toRelative(this.#root, abs);
|
|
3563
3725
|
return rel !== abs && isSensitivePath(rel);
|
|
3564
3726
|
};
|
|
3565
3727
|
const watcher = chokidar.watch(this.#root, {
|
|
3566
|
-
ignored: [...this.#ignored, denySensitive],
|
|
3728
|
+
ignored: [...this.#ignored.map(relativeMatch), denySensitive],
|
|
3567
3729
|
ignoreInitial: false,
|
|
3568
3730
|
persistent: true,
|
|
3731
|
+
usePolling: this.#usePolling,
|
|
3732
|
+
...this.#usePolling ? { interval: this.#pollIntervalMs, binaryInterval: this.#pollIntervalMs } : {},
|
|
3569
3733
|
awaitWriteFinish: { stabilityThreshold: 50, pollInterval: 10 }
|
|
3570
3734
|
});
|
|
3571
3735
|
this.#watcher = watcher;
|
|
@@ -3608,8 +3772,8 @@ var WorkspaceWatcher = class extends EventEmitter {
|
|
|
3608
3772
|
};
|
|
3609
3773
|
|
|
3610
3774
|
// ../indexer/dist/workspace-indexer.js
|
|
3611
|
-
import { readFile as
|
|
3612
|
-
import { join, resolve as resolve2, sep as sep2 } from "node:path";
|
|
3775
|
+
import { readFile as readFile3, readdir, stat } from "node:fs/promises";
|
|
3776
|
+
import { join as join2, resolve as resolve2, sep as sep2 } from "node:path";
|
|
3613
3777
|
|
|
3614
3778
|
// ../indexer/dist/co-change.js
|
|
3615
3779
|
import { spawn } from "node:child_process";
|
|
@@ -3811,6 +3975,7 @@ var WorkspaceIndexer = class {
|
|
|
3811
3975
|
#ignored;
|
|
3812
3976
|
#concurrency;
|
|
3813
3977
|
#coChangeBuilder;
|
|
3978
|
+
#watchTuning;
|
|
3814
3979
|
#watcher = null;
|
|
3815
3980
|
constructor(options) {
|
|
3816
3981
|
this.#root = resolve2(options.root);
|
|
@@ -3819,6 +3984,7 @@ var WorkspaceIndexer = class {
|
|
|
3819
3984
|
this.#ownsIndexer = options.indexer === void 0;
|
|
3820
3985
|
this.#ignored = options.ignored;
|
|
3821
3986
|
this.#concurrency = Math.max(1, options.concurrency ?? 8);
|
|
3987
|
+
this.#watchTuning = options.watch;
|
|
3822
3988
|
this.#coChangeBuilder = options.coChange === false ? null : new CoChangeBuilder({
|
|
3823
3989
|
repoRoot: this.#root,
|
|
3824
3990
|
storage: this.#storage,
|
|
@@ -3882,7 +4048,7 @@ var WorkspaceIndexer = class {
|
|
|
3882
4048
|
return;
|
|
3883
4049
|
}
|
|
3884
4050
|
for (const entry of entries) {
|
|
3885
|
-
const abs =
|
|
4051
|
+
const abs = join2(dir, entry.name);
|
|
3886
4052
|
const rel = toRelative2(this.#root, abs);
|
|
3887
4053
|
if (this.#isIgnored(rel))
|
|
3888
4054
|
continue;
|
|
@@ -3929,7 +4095,11 @@ var WorkspaceIndexer = class {
|
|
|
3929
4095
|
this.#indexer.dispose();
|
|
3930
4096
|
}
|
|
3931
4097
|
#watcherOptions() {
|
|
3932
|
-
return
|
|
4098
|
+
return {
|
|
4099
|
+
root: this.#root,
|
|
4100
|
+
...this.#ignored !== void 0 ? { ignored: this.#ignored } : {},
|
|
4101
|
+
...this.#watchTuning ?? {}
|
|
4102
|
+
};
|
|
3933
4103
|
}
|
|
3934
4104
|
async #handleEvent(ev) {
|
|
3935
4105
|
try {
|
|
@@ -3949,7 +4119,7 @@ var WorkspaceIndexer = class {
|
|
|
3949
4119
|
let raw;
|
|
3950
4120
|
let stats;
|
|
3951
4121
|
try {
|
|
3952
|
-
raw = await
|
|
4122
|
+
raw = await readFile3(absPath);
|
|
3953
4123
|
stats = await stat(absPath);
|
|
3954
4124
|
} catch (err) {
|
|
3955
4125
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
@@ -4001,8 +4171,8 @@ var WorkspaceIndexer = class {
|
|
|
4001
4171
|
// dist/composition.js
|
|
4002
4172
|
import { createHash as createHash3 } from "node:crypto";
|
|
4003
4173
|
import { mkdirSync } from "node:fs";
|
|
4004
|
-
import { homedir } from "node:os";
|
|
4005
|
-
import { basename as basename5, dirname as dirname2, join as
|
|
4174
|
+
import { homedir as homedir2 } from "node:os";
|
|
4175
|
+
import { basename as basename5, dirname as dirname2, join as join4, resolve as resolve4 } from "node:path";
|
|
4006
4176
|
|
|
4007
4177
|
// ../storage-sqlite/dist/adapter.js
|
|
4008
4178
|
import Database from "better-sqlite3";
|
|
@@ -4727,8 +4897,8 @@ var DEFAULT_VECTOR_DIMENSION = 1024;
|
|
|
4727
4897
|
var DEFAULT_SCHEMA = "public";
|
|
4728
4898
|
|
|
4729
4899
|
// ../storage-supabase/dist/migrations.js
|
|
4730
|
-
import { dirname, join as
|
|
4731
|
-
import { fileURLToPath } from "node:url";
|
|
4900
|
+
import { dirname, join as join3, resolve as resolve3 } from "node:path";
|
|
4901
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
4732
4902
|
|
|
4733
4903
|
// ../storage-supabase/dist/migrations-data.generated.js
|
|
4734
4904
|
var EMBEDDED_MIGRATIONS = {
|
|
@@ -4819,13 +4989,13 @@ COMMIT;
|
|
|
4819
4989
|
};
|
|
4820
4990
|
|
|
4821
4991
|
// ../storage-supabase/dist/migrations.js
|
|
4822
|
-
var HERE = dirname(
|
|
4992
|
+
var HERE = dirname(fileURLToPath2(import.meta.url));
|
|
4823
4993
|
var REPO_ROOT = resolve3(HERE, "..", "..", "..");
|
|
4824
|
-
var MIGRATIONS_DIR =
|
|
4994
|
+
var MIGRATIONS_DIR = join3(REPO_ROOT, "infra", "supabase", "migrations");
|
|
4825
4995
|
var MIGRATIONS = Object.keys(EMBEDDED_MIGRATIONS).sort().map((filename, idx) => ({
|
|
4826
4996
|
id: idx + 1,
|
|
4827
4997
|
filename,
|
|
4828
|
-
path:
|
|
4998
|
+
path: join3(MIGRATIONS_DIR, filename)
|
|
4829
4999
|
}));
|
|
4830
5000
|
async function loadMigrationSql(filename) {
|
|
4831
5001
|
const sql = EMBEDDED_MIGRATIONS[filename];
|
|
@@ -6149,7 +6319,7 @@ var HybridRetriever = class {
|
|
|
6149
6319
|
const coChangeActive = effectiveEdgeWeights[CO_CHANGE] > 0;
|
|
6150
6320
|
const lexCols = options.lexicalColumnWeights;
|
|
6151
6321
|
const lexicalPromise = wLex > 0 ? this.#storage.searchByText(trimmed, candidateLimit, lexCols !== void 0 ? { columnWeights: lexCols } : void 0) : Promise.resolve([]);
|
|
6152
|
-
const vectorPromise = wVec > 0 ? this.#runVector(trimmed, candidateLimit, options.signal) : Promise.resolve({ hits: [], queryVector: null });
|
|
6322
|
+
const vectorPromise = wVec > 0 ? this.#runVector(trimmed, candidateLimit, options.signal, options.onVectorError) : Promise.resolve({ hits: [], queryVector: null });
|
|
6153
6323
|
const [lexicalHits, vectorResult] = await Promise.all([
|
|
6154
6324
|
lexicalPromise,
|
|
6155
6325
|
vectorPromise
|
|
@@ -6240,15 +6410,24 @@ var HybridRetriever = class {
|
|
|
6240
6410
|
}
|
|
6241
6411
|
return fusedResults;
|
|
6242
6412
|
}
|
|
6243
|
-
async #runVector(query, limit, signal) {
|
|
6413
|
+
async #runVector(query, limit, signal, onVectorError) {
|
|
6244
6414
|
const opts = signal !== void 0 ? { inputType: "query", signal } : { inputType: "query" };
|
|
6245
|
-
|
|
6246
|
-
|
|
6415
|
+
try {
|
|
6416
|
+
const vectors = await this.#embedder.embed([query], opts);
|
|
6417
|
+
if (vectors.length === 0 || vectors[0] === void 0) {
|
|
6418
|
+
return { hits: [], queryVector: null };
|
|
6419
|
+
}
|
|
6420
|
+
const queryVector = vectors[0];
|
|
6421
|
+
const hits = await this.#storage.searchByVector(queryVector, limit);
|
|
6422
|
+
return { hits, queryVector };
|
|
6423
|
+
} catch (err) {
|
|
6424
|
+
if (err?.name === "AbortError")
|
|
6425
|
+
throw err;
|
|
6426
|
+
if (onVectorError === void 0)
|
|
6427
|
+
throw err;
|
|
6428
|
+
onVectorError(err);
|
|
6247
6429
|
return { hits: [], queryVector: null };
|
|
6248
6430
|
}
|
|
6249
|
-
const queryVector = vectors[0];
|
|
6250
|
-
const hits = await this.#storage.searchByVector(queryVector, limit);
|
|
6251
|
-
return { hits, queryVector };
|
|
6252
6431
|
}
|
|
6253
6432
|
/**
|
|
6254
6433
|
* Run typed symbol-graph expansion from `seeds`.
|
|
@@ -8257,7 +8436,7 @@ function discoverQueryRewriter(env, fetchImpl) {
|
|
|
8257
8436
|
function getStableDbPath(workspaceRoot) {
|
|
8258
8437
|
const abs = resolve4(workspaceRoot);
|
|
8259
8438
|
const hash = createHash3("sha256").update(abs).digest("hex").slice(0, 16);
|
|
8260
|
-
return
|
|
8439
|
+
return join4(homedir2(), ".prometheus", `${hash}.db`);
|
|
8261
8440
|
}
|
|
8262
8441
|
var StorageConfigError = class extends Error {
|
|
8263
8442
|
constructor(reason) {
|
|
@@ -8336,7 +8515,10 @@ async function composeFromEnv(opts) {
|
|
|
8336
8515
|
const workspaceName = (env.PROMETHEUS_WORKSPACE_NAME ?? "") !== "" ? env.PROMETHEUS_WORKSPACE_NAME : basename5(workspaceRoot) || workspaceRoot;
|
|
8337
8516
|
const { id: providerId, provider: embedder, regionMode } = discoverEmbeddingProvider(env, opts.fetch);
|
|
8338
8517
|
const apiKeyPresent = (env.PROMETHEUS_API_KEY ?? "") !== "";
|
|
8339
|
-
const storageOptions =
|
|
8518
|
+
const storageOptions = {
|
|
8519
|
+
writable: true,
|
|
8520
|
+
defaultDbPath: getStableDbPath(workspaceRoot)
|
|
8521
|
+
};
|
|
8340
8522
|
const { id: storageBackend, adapter: storage, dbPath } = discoverStorageBackend(env, regionMode, storageOptions);
|
|
8341
8523
|
await storage.init();
|
|
8342
8524
|
const retriever = new HybridRetriever({ storage, embedder });
|
|
@@ -8372,7 +8554,7 @@ async function composeFromEnv(opts) {
|
|
|
8372
8554
|
}
|
|
8373
8555
|
|
|
8374
8556
|
// dist/roots.js
|
|
8375
|
-
import { fileURLToPath as
|
|
8557
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
8376
8558
|
async function rootFromClient(server, timeoutMs = 2500) {
|
|
8377
8559
|
let supportsRoots = false;
|
|
8378
8560
|
try {
|
|
@@ -8393,7 +8575,7 @@ async function rootFromClient(server, timeoutMs = 2500) {
|
|
|
8393
8575
|
const uri = typeof r?.uri === "string" ? r.uri : "";
|
|
8394
8576
|
if (uri.startsWith("file://")) {
|
|
8395
8577
|
try {
|
|
8396
|
-
return
|
|
8578
|
+
return fileURLToPath3(uri);
|
|
8397
8579
|
} catch {
|
|
8398
8580
|
}
|
|
8399
8581
|
}
|
|
@@ -8405,8 +8587,8 @@ async function rootFromClient(server, timeoutMs = 2500) {
|
|
|
8405
8587
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8406
8588
|
|
|
8407
8589
|
// dist/tools.js
|
|
8408
|
-
import { readFile as
|
|
8409
|
-
import { isAbsolute, join as
|
|
8590
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
8591
|
+
import { isAbsolute, join as join5, normalize, relative, resolve as resolve5, sep as sep3 } from "node:path";
|
|
8410
8592
|
import { z } from "zod";
|
|
8411
8593
|
|
|
8412
8594
|
// dist/frameworks.js
|
|
@@ -8608,7 +8790,7 @@ async function snippetForSymbol(workspaceRoot, symbol, cache, capBytes = MAX_SNI
|
|
|
8608
8790
|
let buf = cache.get(relPath);
|
|
8609
8791
|
if (buf === void 0) {
|
|
8610
8792
|
const abs = resolveInWorkspace(workspaceRoot, relPath);
|
|
8611
|
-
buf = await
|
|
8793
|
+
buf = await readFile4(abs).catch(() => null);
|
|
8612
8794
|
cache.set(relPath, buf);
|
|
8613
8795
|
}
|
|
8614
8796
|
if (buf === null)
|
|
@@ -8757,7 +8939,16 @@ ${hyp}`;
|
|
|
8757
8939
|
} catch {
|
|
8758
8940
|
}
|
|
8759
8941
|
}
|
|
8760
|
-
|
|
8942
|
+
let vectorError = null;
|
|
8943
|
+
const pool = await retriever.search(searchQuery, {
|
|
8944
|
+
k: poolK,
|
|
8945
|
+
onVectorError: (err) => {
|
|
8946
|
+
if (vectorError !== null)
|
|
8947
|
+
return;
|
|
8948
|
+
vectorError = err instanceof Error ? err.message : String(err);
|
|
8949
|
+
console.error(`[context-mcp] search_code: vector (semantic) search unavailable \u2014 falling back to lexical + symbol-graph. Likely a missing/invalid embedding API key; set PROMETHEUS_API_KEY (a real minted prom_live_\u2026 key) or a provider key (e.g. VOYAGE_API_KEY) to enable semantic ranking. Cause: ${vectorError}`);
|
|
8950
|
+
}
|
|
8951
|
+
});
|
|
8761
8952
|
let ordered = pool;
|
|
8762
8953
|
let reranked = false;
|
|
8763
8954
|
if (reranker && pool.length > 0) {
|
|
@@ -8782,7 +8973,18 @@ ${hyp}`;
|
|
|
8782
8973
|
const snip = await snippetForSymbol(workspaceRoot, r.symbol, cache);
|
|
8783
8974
|
return snip === null ? base : { ...base, snippet: snip.text, snippetTruncated: snip.truncated };
|
|
8784
8975
|
}));
|
|
8785
|
-
|
|
8976
|
+
const payload = {
|
|
8977
|
+
query: args.query,
|
|
8978
|
+
k,
|
|
8979
|
+
reranked,
|
|
8980
|
+
results: mapped
|
|
8981
|
+
};
|
|
8982
|
+
if (vectorError !== null) {
|
|
8983
|
+
payload.degraded = "lexical+graph-only";
|
|
8984
|
+
payload.note = "Semantic (vector) search was unavailable \u2014 results are lexical (keyword) + symbol-graph only, which can rank less precisely on concept queries. Set a valid embedding key (PROMETHEUS_API_KEY = a real minted prom_live_\u2026 key, or e.g. VOYAGE_API_KEY) to enable semantic ranking.";
|
|
8985
|
+
payload.vectorError = vectorError;
|
|
8986
|
+
}
|
|
8987
|
+
return textResult(payload);
|
|
8786
8988
|
});
|
|
8787
8989
|
server.registerTool("get_symbol", {
|
|
8788
8990
|
title: "Exact symbol lookup",
|
|
@@ -8852,7 +9054,7 @@ ${hyp}`;
|
|
|
8852
9054
|
if (isSensitivePath(relative(workspaceRoot, abs))) {
|
|
8853
9055
|
throw new Error(`${SENSITIVE_PATH_ERROR}: "${args.path}".`);
|
|
8854
9056
|
}
|
|
8855
|
-
const buf = await
|
|
9057
|
+
const buf = await readFile4(abs);
|
|
8856
9058
|
const start = args.startByte ?? 0;
|
|
8857
9059
|
const end = args.endByte ?? buf.byteLength;
|
|
8858
9060
|
if (end < start) {
|
|
@@ -8923,7 +9125,7 @@ ${hyp}`;
|
|
|
8923
9125
|
const manifests = {};
|
|
8924
9126
|
for (const name of FRAMEWORK_MANIFESTS) {
|
|
8925
9127
|
try {
|
|
8926
|
-
manifests[name] = await
|
|
9128
|
+
manifests[name] = await readFile4(join5(workspaceRoot, name), "utf8");
|
|
8927
9129
|
} catch {
|
|
8928
9130
|
}
|
|
8929
9131
|
}
|
|
@@ -8951,6 +9153,10 @@ var SERVER_IDENTITY = {
|
|
|
8951
9153
|
function errMessage(err) {
|
|
8952
9154
|
return err instanceof Error ? err.message : String(err);
|
|
8953
9155
|
}
|
|
9156
|
+
function looksLikeMissingNativeBinding(msg) {
|
|
9157
|
+
return /bindings file|better_sqlite3\.node|could not locate the bindings|node_module_version|was compiled against a different|invalid elf|\.node['"\s]/i.test(msg);
|
|
9158
|
+
}
|
|
9159
|
+
var NATIVE_BINDING_HINT = '\nThis looks like the native `better-sqlite3` module failed to load \u2014 usually\nbecause npm `ignore-scripts=true` (corporate hardening) made `npx` skip the\nnative build, so the binary was never produced. Fix it once, keeping your\nhardening intact:\n npm install -g @prom.codes/context-mcp --ignore-scripts=false --foreground-scripts\nthen point Claude Code at the built binary instead of npx:\n claude mcp add context -- node "$(npm root -g)/@prom.codes/context-mcp/dist/bin.js"\nDocs: https://prom.codes/docs/mcp/claude-code\n';
|
|
8954
9160
|
function startManagedIndexing(composed) {
|
|
8955
9161
|
const indexer = new WorkspaceIndexer({
|
|
8956
9162
|
root: composed.workspaceRoot,
|
|
@@ -8987,6 +9193,7 @@ async function main() {
|
|
|
8987
9193
|
const explicitRoot = (env.PROMETHEUS_WORKSPACE_ROOT ?? "").trim();
|
|
8988
9194
|
const claudeRoot = (env.CLAUDE_PROJECT_DIR ?? "").trim();
|
|
8989
9195
|
const eagerVia = explicitRoot !== "" ? "PROMETHEUS_WORKSPACE_ROOT" : claudeRoot !== "" ? "CLAUDE_PROJECT_DIR" : null;
|
|
9196
|
+
void maybeNotifyUpdate(import.meta.url, env);
|
|
8990
9197
|
const transport = new StdioServerTransport();
|
|
8991
9198
|
const server = new McpServer2(SERVER_IDENTITY, { capabilities: { tools: {} } });
|
|
8992
9199
|
let composed = null;
|
|
@@ -9054,5 +9261,7 @@ main().catch((err) => {
|
|
|
9054
9261
|
const message = err instanceof Error ? err.message : String(err);
|
|
9055
9262
|
process.stderr.write(`prometheus-context-mcp: fatal: ${message}
|
|
9056
9263
|
`);
|
|
9264
|
+
if (looksLikeMissingNativeBinding(message))
|
|
9265
|
+
process.stderr.write(NATIVE_BINDING_HINT);
|
|
9057
9266
|
process.exit(1);
|
|
9058
9267
|
});
|