@prom.codes/context-mcp 0.4.5 → 0.4.7

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.
Files changed (3) hide show
  1. package/README.md +14 -1
  2. package/dist/bin.js +50 -39
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -25,10 +25,23 @@ MCP hosts (Cursor, VS Code) use the same command/args in their own config.
25
25
  the MCP `roots` capability. Set it only to point at a different folder.
26
26
  - The index is a local SQLite DB at `~/.prometheus/<hash>.db` (one per project).
27
27
  Your code never leaves your machine — only embedding *text* transits to the proxy.
28
+ - **Won't crawl your home folder.** If a fresh window opens with no project, the
29
+ workspace falls back to the host cwd (often home); the server **refuses to
30
+ auto-index the home directory or a filesystem root** and leaves the index empty
31
+ until you open a real project. Call `index_status` to see what's going on.
28
32
 
29
33
  Tools: `search_code`, `get_symbol`, `find_references`, `find_callers`,
30
34
  `find_callees`, `expand_context`, `get_file`, `list_changed_since`,
31
- `list_workspaces`, `framework_overview`.
35
+ `list_workspaces`, `framework_overview`, `index_status` (health check:
36
+ which folder, how much is indexed, does the key work?).
37
+
38
+ ## Awareness
39
+
40
+ The server advertises MCP `instructions` that tell the agent to PREFER
41
+ `search_code` + the graph tools over a manual grep→read loop. Context tools are
42
+ reactive (the agent reaches for them when it needs code), so — unlike memory —
43
+ no rule file is installed; the instructions + assertive tool descriptions are
44
+ enough to win over plain grep on a large or unfamiliar repo.
32
45
 
33
46
  ## Native modules
34
47
 
