evrex-mcp 0.8.0 → 0.8.2

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/account.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.
package/dist/capture.js CHANGED
@@ -180,17 +180,38 @@ function commitMeta(repoPath, sha) {
180
180
  const line = git(repoPath, [
181
181
  "show",
182
182
  "-s",
183
- `--format=%H${FIELD_SEP}%an${FIELD_SEP}%ae${FIELD_SEP}%aI`,
183
+ `--format=%H${FIELD_SEP}%an${FIELD_SEP}%ae${FIELD_SEP}%aI${FIELD_SEP}%P`,
184
184
  sha
185
185
  ]).trim();
186
186
  const parts = line.split(FIELD_SEP);
187
- const message = git(repoPath, ["show", "-s", "--format=%B", sha]).replace(/\n+$/, "");
187
+ const body = git(repoPath, ["show", "-s", "--notes", `--format=%B${FIELD_SEP}%N`, sha]);
188
+ const sep2 = body.indexOf(FIELD_SEP);
189
+ let message = (sep2 === -1 ? body : body.slice(0, sep2)).replace(/\n+$/, "");
190
+ const note = sep2 === -1 ? "" : body.slice(sep2 + FIELD_SEP.length);
191
+ const noted = /^Evrex-Session:\s*(\S+)\s*$/m.exec(note);
192
+ if (noted && !/^Evrex-Session:/m.test(message)) {
193
+ message = `${message}
194
+
195
+ ${noted[0].trim()}`;
196
+ }
188
197
  return {
189
198
  sha: parts[0] ?? sha,
190
199
  author: parts[1] ?? "",
191
200
  authorEmail: parts[2] ?? "",
192
201
  ts: parts[3] ?? (/* @__PURE__ */ new Date()).toISOString(),
193
- message
202
+ parents: (parts[4] ?? "").split(" ").filter(Boolean),
203
+ message,
204
+ // The note's session, exposed on its own as well as folded above. When
205
+ // the message ALREADY carries a trailer, the fold declines (never rewrite
206
+ // what was stamped at commit time) — but the parse must still prefer the
207
+ // note: it exists only because an operator pressed "verify" on a commit
208
+ // whose message trailer names a session no ingest can resolve. Commit
209
+ // 843dabb3 is the standing example — its at-commit-time trailer names a
210
+ // session with no transcript anywhere, so the folding guard alone left it
211
+ // permanently un-verifiable: every promote re-ingested the dangling id,
212
+ // bestLink demoted it below the resolvable match, and the button offered
213
+ // the same commit again.
214
+ notedSession: noted?.[1] ?? null
194
215
  };
195
216
  }
