evrex-mcp 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/continuity.ts
4
- import { execFileSync } from "node:child_process";
4
+ import { execFileSync as execFileSync2 } from "node:child_process";
5
5
  import { closeSync, openSync, readSync, statSync } from "node:fs";
6
6
  import { pathToFileURL } from "node:url";
7
7
 
@@ -51,7 +51,7 @@ var evrexApi = {
51
51
  // Evidence-only retrieval (BM25 + embedding), no LLM synthesis call — see
52
52
  // apps/backend/src/query/query.service.ts#search. Used by evrex_search,
53
53
  // which wants ranked hits fast, not a synthesized paragraph.
54
- search: (repoPath, text, filePaths) => post("/search", { repoPath, text, filePaths }),
54
+ search: (repoPath, text, filePaths, boost) => post("/search", { repoPath, text, filePaths, boost }),
55
55
  // Everything that happened in a repo, newest first, bounded by days — the
56
56
  // same query the desktop Timeline screen makes. Sessions and commits
57
57
  // interleaved, each with the handle evrex_expand takes.
@@ -62,6 +62,7 @@ var evrexApi = {
62
62
  };
63
63
 
64
64
  // src/hook-runtime.ts
65
+ import { execFileSync } from "node:child_process";
65
66
  function readStdin() {
66
67
  return new Promise((resolve) => {
67
68
  let raw = "";
@@ -87,7 +88,34 @@ function repoMatchForCwd(repos, cwd) {
87
88
  }
88
89
  }
89
90
  }
90
- return best;
91
+ if (best) return best;
92
+ const hop = worktreeHop(cwd);
93
+ if (!hop) return null;
94
+ for (const repo of repos) {
95
+ for (const path of repo.localPaths ?? []) {
96
+ if (!path) continue;
97
+ if (hop.main === path || hop.main.startsWith(`${path}/`)) {
98
+ return { id: repo.id, root: hop.top };
99
+ }
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+ function worktreeHop(cwd) {
105
+ try {
106
+ const raw = execFileSync(
107
+ "git",
108
+ ["-C", cwd, "rev-parse", "--git-common-dir", "--show-toplevel"],
109
+ { stdio: ["ignore", "pipe", "ignore"], timeout: 1500 }
110
+ ).toString("utf-8").trim().split("\n");
111
+ const [gitDir, top] = [raw[0] ?? "", raw[1] ?? ""];
112
+ if (!gitDir.startsWith("/") || !gitDir.endsWith("/.git") || !top) return null;
113
+ const main2 = gitDir.slice(0, -"/.git".length);
114
+ if (!main2 || main2 === top) return null;
115
+ return { main: main2, top };
116
+ } catch {
117
+ return null;
118
+ }
91
119
  }
92
120
  function repoForCwd(repos, cwd) {
93
121
  return repoMatchForCwd(repos, cwd)?.id ?? null;
@@ -258,7 +286,7 @@ function ago(iso, now = /* @__PURE__ */ new Date()) {
258
286
  }
259
287
  function currentBranch(cwd) {
260
288
  try {
261
- const out = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
289
+ const out = execFileSync2("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
262
290
  cwd,
263
291
  stdio: ["ignore", "pipe", "ignore"],
264
292
  timeout: 1e3
package/dist/hook.js CHANGED
@@ -49,7 +49,7 @@ var evrexApi = {
49
49
  // Evidence-only retrieval (BM25 + embedding), no LLM synthesis call — see
50
50
  // apps/backend/src/query/query.service.ts#search. Used by evrex_search,
51
51
  // which wants ranked hits fast, not a synthesized paragraph.
52
- search: (repoPath, text, filePaths) => post("/search", { repoPath, text, filePaths }),
52
+ search: (repoPath, text, filePaths, boost) => post("/search", { repoPath, text, filePaths, boost }),
53
53
  // Everything that happened in a repo, newest first, bounded by days — the
54
54
  // same query the desktop Timeline screen makes. Sessions and commits
55
55
  // interleaved, each with the handle evrex_expand takes.
@@ -86,7 +86,34 @@ function repoMatchForCwd(repos, cwd) {
86
86
  }
87
87
  }
88
88
  }
89
- return best;
89
+ if (best) return best;
90
+ const hop = worktreeHop(cwd);
91
+ if (!hop) return null;
92
+ for (const repo of repos) {
93
+ for (const path of repo.localPaths ?? []) {
94
+ if (!path) continue;
95
+ if (hop.main === path || hop.main.startsWith(`${path}/`)) {
96
+ return { id: repo.id, root: hop.top };
97
+ }
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+ function worktreeHop(cwd) {
103
+ try {
104
+ const raw = execFileSync(
105
+ "git",
106
+ ["-C", cwd, "rev-parse", "--git-common-dir", "--show-toplevel"],
107
+ { stdio: ["ignore", "pipe", "ignore"], timeout: 1500 }
108
+ ).toString("utf-8").trim().split("\n");
109
+ const [gitDir, top] = [raw[0] ?? "", raw[1] ?? ""];
110
+ if (!gitDir.startsWith("/") || !gitDir.endsWith("/.git") || !top) return null;
111
+ const main2 = gitDir.slice(0, -"/.git".length);
112
+ if (!main2 || main2 === top) return null;
113
+ return { main: main2, top };
114
+ } catch {
115
+ return null;
116
+ }
90
117
  }
91
118
  function repoForCwd(repos, cwd) {
92
119
  return repoMatchForCwd(repos, cwd)?.id ?? null;
@@ -245,7 +272,10 @@ async function main() {
245
272
  if (!repoId) return;
246
273
  const remaining = DEADLINE_MS - (Date.now() - started);
247
274
  if (remaining < 500) return;
248
- const result = await withDeadline(evrexApi.search(repoId, prompt), remaining);
275
+ const result = await withDeadline(
276
+ evrexApi.search(repoId, prompt, void 0, false),
277
+ remaining
278
+ );
249
279
  if (!result?.evidence?.length) return;
250
280
  const sessionId = input.session_id ?? "";
251
281
  const path = statePath();