package/dist/bin.js CHANGED
@@ -3369,7 +3369,7 @@ async function runEmbedPass(storage, embedder, options, driftRecovered) {
3369
3369
 
3370
3370
  // ../indexer/dist/watcher.js
3371
3371
  import chokidar from "chokidar";
3372
- import { resolve, sep } from "node:path";
3372
+ import { resolve as resolve2, sep } from "node:path";
3373
3373
  import { EventEmitter } from "node:events";
3374
3374
 
3375
3375
  // ../shared/dist/types.js
@@ -3631,6 +3631,20 @@ function notify(log, name, current, latest) {
3631
3631
  `);
3632
3632
  }
3633
3633
 
3634
+ // ../shared/dist/workspace-root.js
3635
+ import { homedir as homedir2 } from "node:os";
3636
+ import { dirname, resolve } from "node:path";
3637
+ function isHomeOrFilesystemRoot(root) {
3638
+ const abs = resolve(root);
3639
+ if (abs === "")
3640
+ return true;
3641
+ if (abs === resolve(homedir2()))
3642
+ return true;
3643
+ if (dirname(abs) === abs)
3644
+ return true;
3645
+ return false;
3646
+ }
3647
+
3634
3648
  // ../shared/dist/index.js
3635
3649
  var PROMETHEUS_VERSION = "0.1.0";
3636
3650
 
@@ -3695,7 +3709,7 @@ var WorkspaceWatcher = class extends EventEmitter {
3695
3709
  #pending = /* @__PURE__ */ new Map();
3696
3710
  constructor(options) {
3697
3711
  super();
3698
- this.#root = resolve(options.root);
3712
+ this.#root = resolve2(options.root);
3699
3713
  this.#ignored = options.ignored ?? DEFAULT_IGNORED;
3700
3714
  this.#debounceMs = options.debounceMs ?? 50;
3701
3715
  const envPolling = process.env.CHOKIDAR_USEPOLLING === "true" || process.env.CHOKIDAR_USEPOLLING === "1";
@@ -3773,7 +3787,7 @@ var WorkspaceWatcher = class extends EventEmitter {
3773
3787
 
3774
3788
  // ../indexer/dist/workspace-indexer.js
3775
3789
  import { readFile as readFile3, readdir, stat } from "node:fs/promises";
3776
- import { join as join2, resolve as resolve2, sep as sep2 } from "node:path";
3790
+ import { join as join2, resolve as resolve3, sep as sep2 } from "node:path";
3777
3791
 
3778
3792
  // ../indexer/dist/co-change.js
3779
3793
  import { spawn } from "node:child_process";
@@ -3978,7 +3992,7 @@ var WorkspaceIndexer = class {
3978
3992
  #watchTuning;
3979
3993
  #watcher = null;
3980
3994
  constructor(options) {
3981
- this.#root = resolve2(options.root);
3995
+ this.#root = resolve3(options.root);
3982
3996
  this.#storage = options.storage;
3983
3997
  this.#indexer = options.indexer ?? new Indexer();
3984
3998
  this.#ownsIndexer = options.indexer === void 0;
@@ -4171,8 +4185,8 @@ var WorkspaceIndexer = class {
4171
4185
  // dist/composition.js
4172
4186
  import { createHash as createHash3 } from "node:crypto";
4173
4187
  import { mkdirSync } from "node:fs";
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";
4188
+ import { homedir as homedir3 } from "node:os";
4189
+ import { basename as basename5, dirname as dirname3, join as join4, resolve as resolve5 } from "node:path";
4176
4190
 
4177
4191
  // ../storage-sqlite/dist/adapter.js
4178
4192
  import Database from "better-sqlite3";
@@ -4897,7 +4911,7 @@ var DEFAULT_VECTOR_DIMENSION = 1024;
4897
4911
  var DEFAULT_SCHEMA = "public";
4898
4912
 
4899
4913
  // ../storage-supabase/dist/migrations.js
4900
- import { dirname, join as join3, resolve as resolve3 } from "node:path";
4914
+ import { dirname as dirname2, join as join3, resolve as resolve4 } from "node:path";
4901
4915
  import { fileURLToPath as fileURLToPath2 } from "node:url";
4902
4916
 
4903
4917
  // ../storage-supabase/dist/migrations-data.generated.js
@@ -4989,8 +5003,8 @@ COMMIT;
4989
5003
  };
4990
5004
 
4991
5005
  // ../storage-supabase/dist/migrations.js
4992
- var HERE = dirname(fileURLToPath2(import.meta.url));
4993
- var REPO_ROOT = resolve3(HERE, "..", "..", "..");
5006
+ var HERE = dirname2(fileURLToPath2(import.meta.url));
5007
+ var REPO_ROOT = resolve4(HERE, "..", "..", "..");
4994
5008
  var MIGRATIONS_DIR = join3(REPO_ROOT, "infra", "supabase", "migrations");
4995
5009
  var MIGRATIONS = Object.keys(EMBEDDED_MIGRATIONS).sort().map((filename, idx) => ({
4996
5010
  id: idx + 1,
@@ -6574,14 +6588,14 @@ function parseRetryAfterMs(value, now = Date.now()) {
6574
6588
  return delta > 0 ? delta : 0;
6575
6589
  }
6576
6590
  function sleep(ms, signal) {
6577
- return new Promise((resolve6, reject) => {
6591
+ return new Promise((resolve7, reject) => {
6578
6592
  if (signal?.aborted === true) {
6579
6593
  reject(new Error("aborted"));
6580
6594
  return;
6581
6595
  }
6582
6596
  const timer = setTimeout(() => {
6583
6597
  signal?.removeEventListener("abort", onAbort);
6584
- resolve6();
6598
+ resolve7();
6585
6599
  }, ms);
6586
6600
  const onAbort = () => {
6587
6601
  clearTimeout(timer);
@@ -6809,14 +6823,14 @@ function taskTypeFor(inputType) {
6809
6823
  return inputType === "query" ? "RETRIEVAL_QUERY" : "RETRIEVAL_DOCUMENT";
6810
6824
  }
6811
6825
  function sleep2(ms, signal) {
6812
- return new Promise((resolve6, reject) => {
6826
+ return new Promise((resolve7, reject) => {
6813
6827
  if (signal?.aborted === true) {
6814
6828
  reject(new Error("aborted"));
6815
6829
  return;
6816
6830
  }
6817
6831
  const timer = setTimeout(() => {
6818
6832
  signal?.removeEventListener("abort", onAbort);
6819
- resolve6();
6833
+ resolve7();
6820
6834
  }, ms);
6821
6835
  const onAbort = () => {
6822
6836
  clearTimeout(timer);
@@ -6946,14 +6960,14 @@ var DEFAULT_BATCH3 = 96;
6946
6960
  var DEFAULT_RETRIES3 = 4;
6947
6961
  var DEFAULT_BACKOFF3 = 250;
6948
6962
  function sleep3(ms, signal) {
6949
- return new Promise((resolve6, reject) => {
6963
+ return new Promise((resolve7, reject) => {
6950
6964
  if (signal?.aborted === true) {
6951
6965
  reject(new Error("aborted"));
6952
6966
  return;
6953
6967
  }
6954
6968
  const timer = setTimeout(() => {
6955
6969
  signal?.removeEventListener("abort", onAbort);
6956
- resolve6();
6970
+ resolve7();
6957
6971
  }, ms);
6958
6972
  const onAbort = () => {
6959
6973
  clearTimeout(timer);
@@ -7096,14 +7110,14 @@ var DEFAULT_BATCH_CHARS = 4e5;
7096
7110
  var DEFAULT_RETRIES4 = 4;
7097
7111
  var DEFAULT_BACKOFF4 = 250;
7098
7112
  function sleep4(ms, signal) {
7099
- return new Promise((resolve6, reject) => {
7113
+ return new Promise((resolve7, reject) => {
7100
7114
  if (signal?.aborted === true) {
7101
7115
  reject(new Error("aborted"));
7102
7116
  return;
7103
7117
  }
7104
7118
  const timer = setTimeout(() => {
7105
7119
  signal?.removeEventListener("abort", onAbort);
7106
- resolve6();
7120
+ resolve7();
7107
7121
  }, ms);
7108
7122
  const onAbort = () => {
7109
7123
  clearTimeout(timer);
@@ -7418,14 +7432,14 @@ function parseRetryAfterMs2(value, now = Date.now()) {
7418
7432
  return delta > 0 ? delta : 0;
7419
7433
  }
7420
7434
  function sleep5(ms, signal) {
7421
- return new Promise((resolve6, reject) => {
7435
+ return new Promise((resolve7, reject) => {
7422
7436
  if (signal?.aborted === true) {
7423
7437
  reject(new Error("aborted"));
7424
7438
  return;
7425
7439
  }
7426
7440
  const timer = setTimeout(() => {
7427
7441
  signal?.removeEventListener("abort", onAbort);
7428
- resolve6();
7442
+ resolve7();
7429
7443
  }, ms);
7430
7444
  const onAbort = () => {
7431
7445
  clearTimeout(timer);
@@ -7590,14 +7604,14 @@ function parseRetryAfterMs3(value, now = Date.now()) {
7590
7604
  return delta > 0 ? delta : 0;
7591
7605
  }
7592
7606
  function sleep6(ms, signal) {
7593
- return new Promise((resolve6, reject) => {
7607
+ return new Promise((resolve7, reject) => {
7594
7608
  if (signal?.aborted === true) {
7595
7609
  reject(new Error("aborted"));
7596
7610
  return;
7597
7611
  }
7598
7612
  const timer = setTimeout(() => {
7599
7613
  signal?.removeEventListener("abort", onAbort);
7600
- resolve6();
7614
+ resolve7();
7601
7615
  }, ms);
7602
7616
  const onAbort = () => {
7603
7617
  clearTimeout(timer);
@@ -7789,14 +7803,14 @@ function parseRetryAfterMs4(value, now = Date.now()) {
7789
7803
  return delta > 0 ? delta : 0;
7790
7804
  }
7791
7805
  function sleep7(ms, signal) {
7792
- return new Promise((resolve6, reject) => {
7806
+ return new Promise((resolve7, reject) => {
7793
7807
  if (signal?.aborted === true) {
7794
7808
  reject(new Error("aborted"));
7795
7809
  return;
7796
7810
  }
7797
7811
  const timer = setTimeout(() => {
7798
7812
  signal?.removeEventListener("abort", onAbort);
7799
- resolve6();
7813
+ resolve7();
7800
7814
  }, ms);
7801
7815
  const onAbort = () => {
7802
7816
  clearTimeout(timer);
@@ -7960,14 +7974,14 @@ function parseRetryAfterMs5(value, now = Date.now()) {
7960
7974
  return delta > 0 ? delta : 0;
7961
7975
  }
7962
7976
  function sleep8(ms, signal) {
7963
- return new Promise((resolve6, reject) => {
7977
+ return new Promise((resolve7, reject) => {
7964
7978
  if (signal?.aborted === true) {
7965
7979
  reject(new Error("aborted"));
7966
7980
  return;
7967
7981
  }
7968
7982
  const timer = setTimeout(() => {
7969
7983
  signal?.removeEventListener("abort", onAbort);
7970
- resolve6();
7984
+ resolve7();
7971
7985
  }, ms);
7972
7986
  const onAbort = () => {
7973
7987
  clearTimeout(timer);
@@ -8434,19 +8448,12 @@ function discoverQueryRewriter(env, fetchImpl) {
8434
8448
  throw new NoProviderError(`unknown PROMETHEUS_REWRITER_PROVIDER="${forced}" (expected "none", "gemini", or "mistral")`);
8435
8449
  }
8436
8450
  function getStableDbPath(workspaceRoot) {
8437
- const abs = resolve4(workspaceRoot);
8451
+ const abs = resolve5(workspaceRoot);
8438
8452
  const hash = createHash3("sha256").update(abs).digest("hex").slice(0, 16);
8439
- return join4(homedir2(), ".prometheus", `${hash}.db`);
8453
+ return join4(homedir3(), ".prometheus", `${hash}.db`);
8440
8454
  }
8441
8455
  function isAutoIndexableRoot(workspaceRoot) {
8442
- const abs = resolve4(workspaceRoot);
8443
- if (abs === "")
8444
- return false;
8445
- if (abs === resolve4(homedir2()))
8446
- return false;
8447
- if (dirname2(abs) === abs)
8448
- return false;
8449
- return true;
8456
+ return !isHomeOrFilesystemRoot(workspaceRoot);
8450
8457
  }
8451
8458
  var StorageConfigError = class extends Error {
8452
8459
  constructor(reason) {
@@ -8486,7 +8493,7 @@ function discoverStorageBackend(env, regionMode, options = {}) {
8486
8493
  }
8487
8494
  const writable = options.writable === true;
8488
8495
  if (writable && dbPath !== ":memory:") {
8489
- mkdirSync(dirname2(dbPath), { recursive: true });
8496
+ mkdirSync(dirname3(dbPath), { recursive: true });
8490
8497
  }
8491
8498
  return {
8492
8499
  id: "sqlite",
@@ -8600,7 +8607,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8600
8607
 
8601
8608
  // dist/tools.js
8602
8609
  import { readFile as readFile4 } from "node:fs/promises";
8603
- import { isAbsolute, join as join5, normalize, relative, resolve as resolve5, sep as sep3 } from "node:path";
8610
+ import { isAbsolute, join as join5, normalize, relative, resolve as resolve6, sep as sep3 } from "node:path";
8604
8611
  import { z } from "zod";
8605
8612
 
8606
8613
  // dist/frameworks.js
@@ -8859,7 +8866,7 @@ function resolveInWorkspace(workspaceRoot, input) {
8859
8866
  throw new Error(`path "${input}" must be relative to the workspace root.`);
8860
8867
  }
8861
8868
  const normalised = normalize(input);
8862
- const abs = resolve5(workspaceRoot, normalised);
8869
+ const abs = resolve6(workspaceRoot, normalised);
8863
8870
  const rel = relative(workspaceRoot, abs);
8864
8871
  if (rel === "" || rel.startsWith("..") || sep3 !== "/" && rel.startsWith(`..${sep3}`)) {
8865
8872
  throw new Error(`path "${input}" escapes the workspace root.`);
@@ -9204,6 +9211,7 @@ var SERVER_IDENTITY = {
9204
9211
  version: PROMETHEUS_VERSION,
9205
9212
  title: "prom.codes Context"
9206
9213
  };
9214
+ var SERVER_INSTRUCTIONS = "This workspace is indexed by the prom.codes context engine. PREFER these tools over a manual grep/read loop when navigating code: search_code (hybrid semantic + lexical + symbol-graph \u2014 your FIRST move for any 'where/how is X' question, returns the code inline), get_symbol, find_references, find_callers, find_callees, expand_context, get_file. They are faster and more precise than scanning files by hand, especially on a large or unfamiliar repo. If search_code returns nothing or looks degraded, call index_status to check the index and the embedding key.";
9207
9215
 
9208
9216
  // dist/bin.js
9209
9217
  function errMessage(err) {
@@ -9251,7 +9259,10 @@ async function main() {
9251
9259
  const eagerVia = explicitRoot !== "" ? "PROMETHEUS_WORKSPACE_ROOT" : claudeRoot !== "" ? "CLAUDE_PROJECT_DIR" : null;
9252
9260
  void maybeNotifyUpdate(import.meta.url, env);
9253
9261
  const transport = new StdioServerTransport();
9254
- const server = new McpServer2(SERVER_IDENTITY, { capabilities: { tools: {} } });
9262
+ const server = new McpServer2(SERVER_IDENTITY, {
9263
+ capabilities: { tools: {} },
9264
+ instructions: SERVER_INSTRUCTIONS
9265
+ });
9255
9266
  let composed = null;
9256
9267
  let managedIndexer = null;
9257
9268
  const shutdown = async (signal) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prom.codes/context-mcp",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "description": "prom.codes Context — local-first codebase indexing & retrieval as an MCP server.",
5
5
  "type": "module",
6
6
  "bin": {