196
217
  function parseTrailers(repoPath, message) {
@@ -238,6 +259,10 @@ function trailerValue(trailers, key) {
238
259
  const k = key.toLowerCase();
239
260
  return trailers.find((t) => t.key.toLowerCase() === k)?.value ?? null;
240
261
  }
262
+ function originOf(trailers) {
263
+ const v = trailerValue(trailers, EVREX_ORIGIN_TRAILER_KEY);
264
+ return v?.trim().toLowerCase() === "human" ? "human" : null;
265
+ }
241
266
  function agentTrailersOf(trailers) {
242
267
  const out = [];
243
268
  for (const t of trailers) {
@@ -307,6 +332,9 @@ function commitFiles(repoPath, sha) {
307
332
  }
308
333
  function parseGitLog(repoPath, repoId, known) {
309
334
  const shas = listShas(repoPath).filter((sha) => !known?.has(sha));
335
+ return parseCommitsBySha(repoPath, shas, repoId);
336
+ }
337
+ function parseCommitsBySha(repoPath, shas, repoId) {
310
338
  const id = repoId ?? deriveRepoId(repoPath);
311
339
  return shas.map((sha) => {
312
340
  const meta = commitMeta(repoPath, sha);
@@ -319,15 +347,19 @@ function parseGitLog(repoPath, repoId, known) {
319
347
  authorEmail: meta.authorEmail,
320
348
  ts: meta.ts,
321
349
  message: meta.message,
350
+ parents: meta.parents,
322
351
  branch: commitBranch(repoPath, sha),
323
- evrexSessionTrailer: trailerValue(trailers, EVREX_SESSION_TRAILER_KEY),
352
+ // A note is the operator's explicit later correction, so where both
353
+ // exist it names the session — see commitMeta's notedSession.
354
+ evrexSessionTrailer: meta.notedSession ?? trailerValue(trailers, EVREX_SESSION_TRAILER_KEY),
355
+ origin: originOf(trailers),
324
356
  agentTrailers: agentTrailersOf(trailers),
325
357
  statedInsights: statedInsightsOf(trailers),
326
358
  files: commitFiles(repoPath, sha)
327
359
  };
328
360
  });
329
361
  }
330
- var DIFF_CAP, FIELD_SEP, EVREX_SESSION_TRAILER_KEY;
362
+ var DIFF_CAP, FIELD_SEP, EVREX_SESSION_TRAILER_KEY, EVREX_ORIGIN_TRAILER_KEY;
331
363
  var init_git_history = __esm({
332
364
  "../../packages/ingest-core/src/git-history.ts"() {
333
365
  "use strict";
@@ -335,6 +367,7 @@ var init_git_history = __esm({
335
367
  DIFF_CAP = 2e4;
336
368
  FIELD_SEP = "";
337
369
  EVREX_SESSION_TRAILER_KEY = "Evrex-Session";
370
+ EVREX_ORIGIN_TRAILER_KEY = "Evrex-Origin";
338
371
  }
339
372
  });
340
373
 
@@ -399,7 +432,7 @@ var PARSER_VERSION;
399
432
  var init_incremental = __esm({
400
433
  "../../packages/ingest-core/src/incremental.ts"() {
401
434
  "use strict";
402
- PARSER_VERSION = 4;
435
+ PARSER_VERSION = 7;
403
436
  }
404
437
  });
405
438
 
@@ -514,11 +547,54 @@ var init_redact = __esm({
514
547
 
515
548
  // ../../packages/ingest-core/src/subject-linking.ts
516
549
  function matchCommitToSession(commit, sessions) {
550
+ const saw = sessions.filter(
551
+ (s) => (s.committedShas ?? []).some(
552
+ (short) => short.length >= 7 && commit.sha.startsWith(short)
553
+ )
554
+ );
555
+ if (saw.length > 0) {
556
+ const oneLineage2 = saw.every((s) => s.startedAt === saw[0].startedAt);
557
+ if (!oneLineage2) {
558
+ return { sha: commit.sha, sessionId: null, reason: "ambiguous" };
559
+ }
560
+ const original2 = [...saw].sort((a, b) => a.endedAt - b.endedAt)[0];
561
+ return {
562
+ sha: commit.sha,
563
+ sessionId: original2.sessionId,
564
+ evidence: "saw-the-sha",
565
+ confidence: SHA_CONFIDENCE
566
+ };
567
+ }
517
568
  const subject = commit.subject.trim();
569
+ const prMatch = /\(#(\d+)\)$/.exec(subject) ?? /^Merge pull request #(\d+)\b/.exec(subject);
570
+ if (prMatch) {
571
+ const pr = Number(prMatch[1]);
572
+ const mergedIt = sessions.filter(
573
+ (s) => (s.mergedPrNumbers ?? []).includes(pr)
574
+ );
575
+ if (mergedIt.length > 0) {
576
+ const oneLineage2 = mergedIt.every(
577
+ (s) => s.startedAt === mergedIt[0].startedAt
578
+ );
579
+ if (!oneLineage2) {
580
+ return { sha: commit.sha, sessionId: null, reason: "ambiguous" };
581
+ }
582
+ const original2 = [...mergedIt].sort((a, b) => a.endedAt - b.endedAt)[0];
583
+ return {
584
+ sha: commit.sha,
585
+ sessionId: original2.sessionId,
586
+ evidence: "merged-the-pr",
587
+ confidence: SHA_CONFIDENCE
588
+ };
589
+ }
590
+ }
518
591
  if (subject.length === 0) {
519
592
  return { sha: commit.sha, sessionId: null, reason: "absent" };
520
593
  }
521
- const ran = sessions.filter((s) => s.committedSubjects.includes(subject));
594
+ const unsquashed = subject.replace(/\s+\(#\d+\)$/, "");
595
+ const ran = sessions.filter(
596
+ (s) => s.committedSubjects.includes(subject) || unsquashed !== subject && s.committedSubjects.includes(unsquashed)
597
+ );
522
598
  if (ran.length === 0) {
523
599
  return { sha: commit.sha, sessionId: null, reason: "absent" };
524
600
  }
@@ -572,15 +648,61 @@ function committedSubjects(command) {
572
648
  if (inline) {
573
649
  const subject = inline[2].split("\n")[0].trim();
574
650
  if (subject) out.push(subject);
651
+ continue;
652
+ }
653
+ const marginal = /^[^\n]*?-am\s*(['"])([\s\S]*?)\1/.exec(rest) ?? /^[^\n]*?--message[= ]\s*(['"])([\s\S]*?)\1/.exec(rest) ?? /^[^\n]*?-m(['"])([\s\S]*?)\1/.exec(rest);
654
+ if (marginal) {
655
+ const subject = marginal[2].split("\n")[0].trim();
656
+ if (subject) out.push(subject);
657
+ continue;
658
+ }
659
+ const fromFile = /^[^\n]*?(?:-F|--file)[= ]\s*(\S+)/.exec(rest);
660
+ if (fromFile) {
661
+ const file = fromFile[1].replace(/^["']|["']$/g, "");
662
+ const escaped = file.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
663
+ const wrote = new RegExp(
664
+ `(?:cat\\s*>>?|tee\\s+(?:-a\\s+)?)\\s*["']?${escaped}["']?[^\\n]*<<-?\\s*(['"]?)(\\w+)\\1[^\\n]*\\r?\\n([^\\n]*)`
665
+ ).exec(command.slice(0, found.index));
666
+ if (wrote) {
667
+ const subject = wrote[3].trim();
668
+ if (subject) out.push(subject);
669
+ }
575
670
  }
576
671
  }
577
672
  return out;
578
673
  }
579
- var INFERRED_CONFIDENCE;
674
+ function mergeResponseShas(output) {
675
+ const out = /* @__PURE__ */ new Set();
676
+ const line = /"sha"\s*:\s*"([0-9a-f]{40})"/g;
677
+ for (let m = line.exec(output); m !== null; m = line.exec(output)) {
678
+ out.add(m[1]);
679
+ }
680
+ return [...out];
681
+ }
682
+ function commitShaOutputs(output) {
683
+ const out = /* @__PURE__ */ new Set();
684
+ const line = /\[[\w./+-]+ (?:\(root-commit\) )?([0-9a-f]{7,12})\]/g;
685
+ for (let m = line.exec(output); m !== null; m = line.exec(output)) {
686
+ out.add(m[1]);
687
+ }
688
+ return [...out];
689
+ }
690
+ function mergedPrFromCommand(command) {
691
+ const api = /\/pulls\/(\d+)\/merge\b/.exec(command);
692
+ if (api) return Number(api[1]);
693
+ const gh = /\bgh\s+pr\s+merge\s+(?:.*?\/pull\/(\d+)\b|(\d+)\b)/.exec(command);
694
+ if (gh) return Number(gh[1] ?? gh[2]);
695
+ return null;
696
+ }
697
+ function mergeSucceeded(output) {
698
+ return /"merged"\s*:\s*true/.test(output) || /(Squashed and |Rebased and )?[Mm]erged pull request #\d+/.test(output);
699
+ }
700
+ var INFERRED_CONFIDENCE, SHA_CONFIDENCE;
580
701
  var init_subject_linking = __esm({
581
702
  "../../packages/ingest-core/src/subject-linking.ts"() {
582
703
  "use strict";
583
704
  INFERRED_CONFIDENCE = 0.9;
705
+ SHA_CONFIDENCE = 0.95;
584
706
  }
585
707
  });
586
708
 
@@ -811,6 +933,7 @@ function parseSessionFile(filePath, repoPath, repoId = deriveRepoId(repoPath), a
811
933
  let totalRedactions = 0;
812
934
  let branch = null;
813
935
  let agentId = null;
936
+ const seenIds = /* @__PURE__ */ new Set();
814
937
  for (const line of lines) {
815
938
  let record;
816
939
  try {
@@ -826,6 +949,8 @@ function parseSessionFile(filePath, repoPath, repoId = deriveRepoId(repoPath), a
826
949
  const id = record.uuid;
827
950
  const ts = record.timestamp;
828
951
  if (!id || !ts) continue;
952
+ if (seenIds.has(id)) continue;
953
+ seenIds.add(id);
829
954
  sessionId ??= record.sessionId ?? record.session_id ?? null;
830
955
  if (typeof record.gitBranch === "string" && record.gitBranch) branch = record.gitBranch;
831
956
  if (typeof record.agentId === "string" && record.agentId) agentId ??= record.agentId;
@@ -879,6 +1004,7 @@ function parseSessionFile(filePath, repoPath, repoId = deriveRepoId(repoPath), a
879
1004
  const subagent = agentId ? { agentId, agentType: meta?.agentType ?? null, description: meta?.description ?? null } : null;
880
1005
  if (agentId && !aiTitle && meta?.description) aiTitle = meta.description;
881
1006
  const sortedTs = turns.map((t) => t.ts).sort();
1007
+ const commitEvidence = collectCommitEvidence(lines);
882
1008
  const rawContent = capped ? "" : lines.map((line) => {
883
1009
  try {
884
1010
  return JSON.stringify(redactJsonValue(JSON.parse(line)).value);
@@ -902,7 +1028,9 @@ function parseSessionFile(filePath, repoPath, repoId = deriveRepoId(repoPath), a
902
1028
  // filled in by the caller — see getGitUserName in git-history.ts
903
1029
  sourceFile: filePath,
904
1030
  redactionCount: totalRedactions,
905
- committedSubjects: collectCommittedSubjects(lines),
1031
+ committedSubjects: commitEvidence.subjects,
1032
+ committedShas: commitEvidence.shas,
1033
+ mergedPrNumbers: commitEvidence.prNumbers,
906
1034
  branch,
907
1035
  parentSessionId,
908
1036
  subagent,
@@ -911,10 +1039,14 @@ function parseSessionFile(filePath, repoPath, repoId = deriveRepoId(repoPath), a
911
1039
  turns
912
1040
  };
913
1041
  }
914
- function collectCommittedSubjects(lines) {
1042
+ function collectCommitEvidence(lines) {
915
1043
  const subjects = /* @__PURE__ */ new Set();
1044
+ const shas = /* @__PURE__ */ new Set();
1045
+ const prNumbers = /* @__PURE__ */ new Set();
1046
+ const commitCallIds = /* @__PURE__ */ new Set();
1047
+ const mergeCallIds = /* @__PURE__ */ new Map();
916
1048
  for (const line of lines) {
917
- if (!line.includes("git commit")) continue;
1049
+ if (!line.includes("git commit") && !line.includes("/merge") && !line.includes("tool_use_id")) continue;
918
1050
  let record;
919
1051
  try {
920
1052
  record = JSON.parse(line);
@@ -924,13 +1056,40 @@ function collectCommittedSubjects(lines) {
924
1056
  const content = record?.message?.content;
925
1057
  if (!Array.isArray(content)) continue;
926
1058
  for (const block of content) {
927
- if (block?.type !== "tool_use") continue;
928
- const command = block?.input?.command;
929
- if (typeof command !== "string") continue;
930
- for (const subject of committedSubjects(command)) subjects.add(subject);
1059
+ if (block?.type === "tool_use") {
1060
+ const command = block?.input?.command;
1061
+ if (typeof command !== "string") continue;
1062
+ const found = committedSubjects(command);
1063
+ for (const subject of found) subjects.add(subject);
1064
+ if (/\bgit\s+(?:-C\s+\S+\s+)?commit\b/.test(command) && typeof block?.id === "string") {
1065
+ commitCallIds.add(block.id);
1066
+ }
1067
+ if ((/\/pulls\/\d+\/merge\b/.test(command) || /\bgh\s+pr\s+merge\b/.test(command)) && typeof block?.id === "string") {
1068
+ mergeCallIds.set(block.id, mergedPrFromCommand(command));
1069
+ }
1070
+ continue;
1071
+ }
1072
+ if (block?.type === "tool_result" && mergeCallIds.has(block?.tool_use_id)) {
1073
+ const raw = block?.content;
1074
+ const text = typeof raw === "string" ? raw : Array.isArray(raw) ? raw.map(
1075
+ (x) => typeof x?.text === "string" ? x.text : ""
1076
+ ).join(" ") : "";
1077
+ for (const sha of mergeResponseShas(text)) shas.add(sha);
1078
+ if (mergeSucceeded(text)) {
1079
+ const pr = mergeCallIds.get(block?.tool_use_id);
1080
+ if (typeof pr === "number") prNumbers.add(pr);
1081
+ }
1082
+ }
1083
+ if (block?.type === "tool_result" && commitCallIds.has(block?.tool_use_id)) {
1084
+ const raw = block?.content;
1085
+ const text = typeof raw === "string" ? raw : Array.isArray(raw) ? raw.map(
1086
+ (x) => typeof x?.text === "string" ? x.text : ""
1087
+ ).join(" ") : "";
1088
+ for (const sha of commitShaOutputs(text)) shas.add(sha);
1089
+ }
931
1090
  }
932
1091
  }
933
- return [...subjects];
1092
+ return { subjects: [...subjects], shas: [...shas], prNumbers: [...prNumbers] };
934
1093
  }
935
1094
  function parseAllSessions(repoPath, repoId, cursors = {}) {
936
1095
  const id = repoId ?? deriveRepoId(repoPath);
@@ -1896,16 +2055,58 @@ function addUsage(into, next) {
1896
2055
  model: into.model ?? next.model
1897
2056
  };
1898
2057
  }
1899
- function committedSubjectsFromToolCalls(lines) {
2058
+ function commitEvidenceFromToolCalls(lines) {
1900
2059
  const subjects = /* @__PURE__ */ new Set();
2060
+ const shas = /* @__PURE__ */ new Set();
2061
+ const prNumbers = /* @__PURE__ */ new Set();
2062
+ const commitCallIds = /* @__PURE__ */ new Set();
2063
+ const mergeCallIds = /* @__PURE__ */ new Map();
1901
2064
  for (const line of lines) {
1902
2065
  if (line.type !== "response_item") continue;
1903
- if (payloadType(line) !== "custom_tool_call") continue;
1904
- const input = asString(line.payload?.input);
1905
- if (!input) continue;
1906
- for (const subject of committedSubjects(input)) subjects.add(subject);
2066
+ const kind = payloadType(line);
2067
+ if (kind === "custom_tool_call") {
2068
+ const input = asString(line.payload?.input);
2069
+ if (!input) continue;
2070
+ const cmd = execCmdFrom(input) ?? input;
2071
+ const callId = asString(line.payload?.call_id);
2072
+ for (const subject of committedSubjects(cmd)) subjects.add(subject);
2073
+ if (/\bgit\s+(?:-C\s+\S+\s+)?commit\b/.test(cmd) && callId) {
2074
+ commitCallIds.add(callId);
2075
+ }
2076
+ if ((/\/pulls\/\d+\/merge\b/.test(cmd) || /\bgh\s+pr\s+merge\b/.test(cmd)) && callId) {
2077
+ mergeCallIds.set(callId, mergedPrFromCommand(cmd));
2078
+ }
2079
+ continue;
2080
+ }
2081
+ if (kind === "custom_tool_call_output") {
2082
+ const callId = asString(line.payload?.call_id);
2083
+ if (!callId) continue;
2084
+ const raw = line.payload?.output;
2085
+ const text = Array.isArray(raw) ? raw.map(
2086
+ (x) => typeof x?.text === "string" ? x.text : ""
2087
+ ).join(" ") : asString(raw) ?? "";
2088
+ if (commitCallIds.has(callId)) {
2089
+ for (const sha of commitShaOutputs(text)) shas.add(sha);
2090
+ }
2091
+ if (mergeCallIds.has(callId)) {
2092
+ for (const sha of mergeResponseShas(text)) shas.add(sha);
2093
+ if (mergeSucceeded(text)) {
2094
+ const pr = mergeCallIds.get(callId);
2095
+ if (typeof pr === "number") prNumbers.add(pr);
2096
+ }
2097
+ }
2098
+ }
2099
+ }
2100
+ return { subjects: [...subjects], shas: [...shas], prNumbers: [...prNumbers] };
2101
+ }
2102
+ function execCmdFrom(input) {
2103
+ const m = /cmd\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(input);
2104
+ if (!m) return null;
2105
+ try {
2106
+ return JSON.parse(`"${m[1]}"`);
2107
+ } catch {
2108
+ return null;
1907
2109
  }
1908
- return [...subjects];
1909
2110
  }
1910
2111
  function filesFromToolCalls(lines) {
1911
2112
  const byPath = /* @__PURE__ */ new Map();
@@ -1964,20 +2165,28 @@ function parseCodexSessionFile(filePath, repoPath, repoId) {
1964
2165
  const { content: rawContent, count: rawRedactions } = redactRollout(raw);
1965
2166
  redactionCount += rawRedactions;
1966
2167
  const firstUser = events.find((e) => e.role === "user");
2168
+ const codexCommitEvidence = commitEvidenceFromToolCalls(lines);
1967
2169
  return {
1968
2170
  id: sessionId,
1969
2171
  agentKind: "codex",
1970
2172
  branch: null,
1971
2173
  parentSessionId: null,
1972
2174
  subagent: null,
1973
- // Codex records the remote itself, so identity survives a moved or deleted
1974
- // checkout. Falls back to the caller's derivation when it is absent.
1975
- repoId: repoIdFromMeta(meta) ?? repoId,
2175
+ // The caller's derivation first: it reads the checkout's remote NOW,
2176
+ // which is the identity every other ingest path agrees on. The remote
2177
+ // recorded in session_meta is a historical fact — after the repo's
2178
+ // GitHub transfer, month-old rollouts kept re-minting the dead
2179
+ // jeffcheema id on every re-index, resurrecting a "third evrex-app"
2180
+ // as fast as migrations folded it. Meta only serves a rollout whose
2181
+ // checkout is gone, where a stale identity beats none.
2182
+ repoId: repoId.startsWith("path:") ? repoIdFromMeta(meta) ?? repoId : repoId,
1976
2183
  cwd,
1977
2184
  startedAt: asString(meta.timestamp) ?? events[0]?.ts ?? null,
1978
2185
  endedAt: events[events.length - 1]?.ts ?? null,
1979
2186
  turnCount: turns.length,
1980
- committedSubjects: committedSubjectsFromToolCalls(lines),
2187
+ committedSubjects: codexCommitEvidence.subjects,
2188
+ committedShas: codexCommitEvidence.shas,
2189
+ mergedPrNumbers: codexCommitEvidence.prNumbers,
1981
2190
  aiTitle: firstUser ? firstUser.text.slice(0, 120).trim() : null,
1982
2191
  author: null,
1983
2192
  sourceFile: filePath,
@@ -2928,6 +3137,7 @@ var src_exports = {};
2928
3137
  __export(src_exports, {
2929
3138
  CONVERSATION_KINDS: () => CONVERSATION_KINDS,
2930
3139
  EMPTY_USAGE: () => EMPTY_USAGE,
3140
+ EVREX_ORIGIN_TRAILER_KEY: () => EVREX_ORIGIN_TRAILER_KEY,
2931
3141
  EVREX_SESSION_TRAILER_KEY: () => EVREX_SESSION_TRAILER_KEY,
2932
3142
  JIRA_FIELDS: () => JIRA_FIELDS,
2933
3143
  JIRA_SEARCH_PATH: () => JIRA_SEARCH_PATH,
@@ -2950,6 +3160,7 @@ __export(src_exports, {
2950
3160
  changedSessions: () => changedSessions,
2951
3161
  codexSessionsDir: () => codexSessionsDir,
2952
3162
  collectRepoData: () => collectRepoData,
3163
+ commitShaOutputs: () => commitShaOutputs,
2953
3164
  commitsOlderThan: () => commitsOlderThan,
2954
3165
  committedSubjects: () => committedSubjects,
2955
3166
  copilotSessionsDir: () => copilotSessionsDir,
@@ -2984,14 +3195,19 @@ __export(src_exports, {
2984
3195
  loadComposers: () => loadComposers,
2985
3196
  matchCommitToSession: () => matchCommitToSession,
2986
3197
  measureLineSurvival: () => measureLineSurvival,
3198
+ mergeResponseShas: () => mergeResponseShas,
3199
+ mergeSucceeded: () => mergeSucceeded,
3200
+ mergedPrFromCommand: () => mergedPrFromCommand,
2987
3201
  normalizeRepoRemote: () => normalizeRepoRemote,
2988
3202
  opencodeDbPath: () => opencodeDbPath,
3203
+ originOf: () => originOf,
2989
3204
  parseAllCodexSessions: () => parseAllCodexSessions,
2990
3205
  parseAllCopilotSessions: () => parseAllCopilotSessions,
2991
3206
  parseAllCursorSessions: () => parseAllCursorSessions,
2992
3207
  parseAllOpenCodeSessions: () => parseAllOpenCodeSessions,
2993
3208
  parseAllSessions: () => parseAllSessions,
2994
3209
  parseCodexSessionFile: () => parseCodexSessionFile,
3210
+ parseCommitsBySha: () => parseCommitsBySha,
2995
3211
  parseCopilotSessionDir: () => parseCopilotSessionDir,
2996
3212
  parseCopilotWorkspace: () => parseCopilotWorkspace,
2997
3213
  parseCursorComposer: () => parseCursorComposer,
@@ -3158,7 +3374,7 @@ var init_client = __esm({
3158
3374
  // Evidence-only retrieval (BM25 + embedding), no LLM synthesis call — see
3159
3375
  // apps/backend/src/query/query.service.ts#search. Used by evrex_search,
3160
3376
  // which wants ranked hits fast, not a synthesized paragraph.
3161
- search: (repoPath, text, filePaths) => post("/search", { repoPath, text, filePaths }),
3377
+ search: (repoPath, text, filePaths, boost) => post("/search", { repoPath, text, filePaths, boost }),
3162
3378
  // Everything that happened in a repo, newest first, bounded by days — the
3163
3379
  // same query the desktop Timeline screen makes. Sessions and commits
3164
3380
  // interleaved, each with the handle evrex_expand takes.
@@ -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.
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.
@@ -245,7 +245,10 @@ async function main() {
245
245
  if (!repoId) return;
246
246
  const remaining = DEADLINE_MS - (Date.now() - started);
247
247
  if (remaining < 500) return;
248
- const result = await withDeadline(evrexApi.search(repoId, prompt), remaining);
248
+ const result = await withDeadline(
249
+ evrexApi.search(repoId, prompt, void 0, false),
250
+ remaining
251
+ );
249
252
  if (!result?.evidence?.length) return;
250
253
  const sessionId = input.session_id ?? "";
251
254
  const path = statePath();