opencode-codebase-index 0.13.1 → 0.14.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.
@@ -495,7 +495,7 @@ var require_ignore = __commonJS({
495
495
  // path matching.
496
496
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
497
497
  // @returns {TestResult} true if a file is ignored
498
- test(path15, checkUnignored, mode) {
498
+ test(path16, checkUnignored, mode) {
499
499
  let ignored = false;
500
500
  let unignored = false;
501
501
  let matchedRule;
@@ -504,7 +504,7 @@ var require_ignore = __commonJS({
504
504
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
505
505
  return;
506
506
  }
507
- const matched = rule[mode].test(path15);
507
+ const matched = rule[mode].test(path16);
508
508
  if (!matched) {
509
509
  return;
510
510
  }
@@ -525,17 +525,17 @@ var require_ignore = __commonJS({
525
525
  var throwError = (message, Ctor) => {
526
526
  throw new Ctor(message);
527
527
  };
528
- var checkPath = (path15, originalPath, doThrow) => {
529
- if (!isString(path15)) {
528
+ var checkPath = (path16, originalPath, doThrow) => {
529
+ if (!isString(path16)) {
530
530
  return doThrow(
531
531
  `path must be a string, but got \`${originalPath}\``,
532
532
  TypeError
533
533
  );
534
534
  }
535
- if (!path15) {
535
+ if (!path16) {
536
536
  return doThrow(`path must not be empty`, TypeError);
537
537
  }
538
- if (checkPath.isNotRelative(path15)) {
538
+ if (checkPath.isNotRelative(path16)) {
539
539
  const r = "`path.relative()`d";
540
540
  return doThrow(
541
541
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -544,7 +544,7 @@ var require_ignore = __commonJS({
544
544
  }
545
545
  return true;
546
546
  };
547
- var isNotRelative = (path15) => REGEX_TEST_INVALID_PATH.test(path15);
547
+ var isNotRelative = (path16) => REGEX_TEST_INVALID_PATH.test(path16);
548
548
  checkPath.isNotRelative = isNotRelative;
549
549
  checkPath.convert = (p) => p;
550
550
  var Ignore2 = class {
@@ -574,19 +574,19 @@ var require_ignore = __commonJS({
574
574
  }
575
575
  // @returns {TestResult}
576
576
  _test(originalPath, cache, checkUnignored, slices) {
577
- const path15 = originalPath && checkPath.convert(originalPath);
577
+ const path16 = originalPath && checkPath.convert(originalPath);
578
578
  checkPath(
579
- path15,
579
+ path16,
580
580
  originalPath,
581
581
  this._strictPathCheck ? throwError : RETURN_FALSE
582
582
  );
583
- return this._t(path15, cache, checkUnignored, slices);
583
+ return this._t(path16, cache, checkUnignored, slices);
584
584
  }
585
- checkIgnore(path15) {
586
- if (!REGEX_TEST_TRAILING_SLASH.test(path15)) {
587
- return this.test(path15);
585
+ checkIgnore(path16) {
586
+ if (!REGEX_TEST_TRAILING_SLASH.test(path16)) {
587
+ return this.test(path16);
588
588
  }
589
- const slices = path15.split(SLASH).filter(Boolean);
589
+ const slices = path16.split(SLASH).filter(Boolean);
590
590
  slices.pop();
591
591
  if (slices.length) {
592
592
  const parent = this._t(
@@ -599,18 +599,18 @@ var require_ignore = __commonJS({
599
599
  return parent;
600
600
  }
601
601
  }
602
- return this._rules.test(path15, false, MODE_CHECK_IGNORE);
602
+ return this._rules.test(path16, false, MODE_CHECK_IGNORE);
603
603
  }
604
- _t(path15, cache, checkUnignored, slices) {
605
- if (path15 in cache) {
606
- return cache[path15];
604
+ _t(path16, cache, checkUnignored, slices) {
605
+ if (path16 in cache) {
606
+ return cache[path16];
607
607
  }
608
608
  if (!slices) {
609
- slices = path15.split(SLASH).filter(Boolean);
609
+ slices = path16.split(SLASH).filter(Boolean);
610
610
  }
611
611
  slices.pop();
612
612
  if (!slices.length) {
613
- return cache[path15] = this._rules.test(path15, checkUnignored, MODE_IGNORE);
613
+ return cache[path16] = this._rules.test(path16, checkUnignored, MODE_IGNORE);
614
614
  }
615
615
  const parent = this._t(
616
616
  slices.join(SLASH) + SLASH,
@@ -618,29 +618,29 @@ var require_ignore = __commonJS({
618
618
  checkUnignored,
619
619
  slices
620
620
  );
621
- return cache[path15] = parent.ignored ? parent : this._rules.test(path15, checkUnignored, MODE_IGNORE);
621
+ return cache[path16] = parent.ignored ? parent : this._rules.test(path16, checkUnignored, MODE_IGNORE);
622
622
  }
623
- ignores(path15) {
624
- return this._test(path15, this._ignoreCache, false).ignored;
623
+ ignores(path16) {
624
+ return this._test(path16, this._ignoreCache, false).ignored;
625
625
  }
626
626
  createFilter() {
627
- return (path15) => !this.ignores(path15);
627
+ return (path16) => !this.ignores(path16);
628
628
  }
629
629
  filter(paths) {
630
630
  return makeArray(paths).filter(this.createFilter());
631
631
  }
632
632
  // @returns {TestResult}
633
- test(path15) {
634
- return this._test(path15, this._testCache, true);
633
+ test(path16) {
634
+ return this._test(path16, this._testCache, true);
635
635
  }
636
636
  };
637
637
  var factory = (options) => new Ignore2(options);
638
- var isPathValid = (path15) => checkPath(path15 && checkPath.convert(path15), path15, RETURN_FALSE);
638
+ var isPathValid = (path16) => checkPath(path16 && checkPath.convert(path16), path16, RETURN_FALSE);
639
639
  var setupWindows = () => {
640
640
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
641
641
  checkPath.convert = makePosix;
642
642
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
643
- checkPath.isNotRelative = (path15) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path15) || isNotRelative(path15);
643
+ checkPath.isNotRelative = (path16) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path16) || isNotRelative(path16);
644
644
  };
645
645
  if (
646
646
  // Detect `process` so that it can run in browsers.
@@ -661,7 +661,7 @@ __export(pi_extension_exports, {
661
661
  default: () => codebaseIndexPiExtension
662
662
  });
663
663
  module.exports = __toCommonJS(pi_extension_exports);
664
- var import_typebox = require("typebox");
664
+ var import_typebox2 = require("typebox");
665
665
 
666
666
  // src/config/constants.ts
667
667
  var DEFAULT_INCLUDE = [
@@ -793,7 +793,8 @@ function getDefaultIndexingConfig() {
793
793
  requireProjectMarker: true,
794
794
  maxDepth: 5,
795
795
  maxFilesPerDirectory: 100,
796
- fallbackToTextOnMaxChunks: true
796
+ fallbackToTextOnMaxChunks: true,
797
+ gitBlame: { enabled: false }
797
798
  };
798
799
  }
799
800
  function getDefaultSearchConfig() {
@@ -917,7 +918,10 @@ function parseConfig(raw) {
917
918
  requireProjectMarker: typeof rawIndexing.requireProjectMarker === "boolean" ? rawIndexing.requireProjectMarker : defaultIndexing.requireProjectMarker,
918
919
  maxDepth: typeof rawIndexing.maxDepth === "number" ? rawIndexing.maxDepth < -1 ? -1 : rawIndexing.maxDepth : defaultIndexing.maxDepth,
919
920
  maxFilesPerDirectory: typeof rawIndexing.maxFilesPerDirectory === "number" ? Math.max(1, rawIndexing.maxFilesPerDirectory) : defaultIndexing.maxFilesPerDirectory,
920
- fallbackToTextOnMaxChunks: typeof rawIndexing.fallbackToTextOnMaxChunks === "boolean" ? rawIndexing.fallbackToTextOnMaxChunks : defaultIndexing.fallbackToTextOnMaxChunks
921
+ fallbackToTextOnMaxChunks: typeof rawIndexing.fallbackToTextOnMaxChunks === "boolean" ? rawIndexing.fallbackToTextOnMaxChunks : defaultIndexing.fallbackToTextOnMaxChunks,
922
+ gitBlame: {
923
+ enabled: rawIndexing.gitBlame && typeof rawIndexing.gitBlame === "object" && typeof rawIndexing.gitBlame.enabled === "boolean" ? rawIndexing.gitBlame.enabled : defaultIndexing.gitBlame.enabled
924
+ }
921
925
  };
922
926
  const rawSearch = input.search && typeof input.search === "object" ? input.search : {};
923
927
  const search = {
@@ -1334,7 +1338,7 @@ function formatPrImpact(result) {
1334
1338
 
1335
1339
  // src/tools/operations.ts
1336
1340
  var import_fs9 = require("fs");
1337
- var path14 = __toESM(require("path"), 1);
1341
+ var path15 = __toESM(require("path"), 1);
1338
1342
 
1339
1343
  // src/config/merger.ts
1340
1344
  var import_fs5 = require("fs");
@@ -1504,21 +1508,21 @@ function getProjectIndexRelativePath(host) {
1504
1508
  return CODEBASE_PROJECT_INDEX_RELATIVE_PATH;
1505
1509
  }
1506
1510
  }
1507
- function resolveWorktreeFallbackPath(projectRoot2, relativePath) {
1508
- const mainRepoRoot = resolveWorktreeMainRepoRoot(projectRoot2);
1511
+ function resolveWorktreeFallbackPath(projectRoot3, relativePath) {
1512
+ const mainRepoRoot = resolveWorktreeMainRepoRoot(projectRoot3);
1509
1513
  if (!mainRepoRoot) {
1510
1514
  return null;
1511
1515
  }
1512
1516
  const fallbackPath = path4.join(mainRepoRoot, relativePath);
1513
1517
  return (0, import_fs4.existsSync)(fallbackPath) ? fallbackPath : null;
1514
1518
  }
1515
- function resolveWorktreeFallbackProjectIndexPath(projectRoot2, host) {
1516
- const inheritedHostPath = resolveWorktreeFallbackPath(projectRoot2, getProjectIndexRelativePath(host));
1519
+ function resolveWorktreeFallbackProjectIndexPath(projectRoot3, host) {
1520
+ const inheritedHostPath = resolveWorktreeFallbackPath(projectRoot3, getProjectIndexRelativePath(host));
1517
1521
  if (inheritedHostPath) {
1518
1522
  return inheritedHostPath;
1519
1523
  }
1520
1524
  if (host !== "opencode") {
1521
- return resolveWorktreeFallbackPath(projectRoot2, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
1525
+ return resolveWorktreeFallbackPath(projectRoot3, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
1522
1526
  }
1523
1527
  return null;
1524
1528
  }
@@ -1528,8 +1532,8 @@ function getHostProjectConfigRelativePath(host) {
1528
1532
  function getHostProjectIndexRelativePath(host) {
1529
1533
  return getProjectIndexRelativePath(host);
1530
1534
  }
1531
- function hasHostProjectConfig(projectRoot2, host) {
1532
- return (0, import_fs4.existsSync)(path4.join(projectRoot2, getProjectConfigRelativePath(host)));
1535
+ function hasHostProjectConfig(projectRoot3, host) {
1536
+ return (0, import_fs4.existsSync)(path4.join(projectRoot3, getProjectConfigRelativePath(host)));
1533
1537
  }
1534
1538
  function getGlobalIndexPath(host = "opencode") {
1535
1539
  switch (host) {
@@ -1577,55 +1581,55 @@ function resolveGlobalIndexPath(host = "opencode") {
1577
1581
  }
1578
1582
  return hostIndexPath;
1579
1583
  }
1580
- function resolveProjectConfigPath(projectRoot2, host = "opencode") {
1581
- const hostConfigPath = path4.join(projectRoot2, getProjectConfigRelativePath(host));
1584
+ function resolveProjectConfigPath(projectRoot3, host = "opencode") {
1585
+ const hostConfigPath = path4.join(projectRoot3, getProjectConfigRelativePath(host));
1582
1586
  if ((0, import_fs4.existsSync)(hostConfigPath)) {
1583
1587
  return hostConfigPath;
1584
1588
  }
1585
1589
  if (host !== "opencode") {
1586
- const legacyConfigPath = path4.join(projectRoot2, OPENCODE_PROJECT_CONFIG_RELATIVE_PATH);
1590
+ const legacyConfigPath = path4.join(projectRoot3, OPENCODE_PROJECT_CONFIG_RELATIVE_PATH);
1587
1591
  if ((0, import_fs4.existsSync)(legacyConfigPath)) {
1588
1592
  return legacyConfigPath;
1589
1593
  }
1590
1594
  }
1591
- const hostFallback = resolveWorktreeFallbackPath(projectRoot2, getProjectConfigRelativePath(host));
1595
+ const hostFallback = resolveWorktreeFallbackPath(projectRoot3, getProjectConfigRelativePath(host));
1592
1596
  if (hostFallback) {
1593
1597
  return hostFallback;
1594
1598
  }
1595
1599
  if (host !== "opencode") {
1596
- const legacyFallback = resolveWorktreeFallbackPath(projectRoot2, OPENCODE_PROJECT_CONFIG_RELATIVE_PATH);
1600
+ const legacyFallback = resolveWorktreeFallbackPath(projectRoot3, OPENCODE_PROJECT_CONFIG_RELATIVE_PATH);
1597
1601
  if (legacyFallback) {
1598
1602
  return legacyFallback;
1599
1603
  }
1600
1604
  }
1601
1605
  return hostConfigPath;
1602
1606
  }
1603
- function resolveWritableProjectConfigPath(projectRoot2, host = "opencode") {
1604
- return path4.join(projectRoot2, getProjectConfigRelativePath(host));
1607
+ function resolveWritableProjectConfigPath(projectRoot3, host = "opencode") {
1608
+ return path4.join(projectRoot3, getProjectConfigRelativePath(host));
1605
1609
  }
1606
- function resolveProjectIndexPath(projectRoot2, scope, host = "opencode") {
1610
+ function resolveProjectIndexPath(projectRoot3, scope, host = "opencode") {
1607
1611
  if (scope === "global") {
1608
1612
  return resolveGlobalIndexPath(host);
1609
1613
  }
1610
- const localIndexPath = path4.join(projectRoot2, getProjectIndexRelativePath(host));
1614
+ const localIndexPath = path4.join(projectRoot3, getProjectIndexRelativePath(host));
1611
1615
  if ((0, import_fs4.existsSync)(localIndexPath)) {
1612
1616
  return localIndexPath;
1613
1617
  }
1614
1618
  if (host !== "opencode") {
1615
- const legacyIndexPath = path4.join(projectRoot2, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
1616
- if ((0, import_fs4.existsSync)(legacyIndexPath) && !hasHostProjectConfig(projectRoot2, host)) {
1619
+ const legacyIndexPath = path4.join(projectRoot3, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
1620
+ if ((0, import_fs4.existsSync)(legacyIndexPath) && !hasHostProjectConfig(projectRoot3, host)) {
1617
1621
  return legacyIndexPath;
1618
1622
  }
1619
1623
  }
1620
- if (hasHostProjectConfig(projectRoot2, host)) {
1624
+ if (hasHostProjectConfig(projectRoot3, host)) {
1621
1625
  return localIndexPath;
1622
1626
  }
1623
- const hostFallback = resolveWorktreeFallbackPath(projectRoot2, getProjectIndexRelativePath(host));
1627
+ const hostFallback = resolveWorktreeFallbackPath(projectRoot3, getProjectIndexRelativePath(host));
1624
1628
  if (hostFallback) {
1625
1629
  return hostFallback;
1626
1630
  }
1627
1631
  if (host !== "opencode") {
1628
- const legacyFallback = resolveWorktreeFallbackPath(projectRoot2, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
1632
+ const legacyFallback = resolveWorktreeFallbackPath(projectRoot3, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
1629
1633
  if (legacyFallback) {
1630
1634
  return legacyFallback;
1631
1635
  }
@@ -1758,14 +1762,14 @@ function loadJsonFile(filePath) {
1758
1762
  throw new Error(`Failed to load config file ${filePath}: ${message}`);
1759
1763
  }
1760
1764
  }
1761
- function materializeLocalProjectConfig(projectRoot2, config, host = "opencode") {
1762
- const localConfigPath = resolveWritableProjectConfigPath(projectRoot2, host);
1765
+ function materializeLocalProjectConfig(projectRoot3, config, host = "opencode") {
1766
+ const localConfigPath = resolveWritableProjectConfigPath(projectRoot3, host);
1763
1767
  (0, import_fs5.mkdirSync)(path7.dirname(localConfigPath), { recursive: true });
1764
1768
  (0, import_fs5.writeFileSync)(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
1765
1769
  return localConfigPath;
1766
1770
  }
1767
- function loadProjectConfigLayer(projectRoot2, host = "opencode") {
1768
- const projectConfigPath = resolveProjectConfigPath(projectRoot2, host);
1771
+ function loadProjectConfigLayer(projectRoot3, host = "opencode") {
1772
+ const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
1769
1773
  const projectConfig = loadJsonFile(projectConfigPath);
1770
1774
  if (!projectConfig) {
1771
1775
  return {};
@@ -1776,14 +1780,14 @@ function loadProjectConfigLayer(projectRoot2, host = "opencode") {
1776
1780
  normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
1777
1781
  normalizedConfig.knowledgeBases,
1778
1782
  projectConfigBaseDir,
1779
- projectRoot2
1783
+ projectRoot3
1780
1784
  );
1781
1785
  }
1782
1786
  return normalizedConfig;
1783
1787
  }
1784
- function loadMergedConfig(projectRoot2, host = "opencode") {
1788
+ function loadMergedConfig(projectRoot3, host = "opencode") {
1785
1789
  const globalConfigPath = resolveGlobalConfigPath(host);
1786
- const projectConfigPath = resolveProjectConfigPath(projectRoot2, host);
1790
+ const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
1787
1791
  let globalConfig = null;
1788
1792
  let globalConfigError = null;
1789
1793
  try {
@@ -1792,7 +1796,7 @@ function loadMergedConfig(projectRoot2, host = "opencode") {
1792
1796
  globalConfigError = error instanceof Error ? error : new Error(String(error));
1793
1797
  }
1794
1798
  const projectConfig = loadJsonFile(projectConfigPath);
1795
- const normalizedProjectConfig = loadProjectConfigLayer(projectRoot2, host);
1799
+ const normalizedProjectConfig = loadProjectConfigLayer(projectRoot3, host);
1796
1800
  if (globalConfigError) {
1797
1801
  if (!projectConfig) {
1798
1802
  throw globalConfigError;
@@ -1836,10 +1840,10 @@ function loadMergedConfig(projectRoot2, host = "opencode") {
1836
1840
 
1837
1841
  // src/indexer/index.ts
1838
1842
  var import_fs7 = require("fs");
1839
- var path11 = __toESM(require("path"), 1);
1843
+ var path12 = __toESM(require("path"), 1);
1840
1844
  var import_perf_hooks = require("perf_hooks");
1841
- var import_child_process2 = require("child_process");
1842
- var import_util2 = require("util");
1845
+ var import_child_process3 = require("child_process");
1846
+ var import_util3 = require("util");
1843
1847
 
1844
1848
  // node_modules/eventemitter3/index.mjs
1845
1849
  var import_index = __toESM(require_eventemitter3(), 1);
@@ -3147,10 +3151,10 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
3147
3151
  }
3148
3152
  const batchResults = await Promise.all(
3149
3153
  batches.map(async (batch) => {
3150
- const requests = batch.map((text2) => ({
3154
+ const requests = batch.map((text3) => ({
3151
3155
  model: `models/${this.modelInfo.model}`,
3152
3156
  content: {
3153
- parts: [{ text: text2 }]
3157
+ parts: [{ text: text3 }]
3154
3158
  },
3155
3159
  taskType,
3156
3160
  outputDimensionality: this.modelInfo.dimensions
@@ -3173,7 +3177,7 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
3173
3177
  const data = await response.json();
3174
3178
  return {
3175
3179
  embeddings: data.embeddings.map((e) => e.values),
3176
- tokensUsed: batch.reduce((sum, text2) => sum + Math.ceil(text2.length / 4), 0)
3180
+ tokensUsed: batch.reduce((sum, text3) => sum + Math.ceil(text3.length / 4), 0)
3177
3181
  };
3178
3182
  })
3179
3183
  );
@@ -3190,28 +3194,28 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
3190
3194
  constructor(credentials, modelInfo) {
3191
3195
  super(credentials, modelInfo);
3192
3196
  }
3193
- estimateTokens(text2) {
3194
- return Math.ceil(text2.length / 4);
3197
+ estimateTokens(text3) {
3198
+ return Math.ceil(text3.length / 4);
3195
3199
  }
3196
- truncateToCharLimit(text2, maxChars) {
3197
- if (text2.length <= maxChars) {
3198
- return text2;
3200
+ truncateToCharLimit(text3, maxChars) {
3201
+ if (text3.length <= maxChars) {
3202
+ return text3;
3199
3203
  }
3200
- return `${text2.slice(0, Math.max(0, maxChars - 17))}
3204
+ return `${text3.slice(0, Math.max(0, maxChars - 17))}
3201
3205
  ... [truncated]`;
3202
3206
  }
3203
3207
  isContextLengthError(error) {
3204
3208
  const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
3205
3209
  return message.includes("context length") && (message.includes("exceed") || message.includes("exceeded") || message.includes("too long")) || message.includes("input length exceeds the context length") || message.includes("context length exceeded");
3206
3210
  }
3207
- buildTruncationCandidates(text2) {
3211
+ buildTruncationCandidates(text3) {
3208
3212
  const baseMaxChars = Math.max(1, this.modelInfo.maxTokens * 4);
3209
3213
  const candidateLimits = /* @__PURE__ */ new Set();
3210
- const baselineLimit = text2.length > baseMaxChars ? baseMaxChars : Math.max(
3214
+ const baselineLimit = text3.length > baseMaxChars ? baseMaxChars : Math.max(
3211
3215
  _OllamaEmbeddingProvider.MIN_TRUNCATION_CHARS,
3212
- Math.floor(text2.length * 0.9)
3216
+ Math.floor(text3.length * 0.9)
3213
3217
  );
3214
- if (baselineLimit < text2.length) {
3218
+ if (baselineLimit < text3.length) {
3215
3219
  candidateLimits.add(baselineLimit);
3216
3220
  }
3217
3221
  for (const factor of [0.75, 0.6, 0.45, 0.35, 0.25]) {
@@ -3219,19 +3223,19 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
3219
3223
  _OllamaEmbeddingProvider.MIN_TRUNCATION_CHARS,
3220
3224
  Math.floor(baselineLimit * factor)
3221
3225
  );
3222
- if (scaledLimit < text2.length) {
3226
+ if (scaledLimit < text3.length) {
3223
3227
  candidateLimits.add(scaledLimit);
3224
3228
  }
3225
3229
  }
3226
- candidateLimits.add(Math.min(text2.length - 1, _OllamaEmbeddingProvider.MIN_TRUNCATION_CHARS));
3230
+ candidateLimits.add(Math.min(text3.length - 1, _OllamaEmbeddingProvider.MIN_TRUNCATION_CHARS));
3227
3231
  const candidates = [];
3228
3232
  const seen = /* @__PURE__ */ new Set();
3229
3233
  for (const limit of [...candidateLimits].sort((a, b) => b - a)) {
3230
- if (limit <= 0 || limit >= text2.length) {
3234
+ if (limit <= 0 || limit >= text3.length) {
3231
3235
  continue;
3232
3236
  }
3233
- const truncated = this.truncateToCharLimit(text2, limit);
3234
- if (truncated === text2 || seen.has(truncated)) {
3237
+ const truncated = this.truncateToCharLimit(text3, limit);
3238
+ if (truncated === text3 || seen.has(truncated)) {
3235
3239
  continue;
3236
3240
  }
3237
3241
  seen.add(truncated);
@@ -3239,15 +3243,15 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
3239
3243
  }
3240
3244
  return candidates;
3241
3245
  }
3242
- async embedSingleWithFallback(text2) {
3246
+ async embedSingleWithFallback(text3) {
3243
3247
  try {
3244
- return await this.embedSingle(text2);
3248
+ return await this.embedSingle(text3);
3245
3249
  } catch (error) {
3246
3250
  if (!this.isContextLengthError(error)) {
3247
3251
  throw error;
3248
3252
  }
3249
3253
  let lastError = error;
3250
- for (const truncated of this.buildTruncationCandidates(text2)) {
3254
+ for (const truncated of this.buildTruncationCandidates(text3)) {
3251
3255
  try {
3252
3256
  return await this.embedSingle(truncated);
3253
3257
  } catch (retryError) {
@@ -3260,7 +3264,7 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
3260
3264
  throw lastError;
3261
3265
  }
3262
3266
  }
3263
- async embedSingle(text2) {
3267
+ async embedSingle(text3) {
3264
3268
  const response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
3265
3269
  method: "POST",
3266
3270
  headers: {
@@ -3268,7 +3272,7 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
3268
3272
  },
3269
3273
  body: JSON.stringify({
3270
3274
  model: this.modelInfo.model,
3271
- prompt: text2,
3275
+ prompt: text3,
3272
3276
  truncate: false
3273
3277
  })
3274
3278
  });
@@ -3279,13 +3283,13 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
3279
3283
  const data = await response.json();
3280
3284
  return {
3281
3285
  embedding: data.embedding,
3282
- tokensUsed: this.estimateTokens(text2)
3286
+ tokensUsed: this.estimateTokens(text3)
3283
3287
  };
3284
3288
  }
3285
3289
  async embedBatch(texts) {
3286
3290
  const results = [];
3287
- for (const text2 of texts) {
3288
- results.push(await this.embedSingleWithFallback(text2));
3291
+ for (const text3 of texts) {
3292
+ results.push(await this.embedSingleWithFallback(text3));
3289
3293
  }
3290
3294
  return {
3291
3295
  embeddings: results.map((r) => r.embedding),
@@ -3426,7 +3430,7 @@ var SiliconFlowReranker = class {
3426
3430
  var import_ignore = __toESM(require_ignore(), 1);
3427
3431
  var import_fs6 = require("fs");
3428
3432
  var path8 = __toESM(require("path"), 1);
3429
- function createIgnoreFilter(projectRoot2) {
3433
+ function createIgnoreFilter(projectRoot3) {
3430
3434
  const ig = (0, import_ignore.default)();
3431
3435
  const defaultIgnores = [
3432
3436
  "node_modules",
@@ -3447,7 +3451,7 @@ function createIgnoreFilter(projectRoot2) {
3447
3451
  "**/*build*/**"
3448
3452
  ];
3449
3453
  ig.add(defaultIgnores);
3450
- const gitignorePath = path8.join(projectRoot2, ".gitignore");
3454
+ const gitignorePath = path8.join(projectRoot3, ".gitignore");
3451
3455
  if ((0, import_fs6.existsSync)(gitignorePath)) {
3452
3456
  const gitignoreContent = (0, import_fs6.readFileSync)(gitignorePath, "utf-8");
3453
3457
  ig.add(gitignoreContent);
@@ -3469,13 +3473,13 @@ function matchGlob(filePath, pattern) {
3469
3473
  const regex = new RegExp(`^${regexPattern}$`);
3470
3474
  return regex.test(filePath);
3471
3475
  }
3472
- async function* walkDirectory(dir, projectRoot2, includePatterns, excludePatterns, ignoreFilter, maxFileSize, skipped, options, currentDepth = 0) {
3476
+ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePatterns, ignoreFilter, maxFileSize, skipped, options, currentDepth = 0) {
3473
3477
  const entries = await import_fs6.promises.readdir(dir, { withFileTypes: true });
3474
3478
  const filesInDir = [];
3475
3479
  const subdirs = [];
3476
3480
  for (const entry of entries) {
3477
3481
  const fullPath = path8.join(dir, entry.name);
3478
- const relativePath = path8.relative(projectRoot2, fullPath);
3482
+ const relativePath = path8.relative(projectRoot3, fullPath);
3479
3483
  if (isHiddenPathSegment(entry.name)) {
3480
3484
  if (entry.isDirectory()) {
3481
3485
  skipped.push({ path: relativePath, reason: "excluded" });
@@ -3524,14 +3528,14 @@ async function* walkDirectory(dir, projectRoot2, includePatterns, excludePattern
3524
3528
  yield f;
3525
3529
  }
3526
3530
  for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
3527
- skipped.push({ path: path8.relative(projectRoot2, filesInDir[i].path), reason: "excluded" });
3531
+ skipped.push({ path: path8.relative(projectRoot3, filesInDir[i].path), reason: "excluded" });
3528
3532
  }
3529
3533
  const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
3530
3534
  if (canRecurse) {
3531
3535
  for (const sub of subdirs) {
3532
3536
  yield* walkDirectory(
3533
3537
  sub.fullPath,
3534
- projectRoot2,
3538
+ projectRoot3,
3535
3539
  includePatterns,
3536
3540
  excludePatterns,
3537
3541
  ignoreFilter,
@@ -3543,14 +3547,14 @@ async function* walkDirectory(dir, projectRoot2, includePatterns, excludePattern
3543
3547
  }
3544
3548
  }
3545
3549
  }
3546
- async function collectFiles(projectRoot2, includePatterns, excludePatterns, maxFileSize, additionalRoots, walkOptions) {
3550
+ async function collectFiles(projectRoot3, includePatterns, excludePatterns, maxFileSize, additionalRoots, walkOptions) {
3547
3551
  const opts = walkOptions ?? { maxDepth: 5, maxFilesPerDirectory: 100 };
3548
- const ignoreFilter = createIgnoreFilter(projectRoot2);
3552
+ const ignoreFilter = createIgnoreFilter(projectRoot3);
3549
3553
  const files = [];
3550
3554
  const skipped = [];
3551
3555
  for await (const file of walkDirectory(
3552
- projectRoot2,
3553
- projectRoot2,
3556
+ projectRoot3,
3557
+ projectRoot3,
3554
3558
  includePatterns,
3555
3559
  excludePatterns,
3556
3560
  ignoreFilter,
@@ -3565,7 +3569,7 @@ async function collectFiles(projectRoot2, includePatterns, excludePatterns, maxF
3565
3569
  const normalizedRoots = /* @__PURE__ */ new Set();
3566
3570
  for (const kbRoot of additionalRoots) {
3567
3571
  const resolved = path8.normalize(
3568
- path8.isAbsolute(kbRoot) ? kbRoot : path8.resolve(projectRoot2, kbRoot)
3572
+ path8.isAbsolute(kbRoot) ? kbRoot : path8.resolve(projectRoot3, kbRoot)
3569
3573
  );
3570
3574
  normalizedRoots.add(resolved);
3571
3575
  }
@@ -4132,8 +4136,8 @@ var VectorStore = class {
4132
4136
  var CHARS_PER_TOKEN = 4;
4133
4137
  var MAX_BATCH_TOKENS = 7500;
4134
4138
  var MAX_SINGLE_CHUNK_TOKENS = 2e3;
4135
- function estimateTokens(text2) {
4136
- return Math.ceil(text2.length / CHARS_PER_TOKEN);
4139
+ function estimateTokens(text3) {
4140
+ return Math.ceil(text3.length / CHARS_PER_TOKEN);
4137
4141
  }
4138
4142
  function getEmbeddingHeaderParts(chunk, filePath) {
4139
4143
  const parts = [];
@@ -4667,20 +4671,20 @@ function getErrorMessage(error) {
4667
4671
  return String(error);
4668
4672
  }
4669
4673
  async function getChangedFiles(opts) {
4670
- const { pr, branch, projectRoot: projectRoot2, baseBranch = "main" } = opts;
4674
+ const { pr, branch, projectRoot: projectRoot3, baseBranch = "main" } = opts;
4671
4675
  if (pr !== void 0) {
4672
- return getChangedFilesForPr(pr, projectRoot2, baseBranch);
4676
+ return getChangedFilesForPr(pr, projectRoot3, baseBranch);
4673
4677
  }
4674
- return getChangedFilesForBranch(branch, projectRoot2, baseBranch);
4678
+ return getChangedFilesForBranch(branch, projectRoot3, baseBranch);
4675
4679
  }
4676
- async function getChangedFilesForPr(pr, projectRoot2, baseBranch) {
4680
+ async function getChangedFilesForPr(pr, projectRoot3, baseBranch) {
4677
4681
  let headRefName;
4678
4682
  let actualBaseBranch = baseBranch;
4679
4683
  try {
4680
4684
  const { stdout } = await execFileAsync(
4681
4685
  "gh",
4682
4686
  ["pr", "view", String(pr), "--json", "headRefName,baseRefName,files"],
4683
- { cwd: projectRoot2, timeout: 3e4 }
4687
+ { cwd: projectRoot3, timeout: 3e4 }
4684
4688
  );
4685
4689
  const data = JSON.parse(stdout);
4686
4690
  headRefName = data.headRefName;
@@ -4689,7 +4693,7 @@ async function getChangedFilesForPr(pr, projectRoot2, baseBranch) {
4689
4693
  return {
4690
4694
  files: normalizeFiles(
4691
4695
  data.files.map((f) => f.path),
4692
- projectRoot2
4696
+ projectRoot3
4693
4697
  ),
4694
4698
  baseBranch: actualBaseBranch,
4695
4699
  source: "gh",
@@ -4706,49 +4710,49 @@ async function getChangedFilesForPr(pr, projectRoot2, baseBranch) {
4706
4710
  `PR #${pr} returned no usable branch or file information.`
4707
4711
  );
4708
4712
  }
4709
- const result = await getChangedFilesForBranch(headRefName, projectRoot2, actualBaseBranch);
4713
+ const result = await getChangedFilesForBranch(headRefName, projectRoot3, actualBaseBranch);
4710
4714
  return { ...result, headRefName };
4711
4715
  }
4712
- async function getChangedFilesForBranch(branch, projectRoot2, baseBranch) {
4713
- const targetBranch = branch || await getCurrentBranch2(projectRoot2);
4714
- const mergeBase = await getMergeBase(projectRoot2, baseBranch, targetBranch);
4716
+ async function getChangedFilesForBranch(branch, projectRoot3, baseBranch) {
4717
+ const targetBranch = branch || await getCurrentBranch2(projectRoot3);
4718
+ const mergeBase = await getMergeBase(projectRoot3, baseBranch, targetBranch);
4715
4719
  const { stdout } = await execFileAsync(
4716
4720
  "git",
4717
4721
  ["diff", "--name-only", `${mergeBase}...${targetBranch}`],
4718
- { cwd: projectRoot2, timeout: 3e4 }
4722
+ { cwd: projectRoot3, timeout: 3e4 }
4719
4723
  );
4720
4724
  return {
4721
- files: normalizeFiles(stdout.split("\n"), projectRoot2),
4725
+ files: normalizeFiles(stdout.split("\n"), projectRoot3),
4722
4726
  baseBranch,
4723
4727
  source: "git",
4724
4728
  headRefName: targetBranch
4725
4729
  };
4726
4730
  }
4727
- async function getCurrentBranch2(projectRoot2) {
4731
+ async function getCurrentBranch2(projectRoot3) {
4728
4732
  const { stdout } = await execFileAsync(
4729
4733
  "git",
4730
4734
  ["branch", "--show-current"],
4731
- { cwd: projectRoot2, timeout: 3e4 }
4735
+ { cwd: projectRoot3, timeout: 3e4 }
4732
4736
  );
4733
4737
  return stdout.trim() || "HEAD";
4734
4738
  }
4735
- async function getMergeBase(projectRoot2, baseBranch, branch) {
4739
+ async function getMergeBase(projectRoot3, baseBranch, branch) {
4736
4740
  const { stdout } = await execFileAsync(
4737
4741
  "git",
4738
4742
  ["merge-base", baseBranch, branch],
4739
- { cwd: projectRoot2, timeout: 3e4 }
4743
+ { cwd: projectRoot3, timeout: 3e4 }
4740
4744
  );
4741
4745
  return stdout.trim();
4742
4746
  }
4743
- function normalizeFiles(rawFiles, projectRoot2) {
4747
+ function normalizeFiles(rawFiles, projectRoot3) {
4744
4748
  const seen = /* @__PURE__ */ new Set();
4745
4749
  const result = [];
4746
4750
  for (const raw of rawFiles) {
4747
4751
  const trimmed = raw.trim();
4748
4752
  if (!trimmed) continue;
4749
- const absolute = path10.resolve(projectRoot2, trimmed);
4750
- const relative6 = path10.relative(projectRoot2, absolute);
4751
- const cleaned = relative6.startsWith("./") ? relative6.slice(2) : relative6;
4753
+ const absolute = path10.resolve(projectRoot3, trimmed);
4754
+ const relative7 = path10.relative(projectRoot3, absolute);
4755
+ const cleaned = relative7.startsWith("./") ? relative7.slice(2) : relative7;
4752
4756
  if (!seen.has(cleaned)) {
4753
4757
  seen.add(cleaned);
4754
4758
  result.push(cleaned);
@@ -4757,8 +4761,61 @@ function normalizeFiles(rawFiles, projectRoot2) {
4757
4761
  return result;
4758
4762
  }
4759
4763
 
4764
+ // src/indexer/git-blame.ts
4765
+ var import_child_process2 = require("child_process");
4766
+ var path11 = __toESM(require("path"), 1);
4767
+ var import_util2 = require("util");
4768
+ var execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
4769
+ function parseGitBlamePorcelain(output) {
4770
+ const commits = /* @__PURE__ */ new Map();
4771
+ let current;
4772
+ for (const line of output.split("\n")) {
4773
+ if (/^[0-9a-f]{40} /.test(line)) {
4774
+ const sha = line.slice(0, 40);
4775
+ current = commits.get(sha) ?? {
4776
+ sha,
4777
+ author: "",
4778
+ authorEmail: "",
4779
+ committedAt: 0,
4780
+ summary: "",
4781
+ lines: 0
4782
+ };
4783
+ commits.set(sha, current);
4784
+ continue;
4785
+ }
4786
+ if (!current) {
4787
+ continue;
4788
+ }
4789
+ if (line.startsWith("author ")) {
4790
+ current.author = line.slice("author ".length);
4791
+ } else if (line.startsWith("author-mail ")) {
4792
+ current.authorEmail = line.slice("author-mail ".length).replace(/^<|>$/g, "");
4793
+ } else if (line.startsWith("author-time ")) {
4794
+ current.committedAt = Number.parseInt(line.slice("author-time ".length), 10);
4795
+ } else if (line.startsWith("summary ")) {
4796
+ current.summary = line.slice("summary ".length);
4797
+ } else if (line.startsWith(" ")) {
4798
+ current.lines += 1;
4799
+ }
4800
+ }
4801
+ return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
4802
+ }
4803
+ async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
4804
+ const relativePath = path11.relative(projectRoot3, filePath);
4805
+ try {
4806
+ const { stdout } = await execFileAsync2(
4807
+ "git",
4808
+ ["blame", "--line-porcelain", "-L", `${startLine},${endLine}`, "--", relativePath],
4809
+ { cwd: projectRoot3, timeout: 3e4 }
4810
+ );
4811
+ return parseGitBlamePorcelain(stdout);
4812
+ } catch {
4813
+ return void 0;
4814
+ }
4815
+ }
4816
+
4760
4817
  // src/indexer/index.ts
4761
- var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab"]);
4818
+ var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab", "bash"]);
4762
4819
  var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
4763
4820
  var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
4764
4821
  "function_declaration",
@@ -4838,6 +4895,45 @@ function isSqliteCorruptionError(error) {
4838
4895
  return message.includes("database disk image is malformed") || message.includes("file is not a database") || message.includes("database schema is corrupt") || message.includes("sqlite_corrupt");
4839
4896
  }
4840
4897
  var STARTUP_WARNING_METADATA_KEY = "index.startupWarning";
4898
+ function metadataFromBlame(blame) {
4899
+ if (!blame) {
4900
+ return {};
4901
+ }
4902
+ return {
4903
+ blameSha: blame.sha,
4904
+ blameAuthor: blame.author,
4905
+ blameAuthorEmail: blame.authorEmail,
4906
+ blameCommittedAt: blame.committedAt,
4907
+ blameSummary: blame.summary
4908
+ };
4909
+ }
4910
+ function blameFromChunkData(chunk) {
4911
+ if (!chunk?.blameSha || !chunk.blameAuthor || !chunk.blameAuthorEmail || chunk.blameCommittedAt === void 0 || !chunk.blameSummary) {
4912
+ return void 0;
4913
+ }
4914
+ return {
4915
+ sha: chunk.blameSha,
4916
+ author: chunk.blameAuthor,
4917
+ authorEmail: chunk.blameAuthorEmail,
4918
+ committedAt: chunk.blameCommittedAt,
4919
+ summary: chunk.blameSummary
4920
+ };
4921
+ }
4922
+ function blameFromMetadata(metadata) {
4923
+ if (!metadata.blameSha || !metadata.blameAuthor || !metadata.blameAuthorEmail || metadata.blameCommittedAt === void 0 || !metadata.blameSummary) {
4924
+ return void 0;
4925
+ }
4926
+ return {
4927
+ sha: metadata.blameSha,
4928
+ author: metadata.blameAuthor,
4929
+ authorEmail: metadata.blameAuthorEmail,
4930
+ committedAt: metadata.blameCommittedAt,
4931
+ summary: metadata.blameSummary
4932
+ };
4933
+ }
4934
+ function hasBlameMetadata(metadata) {
4935
+ return blameFromMetadata(metadata) !== void 0;
4936
+ }
4841
4937
  var INDEX_METADATA_VERSION = "1";
4842
4938
  var EMBEDDING_STRATEGY_VERSION = "2";
4843
4939
  var RANKING_TOKEN_CACHE_LIMIT = 4096;
@@ -4881,9 +4977,9 @@ function normalizePendingChunk(rawChunk, maxChunkTokens) {
4881
4977
  };
4882
4978
  const filePath = typeof metadata.filePath === "string" ? metadata.filePath : "unknown";
4883
4979
  texts.push(
4884
- ...createEmbeddingTexts(rebuiltChunk, filePath, maxChunkTokens).map((text2) => ({
4885
- text: text2,
4886
- tokenCount: estimateTokens(text2)
4980
+ ...createEmbeddingTexts(rebuiltChunk, filePath, maxChunkTokens).map((text3) => ({
4981
+ text: text3,
4982
+ tokenCount: estimateTokens(text3)
4887
4983
  }))
4888
4984
  );
4889
4985
  } else {
@@ -4996,9 +5092,9 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
4996
5092
  return true;
4997
5093
  }
4998
5094
  function isPathWithinRoot(filePath, rootPath) {
4999
- const normalizedFilePath = path11.resolve(filePath);
5000
- const normalizedRoot = path11.resolve(rootPath);
5001
- return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path11.sep}`);
5095
+ const normalizedFilePath = path12.resolve(filePath);
5096
+ const normalizedRoot = path12.resolve(rootPath);
5097
+ return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path12.sep}`);
5002
5098
  }
5003
5099
  var rankingQueryTokenCache = /* @__PURE__ */ new Map();
5004
5100
  var rankingNameTokenCache = /* @__PURE__ */ new Map();
@@ -5114,11 +5210,11 @@ function setBoundedCache(cache, key, value) {
5114
5210
  }
5115
5211
  cache.set(key, value);
5116
5212
  }
5117
- function tokenizeTextForRanking(text2) {
5118
- if (!text2) {
5213
+ function tokenizeTextForRanking(text3) {
5214
+ if (!text3) {
5119
5215
  return /* @__PURE__ */ new Set();
5120
5216
  }
5121
- const lowered = text2.toLowerCase();
5217
+ const lowered = text3.toLowerCase();
5122
5218
  const cache = rankingQueryTokenCache.get(lowered) ?? rankingTextTokenCache.get(lowered);
5123
5219
  if (cache) {
5124
5220
  return cache;
@@ -5757,7 +5853,8 @@ function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCa
5757
5853
  chunkType,
5758
5854
  name: chunk.name ?? void 0,
5759
5855
  language: chunk.language,
5760
- hash: chunk.contentHash
5856
+ hash: chunk.contentHash,
5857
+ ...metadataFromBlame(blameFromChunkData(chunk))
5761
5858
  };
5762
5859
  const baselineScore = existing?.score ?? 0.5;
5763
5860
  candidateUnion.set(chunk.chunkId, {
@@ -5841,7 +5938,8 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
5841
5938
  chunkType,
5842
5939
  name: chunk.name ?? void 0,
5843
5940
  language: chunk.language,
5844
- hash: chunk.contentHash
5941
+ hash: chunk.contentHash,
5942
+ ...metadataFromBlame(blameFromChunkData(chunk))
5845
5943
  }
5846
5944
  });
5847
5945
  }
@@ -6010,6 +6108,21 @@ function matchesSearchFilters(candidate, options, minScore) {
6010
6108
  if (options?.chunkType && candidate.metadata.chunkType !== options.chunkType) {
6011
6109
  return false;
6012
6110
  }
6111
+ if (options?.blameAuthor) {
6112
+ const author = options.blameAuthor.toLowerCase();
6113
+ const candidateAuthor = candidate.metadata.blameAuthor?.toLowerCase();
6114
+ const candidateEmail = candidate.metadata.blameAuthorEmail?.toLowerCase();
6115
+ if (candidateAuthor !== author && candidateEmail !== author) return false;
6116
+ }
6117
+ if (options?.blameSha && !candidate.metadata.blameSha?.toLowerCase().startsWith(options.blameSha.toLowerCase())) {
6118
+ return false;
6119
+ }
6120
+ if (options?.blameSince) {
6121
+ const sinceMs = Date.parse(options.blameSince);
6122
+ if (Number.isNaN(sinceMs)) return false;
6123
+ const committedAt = candidate.metadata.blameCommittedAt;
6124
+ if (committedAt === void 0 || committedAt < Math.floor(sinceMs / 1e3)) return false;
6125
+ }
6013
6126
  return true;
6014
6127
  }
6015
6128
  function unionCandidates(semanticCandidates, keywordCandidates) {
@@ -6048,14 +6161,14 @@ var Indexer = class {
6048
6161
  querySimilarityThreshold = 0.85;
6049
6162
  indexCompatibility = null;
6050
6163
  indexingLockPath = "";
6051
- constructor(projectRoot2, config, host = "opencode") {
6052
- this.projectRoot = projectRoot2;
6164
+ constructor(projectRoot3, config, host = "opencode") {
6165
+ this.projectRoot = projectRoot3;
6053
6166
  this.config = config;
6054
6167
  this.host = host;
6055
6168
  this.indexPath = this.getIndexPath();
6056
- this.fileHashCachePath = path11.join(this.indexPath, "file-hashes.json");
6057
- this.failedBatchesPath = path11.join(this.indexPath, "failed-batches.json");
6058
- this.indexingLockPath = path11.join(this.indexPath, "indexing.lock");
6169
+ this.fileHashCachePath = path12.join(this.indexPath, "file-hashes.json");
6170
+ this.failedBatchesPath = path12.join(this.indexPath, "failed-batches.json");
6171
+ this.indexingLockPath = path12.join(this.indexPath, "indexing.lock");
6059
6172
  this.logger = initializeLogger(config.debug);
6060
6173
  }
6061
6174
  getIndexPath() {
@@ -6087,14 +6200,14 @@ var Indexer = class {
6087
6200
  }
6088
6201
  atomicWriteSync(targetPath, data) {
6089
6202
  const tempPath = `${targetPath}.tmp`;
6090
- (0, import_fs7.mkdirSync)(path11.dirname(targetPath), { recursive: true });
6203
+ (0, import_fs7.mkdirSync)(path12.dirname(targetPath), { recursive: true });
6091
6204
  (0, import_fs7.writeFileSync)(tempPath, data);
6092
6205
  (0, import_fs7.renameSync)(tempPath, targetPath);
6093
6206
  }
6094
6207
  getScopedRoots() {
6095
- const roots = /* @__PURE__ */ new Set([path11.resolve(this.projectRoot)]);
6208
+ const roots = /* @__PURE__ */ new Set([path12.resolve(this.projectRoot)]);
6096
6209
  for (const kbRoot of this.config.knowledgeBases) {
6097
- roots.add(path11.resolve(this.projectRoot, kbRoot));
6210
+ roots.add(path12.resolve(this.projectRoot, kbRoot));
6098
6211
  }
6099
6212
  return Array.from(roots);
6100
6213
  }
@@ -6103,29 +6216,29 @@ var Indexer = class {
6103
6216
  if (this.config.scope !== "global") {
6104
6217
  return branchName;
6105
6218
  }
6106
- const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
6219
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
6107
6220
  return `${projectHash}:${branchName}`;
6108
6221
  }
6109
6222
  getBranchCatalogKeyFor(branchName) {
6110
6223
  if (this.config.scope !== "global") {
6111
6224
  return branchName;
6112
6225
  }
6113
- const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
6226
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
6114
6227
  return `${projectHash}:${branchName}`;
6115
6228
  }
6116
6229
  getLegacyBranchCatalogKey() {
6117
6230
  return this.currentBranch || "default";
6118
6231
  }
6119
6232
  getLegacyMigrationMetadataKey() {
6120
- const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
6233
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
6121
6234
  return `index.globalBranchMigration.${projectHash}`;
6122
6235
  }
6123
6236
  getProjectEmbeddingStrategyMetadataKey() {
6124
- const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
6237
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
6125
6238
  return `index.embeddingStrategyVersion.${projectHash}`;
6126
6239
  }
6127
6240
  getProjectForceReembedMetadataKey() {
6128
- const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
6241
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
6129
6242
  return `index.forceReembed.${projectHash}`;
6130
6243
  }
6131
6244
  hasProjectForceReembedPending() {
@@ -6219,7 +6332,7 @@ var Indexer = class {
6219
6332
  if (!this.database) {
6220
6333
  return { chunkIds, symbolIds };
6221
6334
  }
6222
- const projectRootPath = path11.resolve(this.projectRoot);
6335
+ const projectRootPath = path12.resolve(this.projectRoot);
6223
6336
  const projectLocalFilePaths = /* @__PURE__ */ new Set([
6224
6337
  ...Array.from(this.fileHashCache.keys()).filter(
6225
6338
  (filePath) => this.isFileInCurrentScope(filePath, roots) && isPathWithinRoot(filePath, projectRootPath)
@@ -6242,7 +6355,7 @@ var Indexer = class {
6242
6355
  if (this.config.scope !== "global") {
6243
6356
  return this.getBranchCatalogCleanupKeys();
6244
6357
  }
6245
- const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
6358
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
6246
6359
  const keys = /* @__PURE__ */ new Set();
6247
6360
  const projectChunkIdSet = new Set(projectChunkIds);
6248
6361
  const projectSymbolIdSet = new Set(projectSymbolIds);
@@ -6326,7 +6439,7 @@ var Indexer = class {
6326
6439
  if (!this.database || this.config.scope !== "global") {
6327
6440
  return false;
6328
6441
  }
6329
- const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
6442
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
6330
6443
  const roots = this.getScopedRoots();
6331
6444
  const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots);
6332
6445
  return this.database.getAllBranches().some(
@@ -6360,7 +6473,7 @@ var Indexer = class {
6360
6473
  ...Array.from(this.fileHashCache.keys()).filter((filePath) => this.isFileInCurrentScope(filePath, roots)),
6361
6474
  ...scopedEntries.map(({ metadata }) => metadata.filePath)
6362
6475
  ]);
6363
- const projectRootPath = path11.resolve(this.projectRoot);
6476
+ const projectRootPath = path12.resolve(this.projectRoot);
6364
6477
  const projectLocalFilePaths = new Set(
6365
6478
  Array.from(filePaths).filter((filePath) => isPathWithinRoot(filePath, projectRootPath))
6366
6479
  );
@@ -6720,13 +6833,13 @@ var Indexer = class {
6720
6833
  }
6721
6834
  await import_fs7.promises.mkdir(this.indexPath, { recursive: true });
6722
6835
  const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
6723
- const storePath = path11.join(this.indexPath, "vectors");
6836
+ const storePath = path12.join(this.indexPath, "vectors");
6724
6837
  this.store = new VectorStore(storePath, dimensions);
6725
- const indexFilePath = path11.join(this.indexPath, "vectors.usearch");
6838
+ const indexFilePath = path12.join(this.indexPath, "vectors.usearch");
6726
6839
  if ((0, import_fs7.existsSync)(indexFilePath)) {
6727
6840
  this.store.load();
6728
6841
  }
6729
- const invertedIndexPath = path11.join(this.indexPath, "inverted-index.json");
6842
+ const invertedIndexPath = path12.join(this.indexPath, "inverted-index.json");
6730
6843
  this.invertedIndex = new InvertedIndex(invertedIndexPath);
6731
6844
  try {
6732
6845
  this.invertedIndex.load();
@@ -6736,7 +6849,7 @@ var Indexer = class {
6736
6849
  }
6737
6850
  this.invertedIndex = new InvertedIndex(invertedIndexPath);
6738
6851
  }
6739
- const dbPath = path11.join(this.indexPath, "codebase.db");
6852
+ const dbPath = path12.join(this.indexPath, "codebase.db");
6740
6853
  let dbIsNew = !(0, import_fs7.existsSync)(dbPath);
6741
6854
  try {
6742
6855
  this.database = new Database(dbPath);
@@ -6817,7 +6930,7 @@ var Indexer = class {
6817
6930
  if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
6818
6931
  return {
6819
6932
  resetCorruptedIndex: true,
6820
- warning: this.getCorruptedIndexWarning(path11.join(this.indexPath, "codebase.db"))
6933
+ warning: this.getCorruptedIndexWarning(path12.join(this.indexPath, "codebase.db"))
6821
6934
  };
6822
6935
  }
6823
6936
  throw error;
@@ -6832,7 +6945,7 @@ var Indexer = class {
6832
6945
  return;
6833
6946
  }
6834
6947
  const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
6835
- const storeBasePath = path11.join(this.indexPath, "vectors");
6948
+ const storeBasePath = path12.join(this.indexPath, "vectors");
6836
6949
  const storeIndexPath = `${storeBasePath}.usearch`;
6837
6950
  const storeMetadataPath = `${storeBasePath}.meta.json`;
6838
6951
  const backupIndexPath = `${storeIndexPath}.bak`;
@@ -6917,7 +7030,7 @@ var Indexer = class {
6917
7030
  if (!isSqliteCorruptionError(error)) {
6918
7031
  return false;
6919
7032
  }
6920
- const dbPath = path11.join(this.indexPath, "codebase.db");
7033
+ const dbPath = path12.join(this.indexPath, "codebase.db");
6921
7034
  const warning = this.getCorruptedIndexWarning(dbPath);
6922
7035
  const errorMessage = getErrorMessage2(error);
6923
7036
  if (this.config.scope === "global") {
@@ -6940,15 +7053,15 @@ var Indexer = class {
6940
7053
  this.indexCompatibility = null;
6941
7054
  this.fileHashCache.clear();
6942
7055
  const resetPaths = [
6943
- path11.join(this.indexPath, "codebase.db"),
6944
- path11.join(this.indexPath, "codebase.db-shm"),
6945
- path11.join(this.indexPath, "codebase.db-wal"),
6946
- path11.join(this.indexPath, "vectors.usearch"),
6947
- path11.join(this.indexPath, "inverted-index.json"),
6948
- path11.join(this.indexPath, "file-hashes.json"),
6949
- path11.join(this.indexPath, "failed-batches.json"),
6950
- path11.join(this.indexPath, "indexing.lock"),
6951
- path11.join(this.indexPath, "vectors")
7056
+ path12.join(this.indexPath, "codebase.db"),
7057
+ path12.join(this.indexPath, "codebase.db-shm"),
7058
+ path12.join(this.indexPath, "codebase.db-wal"),
7059
+ path12.join(this.indexPath, "vectors.usearch"),
7060
+ path12.join(this.indexPath, "inverted-index.json"),
7061
+ path12.join(this.indexPath, "file-hashes.json"),
7062
+ path12.join(this.indexPath, "failed-batches.json"),
7063
+ path12.join(this.indexPath, "indexing.lock"),
7064
+ path12.join(this.indexPath, "vectors")
6952
7065
  ];
6953
7066
  await Promise.all(resetPaths.map(async (targetPath) => {
6954
7067
  try {
@@ -7185,6 +7298,7 @@ var Indexer = class {
7185
7298
  this.logger.debug("Parsed changed files", { parsedCount: parsedFiles.length, parseMs: parseMs.toFixed(2) });
7186
7299
  const existingChunks = /* @__PURE__ */ new Map();
7187
7300
  const existingChunksByFile = /* @__PURE__ */ new Map();
7301
+ const existingMetadataById = /* @__PURE__ */ new Map();
7188
7302
  for (const { key, metadata } of store.getAllMetadata()) {
7189
7303
  if (scopedRoots && !this.isFileInCurrentScope(metadata.filePath, scopedRoots)) {
7190
7304
  continue;
@@ -7193,6 +7307,7 @@ var Indexer = class {
7193
7307
  continue;
7194
7308
  }
7195
7309
  existingChunks.set(key, metadata.hash);
7310
+ existingMetadataById.set(key, metadata);
7196
7311
  const fileChunks = existingChunksByFile.get(metadata.filePath) || /* @__PURE__ */ new Set();
7197
7312
  fileChunks.add(key);
7198
7313
  existingChunksByFile.set(metadata.filePath, fileChunks);
@@ -7200,6 +7315,8 @@ var Indexer = class {
7200
7315
  const currentChunkIds = /* @__PURE__ */ new Set();
7201
7316
  const currentFilePaths = /* @__PURE__ */ new Set();
7202
7317
  const pendingChunks = [];
7318
+ const gitBlameEnabled = this.config.indexing.gitBlame.enabled && isGitRepo(this.projectRoot);
7319
+ let backfilledBlameMetadata = false;
7203
7320
  for (const filePath of unchangedFilePaths) {
7204
7321
  currentFilePaths.add(filePath);
7205
7322
  const fileChunks = existingChunksByFile.get(filePath);
@@ -7210,10 +7327,52 @@ var Indexer = class {
7210
7327
  }
7211
7328
  }
7212
7329
  const chunkDataBatch = [];
7330
+ if (gitBlameEnabled) {
7331
+ const backfillItems = [];
7332
+ for (const chunkId of currentChunkIds) {
7333
+ const metadata = existingMetadataById.get(chunkId);
7334
+ if (!metadata || hasBlameMetadata(metadata)) {
7335
+ continue;
7336
+ }
7337
+ const chunk = database.getChunk(chunkId);
7338
+ if (!chunk) {
7339
+ continue;
7340
+ }
7341
+ const blame = await getChunkGitBlame(this.projectRoot, chunk.filePath, chunk.startLine, chunk.endLine);
7342
+ const blameMetadata = metadataFromBlame(blame);
7343
+ if (!blameMetadata.blameSha) {
7344
+ continue;
7345
+ }
7346
+ chunkDataBatch.push({
7347
+ ...chunk,
7348
+ blameSha: blameMetadata.blameSha,
7349
+ blameAuthor: blameMetadata.blameAuthor,
7350
+ blameAuthorEmail: blameMetadata.blameAuthorEmail,
7351
+ blameCommittedAt: blameMetadata.blameCommittedAt,
7352
+ blameSummary: blameMetadata.blameSummary
7353
+ });
7354
+ const embeddingBuffer = database.getEmbedding(chunk.contentHash);
7355
+ if (!embeddingBuffer) {
7356
+ continue;
7357
+ }
7358
+ backfillItems.push({
7359
+ id: chunkId,
7360
+ vector: Array.from(bufferToFloat32Array(embeddingBuffer)),
7361
+ metadata: {
7362
+ ...metadata,
7363
+ ...blameMetadata
7364
+ }
7365
+ });
7366
+ }
7367
+ if (backfillItems.length > 0) {
7368
+ store.addBatch(backfillItems);
7369
+ backfilledBlameMetadata = true;
7370
+ }
7371
+ }
7213
7372
  for (const parsed of parsedFiles) {
7214
7373
  currentFilePaths.add(parsed.path);
7215
7374
  if (parsed.chunks.length === 0) {
7216
- const relativePath = path11.relative(this.projectRoot, parsed.path);
7375
+ const relativePath = path12.relative(this.projectRoot, parsed.path);
7217
7376
  stats.parseFailures.push(relativePath);
7218
7377
  }
7219
7378
  let fileChunkCount = 0;
@@ -7234,6 +7393,10 @@ var Indexer = class {
7234
7393
  }
7235
7394
  const id = generateChunkId(parsed.path, chunk);
7236
7395
  const contentHash = generateChunkHash(chunk);
7396
+ const existingContentHash = existingChunks.get(id);
7397
+ const existingChunk = gitBlameEnabled ? database.getChunk(id) : null;
7398
+ const blame = gitBlameEnabled && existingContentHash !== contentHash ? await getChunkGitBlame(this.projectRoot, parsed.path, chunk.startLine, chunk.endLine) : blameFromChunkData(existingChunk);
7399
+ const blameMetadata = metadataFromBlame(blame);
7237
7400
  currentChunkIds.add(id);
7238
7401
  chunkDataBatch.push({
7239
7402
  chunkId: id,
@@ -7243,15 +7406,20 @@ var Indexer = class {
7243
7406
  endLine: chunk.endLine,
7244
7407
  nodeType: chunk.chunkType,
7245
7408
  name: chunk.name,
7246
- language: chunk.language
7409
+ language: chunk.language,
7410
+ blameSha: blameMetadata.blameSha,
7411
+ blameAuthor: blameMetadata.blameAuthor,
7412
+ blameAuthorEmail: blameMetadata.blameAuthorEmail,
7413
+ blameCommittedAt: blameMetadata.blameCommittedAt,
7414
+ blameSummary: blameMetadata.blameSummary
7247
7415
  });
7248
- if (existingChunks.get(id) === contentHash) {
7416
+ if (existingContentHash === contentHash) {
7249
7417
  fileChunkCount++;
7250
7418
  continue;
7251
7419
  }
7252
- const texts = createEmbeddingTexts(chunk, parsed.path, getSafeEmbeddingChunkTokenLimit(configuredProviderInfo)).map((text2) => ({
7253
- text: text2,
7254
- tokenCount: estimateTokens(text2)
7420
+ const texts = createEmbeddingTexts(chunk, parsed.path, getSafeEmbeddingChunkTokenLimit(configuredProviderInfo)).map((text3) => ({
7421
+ text: text3,
7422
+ tokenCount: estimateTokens(text3)
7255
7423
  }));
7256
7424
  const metadata = {
7257
7425
  filePath: parsed.path,
@@ -7260,7 +7428,8 @@ var Indexer = class {
7260
7428
  chunkType: chunk.chunkType,
7261
7429
  name: chunk.name,
7262
7430
  language: chunk.language,
7263
- hash: contentHash
7431
+ hash: contentHash,
7432
+ ...blameMetadata
7264
7433
  };
7265
7434
  pendingChunks.push({
7266
7435
  id,
@@ -7403,6 +7572,9 @@ var Indexer = class {
7403
7572
  database.addChunksToBranchBatch(branchCatalogKey, Array.from(currentChunkIds));
7404
7573
  database.clearBranchSymbols(branchCatalogKey);
7405
7574
  database.addSymbolsToBranchBatch(branchCatalogKey, Array.from(allSymbolIds));
7575
+ if (backfilledBlameMetadata) {
7576
+ store.save();
7577
+ }
7406
7578
  if (scopedRoots) {
7407
7579
  this.replaceScopedFileHashCache(currentFileHashes, scopedRoots);
7408
7580
  this.clearScopedFailedBatches(scopedRoots);
@@ -7782,9 +7954,9 @@ var Indexer = class {
7782
7954
  }
7783
7955
  return bestMatch;
7784
7956
  }
7785
- tokenize(text2) {
7957
+ tokenize(text3) {
7786
7958
  return new Set(
7787
- text2.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((t) => t.length > 1)
7959
+ text3.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((t) => t.length > 1)
7788
7960
  );
7789
7961
  }
7790
7962
  jaccardSimilarity(a, b) {
@@ -7966,7 +8138,8 @@ var Indexer = class {
7966
8138
  content,
7967
8139
  score: r.score,
7968
8140
  chunkType: r.metadata.chunkType,
7969
- name: r.metadata.name
8141
+ name: r.metadata.name,
8142
+ blame: blameFromMetadata(r.metadata)
7970
8143
  };
7971
8144
  })
7972
8145
  );
@@ -8058,12 +8231,12 @@ var Indexer = class {
8058
8231
  this.indexCompatibility = compatibility;
8059
8232
  return;
8060
8233
  }
8061
- const localProjectIndexPaths = [path11.join(this.projectRoot, getHostProjectIndexRelativePath(this.host))];
8234
+ const localProjectIndexPaths = [path12.join(this.projectRoot, getHostProjectIndexRelativePath(this.host))];
8062
8235
  if (this.host !== "opencode") {
8063
- localProjectIndexPaths.push(path11.join(this.projectRoot, getHostProjectIndexRelativePath("opencode")));
8236
+ localProjectIndexPaths.push(path12.join(this.projectRoot, getHostProjectIndexRelativePath("opencode")));
8064
8237
  }
8065
8238
  const isLocalProjectIndex = localProjectIndexPaths.some(
8066
- (localPath) => path11.resolve(this.indexPath) === path11.resolve(localPath)
8239
+ (localPath) => path12.resolve(this.indexPath) === path12.resolve(localPath)
8067
8240
  );
8068
8241
  if (!isLocalProjectIndex) {
8069
8242
  throw new Error(
@@ -8153,7 +8326,7 @@ var Indexer = class {
8153
8326
  gcOrphanSymbols: 0,
8154
8327
  gcOrphanCallEdges: 0,
8155
8328
  resetCorruptedIndex: true,
8156
- warning: this.getCorruptedIndexWarning(path11.join(this.indexPath, "codebase.db"))
8329
+ warning: this.getCorruptedIndexWarning(path12.join(this.indexPath, "codebase.db"))
8157
8330
  };
8158
8331
  }
8159
8332
  this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
@@ -8473,7 +8646,8 @@ var Indexer = class {
8473
8646
  content,
8474
8647
  score: r.score,
8475
8648
  chunkType: r.metadata.chunkType,
8476
- name: r.metadata.name
8649
+ name: r.metadata.name,
8650
+ blame: blameFromMetadata(r.metadata)
8477
8651
  };
8478
8652
  })
8479
8653
  );
@@ -8510,9 +8684,9 @@ var Indexer = class {
8510
8684
  const { database } = await this.ensureInitialized();
8511
8685
  let shortest = [];
8512
8686
  for (const branchKey of this.getBranchCatalogKeys()) {
8513
- const path15 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
8514
- if (path15.length > 0 && (shortest.length === 0 || path15.length < shortest.length)) {
8515
- shortest = path15;
8687
+ const path16 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
8688
+ if (path16.length > 0 && (shortest.length === 0 || path16.length < shortest.length)) {
8689
+ shortest = path16;
8516
8690
  }
8517
8691
  }
8518
8692
  return shortest;
@@ -8544,7 +8718,7 @@ var Indexer = class {
8544
8718
  }
8545
8719
  async getPrImpact(opts) {
8546
8720
  const { database } = await this.ensureInitialized();
8547
- const execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
8721
+ const execFileAsync3 = (0, import_util3.promisify)(import_child_process3.execFile);
8548
8722
  const changedFilesResult = await getChangedFiles({
8549
8723
  pr: opts.pr,
8550
8724
  branch: opts.branch,
@@ -8566,7 +8740,7 @@ var Indexer = class {
8566
8740
  "Run index_codebase first to build the call graph and symbol index for this branch."
8567
8741
  );
8568
8742
  }
8569
- const absoluteChangedFiles = changedFiles.map((f) => path11.resolve(this.projectRoot, f));
8743
+ const absoluteChangedFiles = changedFiles.map((f) => path12.resolve(this.projectRoot, f));
8570
8744
  const directSymbols = database.getSymbolsForFiles(absoluteChangedFiles, branchKey);
8571
8745
  const directIds = directSymbols.map((s) => s.id);
8572
8746
  const direction = opts.direction ?? "both";
@@ -8628,7 +8802,7 @@ var Indexer = class {
8628
8802
  if (opts.checkConflicts) {
8629
8803
  conflictingPRs = [];
8630
8804
  try {
8631
- const { stdout } = await execFileAsync2(
8805
+ const { stdout } = await execFileAsync3(
8632
8806
  "gh",
8633
8807
  ["pr", "list", "--state", "open", "--json", "number,headRefName", "--limit", "10000"],
8634
8808
  { cwd: this.projectRoot, timeout: 3e4 }
@@ -8649,7 +8823,7 @@ var Indexer = class {
8649
8823
  projectRoot: this.projectRoot,
8650
8824
  baseBranch: this.baseBranch
8651
8825
  });
8652
- const otherAbsolute = otherChanged.files.map((f) => path11.resolve(this.projectRoot, f));
8826
+ const otherAbsolute = otherChanged.files.map((f) => path12.resolve(this.projectRoot, f));
8653
8827
  const otherBranchKey = this.getBranchCatalogKeyFor(openPr.headRefName);
8654
8828
  const otherSymbols = database.getSymbolsForFiles(otherAbsolute, otherBranchKey);
8655
8829
  const otherLabels = /* @__PURE__ */ new Set();
@@ -8712,12 +8886,12 @@ var Indexer = class {
8712
8886
  if (meta.filePath) filePaths.add(meta.filePath);
8713
8887
  }
8714
8888
  const directory = options?.directory?.replace(/\/$/, "");
8715
- const absoluteDirectoryFilter = directory ? path11.resolve(this.projectRoot, directory) : void 0;
8889
+ const absoluteDirectoryFilter = directory ? path12.resolve(this.projectRoot, directory) : void 0;
8716
8890
  for (const filePath of filePaths) {
8717
8891
  if (directory) {
8718
- const absoluteFilePath = path11.resolve(filePath);
8892
+ const absoluteFilePath = path12.resolve(filePath);
8719
8893
  const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
8720
- const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path11.sep));
8894
+ const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path12.sep));
8721
8895
  if (!matchesRelative && !matchesProjectRelative) {
8722
8896
  continue;
8723
8897
  }
@@ -8749,43 +8923,43 @@ var Indexer = class {
8749
8923
  };
8750
8924
 
8751
8925
  // src/tools/knowledge-base-paths.ts
8752
- var path12 = __toESM(require("path"), 1);
8926
+ var path13 = __toESM(require("path"), 1);
8753
8927
  function resolveConfigPathValue(value, baseDir) {
8754
8928
  const trimmed = value.trim();
8755
8929
  if (!trimmed) {
8756
8930
  return trimmed;
8757
8931
  }
8758
- const absolutePath = path12.isAbsolute(trimmed) ? trimmed : path12.resolve(baseDir, trimmed);
8759
- return path12.normalize(absolutePath);
8932
+ const absolutePath = path13.isAbsolute(trimmed) ? trimmed : path13.resolve(baseDir, trimmed);
8933
+ return path13.normalize(absolutePath);
8760
8934
  }
8761
8935
  function serializeConfigPathValue(value, baseDir) {
8762
8936
  const trimmed = value.trim();
8763
8937
  if (!trimmed) {
8764
8938
  return trimmed;
8765
8939
  }
8766
- if (!path12.isAbsolute(trimmed)) {
8767
- return normalizePathSeparators(path12.normalize(trimmed));
8940
+ if (!path13.isAbsolute(trimmed)) {
8941
+ return normalizePathSeparators(path13.normalize(trimmed));
8768
8942
  }
8769
- const relativePath = path12.relative(baseDir, trimmed);
8770
- if (!relativePath || !relativePath.startsWith("..") && !path12.isAbsolute(relativePath)) {
8771
- return normalizePathSeparators(path12.normalize(relativePath || "."));
8943
+ const relativePath = path13.relative(baseDir, trimmed);
8944
+ if (!relativePath || !relativePath.startsWith("..") && !path13.isAbsolute(relativePath)) {
8945
+ return normalizePathSeparators(path13.normalize(relativePath || "."));
8772
8946
  }
8773
- return path12.normalize(trimmed);
8947
+ return path13.normalize(trimmed);
8774
8948
  }
8775
- function resolveKnowledgeBasePath(value, projectRoot2) {
8776
- return path12.isAbsolute(value) ? value : path12.resolve(projectRoot2, value);
8949
+ function resolveKnowledgeBasePath(value, projectRoot3) {
8950
+ return path13.isAbsolute(value) ? value : path13.resolve(projectRoot3, value);
8777
8951
  }
8778
- function normalizeKnowledgeBasePath2(value, projectRoot2) {
8779
- return path12.normalize(resolveKnowledgeBasePath(value, projectRoot2));
8952
+ function normalizeKnowledgeBasePath2(value, projectRoot3) {
8953
+ return path13.normalize(resolveKnowledgeBasePath(value, projectRoot3));
8780
8954
  }
8781
- function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath, projectRoot2) {
8782
- const normalizedInput = path12.normalize(inputPath);
8783
- return knowledgeBases.some((kb) => normalizeKnowledgeBasePath2(kb, projectRoot2) === normalizedInput);
8955
+ function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath, projectRoot3) {
8956
+ const normalizedInput = path13.normalize(inputPath);
8957
+ return knowledgeBases.some((kb) => normalizeKnowledgeBasePath2(kb, projectRoot3) === normalizedInput);
8784
8958
  }
8785
- function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot2) {
8786
- const normalizedInput = path12.normalize(inputPath);
8959
+ function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot3) {
8960
+ const normalizedInput = path13.normalize(inputPath);
8787
8961
  return knowledgeBases.findIndex(
8788
- (kb) => path12.normalize(kb) === normalizedInput || normalizeKnowledgeBasePath2(kb, projectRoot2) === normalizedInput
8962
+ (kb) => path13.normalize(kb) === normalizedInput || normalizeKnowledgeBasePath2(kb, projectRoot3) === normalizedInput
8789
8963
  );
8790
8964
  }
8791
8965
 
@@ -8958,16 +9132,57 @@ function formatHealthCheck(result) {
8958
9132
  }
8959
9133
  return lines.join("\n");
8960
9134
  }
9135
+ function formatCallGraphCallers(name, callers, relationshipType) {
9136
+ if (callers.length === 0) {
9137
+ return `No callers found for "${name}"${relationshipType ? ` with type ${relationshipType}` : ""}. It may not be called by any tracked function, or the index needs updating.`;
9138
+ }
9139
+ const formatted = callers.map((edge, index) => {
9140
+ const confidence = edge.confidence !== "Direct" ? ` [${edge.confidence.toLowerCase()}]` : "";
9141
+ return `[${index + 1}] \u2190 from ${edge.fromSymbolName ?? "<unknown>"} in ${edge.fromSymbolFilePath ?? "<unknown file>"} [${edge.fromSymbolId}] (${edge.callType})${confidence} at line ${edge.line}${edge.isResolved ? " [resolved]" : " [unresolved]"}`;
9142
+ });
9143
+ return `"${name}" is called by ${callers.length} function(s):
9144
+
9145
+ ${formatted.join("\n")}`;
9146
+ }
9147
+ function formatCallGraphCallees(symbolId, callees, relationshipType) {
9148
+ if (callees.length === 0) {
9149
+ return `No callees found for symbol ${symbolId}${relationshipType ? ` with type ${relationshipType}` : ""}. The function may not call any other tracked functions.`;
9150
+ }
9151
+ return callees.map((edge, index) => {
9152
+ const confidence = edge.confidence !== "Direct" ? ` [${edge.confidence.toLowerCase()}]` : "";
9153
+ return `[${index + 1}] \u2192 ${edge.targetName} (${edge.callType})${confidence} at line ${edge.line}${edge.isResolved ? ` [resolved: ${edge.toSymbolId}]` : " [unresolved]"}`;
9154
+ }).join("\n");
9155
+ }
9156
+ function formatCallGraphPath(from, to, path16) {
9157
+ if (path16.length === 0) {
9158
+ return `No path found between "${from}" and "${to}". They may be in disconnected components, or the call graph index needs updating.`;
9159
+ }
9160
+ const formatted = path16.map((hop, index) => {
9161
+ const prefix = index === 0 ? "[start]" : `--${hop.callType}-->`;
9162
+ const location = hop.filePath ? ` (${hop.filePath}:${hop.line})` : "";
9163
+ return `${prefix} ${hop.symbolName}${location}`;
9164
+ });
9165
+ return `Path (${path16.length} hops):
9166
+ ${formatted.join("\n")}`;
9167
+ }
8961
9168
  function formatResultHeader(result, index) {
8962
9169
  return result.name ? `[${index + 1}] ${result.chunkType} "${result.name}" in ${result.filePath}:${result.startLine}-${result.endLine}` : `[${index + 1}] ${result.chunkType} in ${result.filePath}:${result.startLine}-${result.endLine}`;
8963
9170
  }
9171
+ function formatBlame(result) {
9172
+ if (!result.blame) {
9173
+ return "";
9174
+ }
9175
+ const date = new Date(result.blame.committedAt * 1e3).toISOString().slice(0, 10);
9176
+ return `
9177
+ ${result.blame.sha.slice(0, 7)} | ${result.blame.author} | ${date} | ${result.blame.summary}`;
9178
+ }
8964
9179
  function formatDefinitionLookup(results, query) {
8965
9180
  if (results.length === 0) {
8966
9181
  return `No definition found for "${query}". Try codebase_search for broader discovery, or verify the symbol name.`;
8967
9182
  }
8968
9183
  const formatted = results.map((r, idx) => {
8969
9184
  const header = formatResultHeader(r, idx);
8970
- return `${header} (score: ${r.score.toFixed(2)})
9185
+ return `${header} (score: ${r.score.toFixed(2)})${formatBlame(r)}
8971
9186
  \`\`\`
8972
9187
  ${truncateContent(r.content)}
8973
9188
  \`\`\``;
@@ -8978,7 +9193,7 @@ function formatSearchResults(results, scoreFormat = "similarity") {
8978
9193
  const formatted = results.map((r, idx) => {
8979
9194
  const header = formatResultHeader(r, idx);
8980
9195
  const scoreLabel = scoreFormat === "similarity" ? `(similarity: ${(r.score * 100).toFixed(1)}%)` : `(score: ${r.score.toFixed(2)})`;
8981
- return `${header} ${scoreLabel}
9196
+ return `${header} ${scoreLabel}${formatBlame(r)}
8982
9197
  \`\`\`
8983
9198
  ${truncateContent(r.content)}
8984
9199
  \`\`\``;
@@ -8988,12 +9203,12 @@ ${truncateContent(r.content)}
8988
9203
 
8989
9204
  // src/tools/config-state.ts
8990
9205
  var import_fs8 = require("fs");
8991
- var path13 = __toESM(require("path"), 1);
8992
- function normalizeKnowledgeBasePaths(config, projectRoot2) {
9206
+ var path14 = __toESM(require("path"), 1);
9207
+ function normalizeKnowledgeBasePaths(config, projectRoot3) {
8993
9208
  const normalized = { ...config };
8994
9209
  if (Array.isArray(normalized.knowledgeBases)) {
8995
9210
  normalized.knowledgeBases = normalized.knowledgeBases.map(
8996
- (kb) => resolveConfigPathValue(kb, projectRoot2)
9211
+ (kb) => resolveConfigPathValue(kb, projectRoot3)
8997
9212
  );
8998
9213
  }
8999
9214
  return normalized;
@@ -9004,19 +9219,19 @@ function toConfigRecord(rawConfig) {
9004
9219
  }
9005
9220
  return { ...rawConfig };
9006
9221
  }
9007
- function getConfigPath(projectRoot2, host = "opencode") {
9008
- return resolveWritableProjectConfigPath(projectRoot2, host);
9222
+ function getConfigPath(projectRoot3, host = "opencode") {
9223
+ return resolveWritableProjectConfigPath(projectRoot3, host);
9009
9224
  }
9010
- function loadRuntimeConfig(projectRoot2, host = "opencode") {
9011
- return normalizeKnowledgeBasePaths(toConfigRecord(loadMergedConfig(projectRoot2, host)), projectRoot2);
9225
+ function loadRuntimeConfig(projectRoot3, host = "opencode") {
9226
+ return normalizeKnowledgeBasePaths(toConfigRecord(loadMergedConfig(projectRoot3, host)), projectRoot3);
9012
9227
  }
9013
- function loadEditableConfig(projectRoot2, host = "opencode") {
9014
- return normalizeKnowledgeBasePaths(toConfigRecord(loadProjectConfigLayer(projectRoot2, host)), projectRoot2);
9228
+ function loadEditableConfig(projectRoot3, host = "opencode") {
9229
+ return normalizeKnowledgeBasePaths(toConfigRecord(loadProjectConfigLayer(projectRoot3, host)), projectRoot3);
9015
9230
  }
9016
- function saveConfig(projectRoot2, config, host = "opencode") {
9017
- const configPath = getConfigPath(projectRoot2, host);
9018
- const configDir = path13.dirname(configPath);
9019
- const configBaseDir = path13.dirname(configDir);
9231
+ function saveConfig(projectRoot3, config, host = "opencode") {
9232
+ const configPath = getConfigPath(projectRoot3, host);
9233
+ const configDir = path14.dirname(configPath);
9234
+ const configBaseDir = path14.dirname(configDir);
9020
9235
  if (!(0, import_fs8.existsSync)(configDir)) {
9021
9236
  (0, import_fs8.mkdirSync)(configDir, { recursive: true });
9022
9237
  }
@@ -9033,9 +9248,9 @@ function saveConfig(projectRoot2, config, host = "opencode") {
9033
9248
  var indexerCache = /* @__PURE__ */ new Map();
9034
9249
  var configCache = /* @__PURE__ */ new Map();
9035
9250
  var defaultProjectRoots = /* @__PURE__ */ new Map();
9036
- function getProjectRoot(projectRoot2, host) {
9037
- if (projectRoot2) {
9038
- return projectRoot2;
9251
+ function getProjectRoot(projectRoot3, host) {
9252
+ if (projectRoot3) {
9253
+ return projectRoot3;
9039
9254
  }
9040
9255
  const root = defaultProjectRoots.get(host);
9041
9256
  if (!root) {
@@ -9043,53 +9258,56 @@ function getProjectRoot(projectRoot2, host) {
9043
9258
  }
9044
9259
  return root;
9045
9260
  }
9046
- function getIndexerCacheKey(projectRoot2, host) {
9047
- return `${host}::${projectRoot2}`;
9261
+ function getIndexerCacheKey(projectRoot3, host) {
9262
+ return `${host}::${projectRoot3}`;
9048
9263
  }
9049
- function getOrCreateIndexer(projectRoot2, host) {
9050
- const key = getIndexerCacheKey(projectRoot2, host);
9264
+ function getOrCreateIndexer(projectRoot3, host) {
9265
+ const key = getIndexerCacheKey(projectRoot3, host);
9051
9266
  const cached = indexerCache.get(key);
9052
9267
  if (cached) {
9053
9268
  return cached;
9054
9269
  }
9055
- const config = parseConfig(loadRuntimeConfig(projectRoot2, host));
9056
- const indexer = new Indexer(projectRoot2, config, host);
9270
+ const config = parseConfig(loadRuntimeConfig(projectRoot3, host));
9271
+ const indexer = new Indexer(projectRoot3, config, host);
9057
9272
  indexerCache.set(key, indexer);
9058
9273
  configCache.set(key, config);
9059
9274
  return indexer;
9060
9275
  }
9061
- function getIndexerForProject(projectRoot2, host = "opencode") {
9062
- const root = getProjectRoot(projectRoot2, host);
9276
+ function getIndexerForProject(projectRoot3, host = "opencode") {
9277
+ const root = getProjectRoot(projectRoot3, host);
9063
9278
  return getOrCreateIndexer(root, host);
9064
9279
  }
9065
- function refreshIndexerForDirectory(projectRoot2, host = "opencode", config = parseConfig(loadRuntimeConfig(projectRoot2, host))) {
9066
- const key = getIndexerCacheKey(projectRoot2, host);
9067
- const indexer = new Indexer(projectRoot2, config, host);
9280
+ function refreshIndexerForDirectory(projectRoot3, host = "opencode", config = parseConfig(loadRuntimeConfig(projectRoot3, host))) {
9281
+ const key = getIndexerCacheKey(projectRoot3, host);
9282
+ const indexer = new Indexer(projectRoot3, config, host);
9068
9283
  indexerCache.set(key, indexer);
9069
9284
  configCache.set(key, config);
9070
9285
  }
9071
- function shouldForceLocalizeProjectIndex(projectRoot2, host = "opencode") {
9072
- const root = getProjectRoot(projectRoot2, host);
9073
- const localIndexPath = path14.join(root, getHostProjectIndexRelativePath(host));
9286
+ function shouldForceLocalizeProjectIndex(projectRoot3, host = "opencode") {
9287
+ const root = getProjectRoot(projectRoot3, host);
9288
+ const localIndexPath = path15.join(root, getHostProjectIndexRelativePath(host));
9074
9289
  if ((0, import_fs9.existsSync)(localIndexPath)) {
9075
9290
  return false;
9076
9291
  }
9077
9292
  const inheritedIndexPath = resolveWorktreeFallbackProjectIndexPath(root, host);
9078
9293
  return inheritedIndexPath !== null;
9079
9294
  }
9080
- async function searchCodebase(projectRoot2, host, query, options = {}) {
9081
- const indexer = getIndexerForProject(projectRoot2, host);
9295
+ async function searchCodebase(projectRoot3, host, query, options = {}) {
9296
+ const indexer = getIndexerForProject(projectRoot3, host);
9082
9297
  return indexer.search(query, options.limit, {
9083
9298
  fileType: options.fileType,
9084
9299
  directory: options.directory,
9085
9300
  chunkType: options.chunkType,
9086
9301
  contextLines: options.contextLines,
9087
9302
  metadataOnly: options.metadataOnly,
9088
- definitionIntent: options.definitionIntent
9303
+ definitionIntent: options.definitionIntent,
9304
+ blameAuthor: options.blameAuthor,
9305
+ blameSha: options.blameSha,
9306
+ blameSince: options.blameSince
9089
9307
  });
9090
9308
  }
9091
- async function findSimilarCode(projectRoot2, host, code, options = {}) {
9092
- const indexer = getIndexerForProject(projectRoot2, host);
9309
+ async function findSimilarCode(projectRoot3, host, code, options = {}) {
9310
+ const indexer = getIndexerForProject(projectRoot3, host);
9093
9311
  return indexer.findSimilar(code, options.limit, {
9094
9312
  fileType: options.fileType,
9095
9313
  directory: options.directory,
@@ -9097,16 +9315,16 @@ async function findSimilarCode(projectRoot2, host, code, options = {}) {
9097
9315
  excludeFile: options.excludeFile
9098
9316
  });
9099
9317
  }
9100
- async function implementationLookup(projectRoot2, host, query, options = {}) {
9101
- const indexer = getIndexerForProject(projectRoot2, host);
9318
+ async function implementationLookup(projectRoot3, host, query, options = {}) {
9319
+ const indexer = getIndexerForProject(projectRoot3, host);
9102
9320
  return indexer.search(query, options.limit, {
9103
9321
  fileType: options.fileType,
9104
9322
  directory: options.directory,
9105
9323
  definitionIntent: true
9106
9324
  });
9107
9325
  }
9108
- async function getCallGraphData(projectRoot2, host, params) {
9109
- const indexer = getIndexerForProject(projectRoot2, host);
9326
+ async function getCallGraphData(projectRoot3, host, params) {
9327
+ const indexer = getIndexerForProject(projectRoot3, host);
9110
9328
  if (params.direction === "callees") {
9111
9329
  if (!params.symbolId) {
9112
9330
  return { direction: "callees", callees: [], callers: [] };
@@ -9117,12 +9335,12 @@ async function getCallGraphData(projectRoot2, host, params) {
9117
9335
  const callers = await indexer.getCallers(params.name, params.relationshipType);
9118
9336
  return { direction: "callers", callers, callees: [] };
9119
9337
  }
9120
- async function getCallGraphPath(projectRoot2, host, from, to, maxDepth) {
9121
- const indexer = getIndexerForProject(projectRoot2, host);
9338
+ async function getCallGraphPath(projectRoot3, host, from, to, maxDepth) {
9339
+ const indexer = getIndexerForProject(projectRoot3, host);
9122
9340
  return indexer.findCallPath(from, to, maxDepth);
9123
9341
  }
9124
- async function runIndexCodebase(projectRoot2, host, args, onProgress) {
9125
- const root = getProjectRoot(projectRoot2, host);
9342
+ async function runIndexCodebase(projectRoot3, host, args, onProgress) {
9343
+ const root = getProjectRoot(projectRoot3, host);
9126
9344
  const key = getIndexerCacheKey(root, host);
9127
9345
  const cachedConfig = configCache.get(key);
9128
9346
  let indexer = getIndexerForProject(root, host);
@@ -9154,16 +9372,16 @@ async function runIndexCodebase(projectRoot2, host, args, onProgress) {
9154
9372
  });
9155
9373
  return { kind: "stats", stats };
9156
9374
  }
9157
- async function getIndexStatus(projectRoot2, host) {
9158
- const indexer = getIndexerForProject(projectRoot2, host);
9375
+ async function getIndexStatus(projectRoot3, host) {
9376
+ const indexer = getIndexerForProject(projectRoot3, host);
9159
9377
  return indexer.getStatus();
9160
9378
  }
9161
- async function getIndexHealthCheck(projectRoot2, host) {
9162
- const indexer = getIndexerForProject(projectRoot2, host);
9379
+ async function getIndexHealthCheck(projectRoot3, host) {
9380
+ const indexer = getIndexerForProject(projectRoot3, host);
9163
9381
  return indexer.healthCheck();
9164
9382
  }
9165
- async function getPrImpact(projectRoot2, host, params) {
9166
- const indexer = getIndexerForProject(projectRoot2, host);
9383
+ async function getPrImpact(projectRoot3, host, params) {
9384
+ const indexer = getIndexerForProject(projectRoot3, host);
9167
9385
  return indexer.getPrImpact({
9168
9386
  pr: params.pr,
9169
9387
  branch: params.branch,
@@ -9173,8 +9391,8 @@ async function getPrImpact(projectRoot2, host, params) {
9173
9391
  direction: params.direction
9174
9392
  });
9175
9393
  }
9176
- async function getIndexMetrics(projectRoot2, host) {
9177
- const indexer = getIndexerForProject(projectRoot2, host);
9394
+ async function getIndexMetrics(projectRoot3, host) {
9395
+ const indexer = getIndexerForProject(projectRoot3, host);
9178
9396
  const logger = indexer.getLogger();
9179
9397
  if (!logger.isEnabled()) {
9180
9398
  return {
@@ -9196,8 +9414,8 @@ async function getIndexMetrics(projectRoot2, host) {
9196
9414
  text: logger.formatMetrics()
9197
9415
  };
9198
9416
  }
9199
- async function getIndexLogs(projectRoot2, host, args) {
9200
- const indexer = getIndexerForProject(projectRoot2, host);
9417
+ async function getIndexLogs(projectRoot3, host, args) {
9418
+ const indexer = getIndexerForProject(projectRoot3, host);
9201
9419
  const logger = indexer.getLogger();
9202
9420
  if (!logger.isEnabled()) {
9203
9421
  return {
@@ -9219,17 +9437,17 @@ async function getIndexLogs(projectRoot2, host, args) {
9219
9437
  text: "No logs recorded yet. Logs are captured during indexing and search operations."
9220
9438
  };
9221
9439
  }
9222
- const text2 = logs.map((entry) => {
9440
+ const text3 = logs.map((entry) => {
9223
9441
  const dataStr = entry.data ? ` ${JSON.stringify(entry.data)}` : "";
9224
9442
  return `[${entry.timestamp}] [${entry.level.toUpperCase()}] [${entry.category}] ${entry.message}${dataStr}`;
9225
9443
  }).join("\n");
9226
- return { kind: "entries", text: text2 };
9444
+ return { kind: "entries", text: text3 };
9227
9445
  }
9228
- function addKnowledgeBase(projectRoot2, host, knowledgeBasePath) {
9229
- const root = getProjectRoot(projectRoot2, host);
9446
+ function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
9447
+ const root = getProjectRoot(projectRoot3, host);
9230
9448
  const inputPath = knowledgeBasePath.trim();
9231
- const normalizedPath = path14.resolve(
9232
- path14.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
9449
+ const normalizedPath = path15.resolve(
9450
+ path15.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
9233
9451
  );
9234
9452
  if (!(0, import_fs9.existsSync)(normalizedPath)) {
9235
9453
  return `Error: Directory does not exist: ${normalizedPath}`;
@@ -9265,7 +9483,7 @@ function addKnowledgeBase(projectRoot2, host, knowledgeBasePath) {
9265
9483
  }
9266
9484
  }
9267
9485
  for (const dotDir of sensitiveDotDirs) {
9268
- const sensitiveDir = path14.join(homeDir, dotDir);
9486
+ const sensitiveDir = path15.join(homeDir, dotDir);
9269
9487
  if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
9270
9488
  return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath}`;
9271
9489
  }
@@ -9298,8 +9516,8 @@ function addKnowledgeBase(projectRoot2, host, knowledgeBasePath) {
9298
9516
  Run /index to rebuild the index with the new knowledge base.`;
9299
9517
  return result;
9300
9518
  }
9301
- function listKnowledgeBases(projectRoot2, host) {
9302
- const root = getProjectRoot(projectRoot2, host);
9519
+ function listKnowledgeBases(projectRoot3, host) {
9520
+ const root = getProjectRoot(projectRoot3, host);
9303
9521
  const config = loadRuntimeConfig(root, host);
9304
9522
  const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
9305
9523
  if (knowledgeBases.length === 0) {
@@ -9328,7 +9546,7 @@ function listKnowledgeBases(projectRoot2, host) {
9328
9546
  }
9329
9547
  result += "\n";
9330
9548
  }
9331
- const hasHostConfig = (0, import_fs9.existsSync)(path14.join(root, getHostProjectConfigRelativePath(host)));
9549
+ const hasHostConfig = (0, import_fs9.existsSync)(path15.join(root, getHostProjectConfigRelativePath(host)));
9332
9550
  if (hasHostConfig) {
9333
9551
  result += `
9334
9552
  Config sources: 1 file(s).`;
@@ -9337,8 +9555,8 @@ Config sources: 1 file(s).`;
9337
9555
  Config file: ${getConfigPath(root, host)}`;
9338
9556
  return result;
9339
9557
  }
9340
- function removeKnowledgeBase(projectRoot2, host, knowledgeBasePath) {
9341
- const root = getProjectRoot(projectRoot2, host);
9558
+ function removeKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
9559
+ const root = getProjectRoot(projectRoot3, host);
9342
9560
  const config = loadEditableConfig(root, host);
9343
9561
  const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
9344
9562
  const index = findKnowledgeBasePathIndex(knowledgeBases, knowledgeBasePath, root);
@@ -9361,17 +9579,9 @@ Run /index to rebuild the index without the removed knowledge base.`;
9361
9579
  return result;
9362
9580
  }
9363
9581
 
9364
- // src/pi-extension.ts
9582
+ // src/pi-call-graph.ts
9583
+ var import_typebox = require("typebox");
9365
9584
  var HOST = "pi";
9366
- var ChunkType = import_typebox.Type.Union([
9367
- import_typebox.Type.Literal("function"),
9368
- import_typebox.Type.Literal("class"),
9369
- import_typebox.Type.Literal("method"),
9370
- import_typebox.Type.Literal("interface"),
9371
- import_typebox.Type.Literal("type"),
9372
- import_typebox.Type.Literal("module"),
9373
- import_typebox.Type.Literal("block")
9374
- ]);
9375
9585
  var RelationshipType = import_typebox.Type.Union([
9376
9586
  import_typebox.Type.Literal("Call"),
9377
9587
  import_typebox.Type.Literal("MethodCall"),
@@ -9380,214 +9590,247 @@ var RelationshipType = import_typebox.Type.Union([
9380
9590
  import_typebox.Type.Literal("Inherits"),
9381
9591
  import_typebox.Type.Literal("Implements")
9382
9592
  ]);
9383
- function text(text2, details) {
9384
- return { content: [{ type: "text", text: text2 }], details };
9593
+ function text(text3, details) {
9594
+ return { content: [{ type: "text", text: text3 }], details };
9385
9595
  }
9386
9596
  function projectRoot(ctx) {
9387
9597
  return ctx?.cwd ?? process.cwd();
9388
9598
  }
9599
+ function registerPiCallGraphTools(pi) {
9600
+ pi.registerTool({
9601
+ name: "call_graph",
9602
+ label: "Call Graph",
9603
+ description: "Find callers or callees of a function/method in the indexed call graph.",
9604
+ parameters: import_typebox.Type.Object({
9605
+ name: import_typebox.Type.String(),
9606
+ direction: import_typebox.Type.Optional(import_typebox.Type.Union([import_typebox.Type.Literal("callers"), import_typebox.Type.Literal("callees")])),
9607
+ symbolId: import_typebox.Type.Optional(import_typebox.Type.String()),
9608
+ relationshipType: import_typebox.Type.Optional(RelationshipType)
9609
+ }),
9610
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9611
+ const result = await getCallGraphData(projectRoot(ctx), HOST, params);
9612
+ if (result.direction === "callees") {
9613
+ return text(
9614
+ params.symbolId ? formatCallGraphCallees(params.symbolId, result.callees, params.relationshipType) : "Error: 'symbolId' is required when direction is 'callees'.",
9615
+ result
9616
+ );
9617
+ }
9618
+ return text(formatCallGraphCallers(params.name, result.callers, params.relationshipType), result);
9619
+ }
9620
+ });
9621
+ pi.registerTool({
9622
+ name: "call_graph_path",
9623
+ label: "Call Graph Path",
9624
+ description: "Find a call path between two functions/methods.",
9625
+ parameters: import_typebox.Type.Object({
9626
+ from: import_typebox.Type.String(),
9627
+ to: import_typebox.Type.String(),
9628
+ maxDepth: import_typebox.Type.Optional(import_typebox.Type.Number({ default: 10 }))
9629
+ }),
9630
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9631
+ const result = await getCallGraphPath(projectRoot(ctx), HOST, params.from, params.to, params.maxDepth);
9632
+ return text(formatCallGraphPath(params.from, params.to, result), result);
9633
+ }
9634
+ });
9635
+ }
9636
+
9637
+ // src/pi-extension.ts
9638
+ var HOST2 = "pi";
9639
+ var ChunkType = import_typebox2.Type.Union([
9640
+ import_typebox2.Type.Literal("function"),
9641
+ import_typebox2.Type.Literal("class"),
9642
+ import_typebox2.Type.Literal("method"),
9643
+ import_typebox2.Type.Literal("interface"),
9644
+ import_typebox2.Type.Literal("type"),
9645
+ import_typebox2.Type.Literal("module"),
9646
+ import_typebox2.Type.Literal("block")
9647
+ ]);
9648
+ function text2(text3, details) {
9649
+ return { content: [{ type: "text", text: text3 }], details };
9650
+ }
9651
+ function projectRoot2(ctx) {
9652
+ return ctx?.cwd ?? process.cwd();
9653
+ }
9389
9654
  function codebaseIndexPiExtension(pi) {
9390
9655
  pi.registerTool({
9391
9656
  name: "codebase_search",
9392
9657
  label: "Codebase Search",
9393
9658
  description: "Semantic search over the indexed codebase. Describe behavior, not syntax.",
9394
- parameters: import_typebox.Type.Object({
9395
- query: import_typebox.Type.String({ description: "Natural language description of what code you're looking for" }),
9396
- limit: import_typebox.Type.Optional(import_typebox.Type.Number({ description: "Maximum results (default: 10)" })),
9397
- fileType: import_typebox.Type.Optional(import_typebox.Type.String({ description: "Filter by extension, e.g. ts, py, rs" })),
9398
- directory: import_typebox.Type.Optional(import_typebox.Type.String({ description: "Filter by directory path" })),
9399
- chunkType: import_typebox.Type.Optional(ChunkType),
9400
- contextLines: import_typebox.Type.Optional(import_typebox.Type.Number({ description: "Extra lines around each match" }))
9659
+ parameters: import_typebox2.Type.Object({
9660
+ query: import_typebox2.Type.String({ description: "Natural language description of what code you're looking for" }),
9661
+ limit: import_typebox2.Type.Optional(import_typebox2.Type.Number({ description: "Maximum results (default: 10)" })),
9662
+ fileType: import_typebox2.Type.Optional(import_typebox2.Type.String({ description: "Filter by extension, e.g. ts, py, rs" })),
9663
+ directory: import_typebox2.Type.Optional(import_typebox2.Type.String({ description: "Filter by directory path" })),
9664
+ chunkType: import_typebox2.Type.Optional(ChunkType),
9665
+ contextLines: import_typebox2.Type.Optional(import_typebox2.Type.Number({ description: "Extra lines around each match" })),
9666
+ blameAuthor: import_typebox2.Type.Optional(import_typebox2.Type.String({ description: "Filter by git blame author name or email" })),
9667
+ blameSha: import_typebox2.Type.Optional(import_typebox2.Type.String({ description: "Filter by git blame commit SHA or prefix" })),
9668
+ blameSince: import_typebox2.Type.Optional(import_typebox2.Type.String({ description: "Filter to chunks last changed on or after this date" }))
9401
9669
  }),
9402
9670
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9403
- const results = await searchCodebase(projectRoot(ctx), HOST, params.query, params);
9404
- return text(formatSearchResults(results), results);
9671
+ const results = await searchCodebase(projectRoot2(ctx), HOST2, params.query, params);
9672
+ return text2(formatSearchResults(results), results);
9405
9673
  }
9406
9674
  });
9407
9675
  pi.registerTool({
9408
9676
  name: "codebase_peek",
9409
9677
  label: "Codebase Peek",
9410
9678
  description: "Semantic search returning only metadata (file, lines, symbol) to save tokens.",
9411
- parameters: import_typebox.Type.Object({
9412
- query: import_typebox.Type.String(),
9413
- limit: import_typebox.Type.Optional(import_typebox.Type.Number()),
9414
- fileType: import_typebox.Type.Optional(import_typebox.Type.String()),
9415
- directory: import_typebox.Type.Optional(import_typebox.Type.String()),
9416
- chunkType: import_typebox.Type.Optional(ChunkType)
9679
+ parameters: import_typebox2.Type.Object({
9680
+ query: import_typebox2.Type.String(),
9681
+ limit: import_typebox2.Type.Optional(import_typebox2.Type.Number()),
9682
+ fileType: import_typebox2.Type.Optional(import_typebox2.Type.String()),
9683
+ directory: import_typebox2.Type.Optional(import_typebox2.Type.String()),
9684
+ chunkType: import_typebox2.Type.Optional(ChunkType),
9685
+ blameAuthor: import_typebox2.Type.Optional(import_typebox2.Type.String()),
9686
+ blameSha: import_typebox2.Type.Optional(import_typebox2.Type.String()),
9687
+ blameSince: import_typebox2.Type.Optional(import_typebox2.Type.String())
9417
9688
  }),
9418
9689
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9419
- const results = await searchCodebase(projectRoot(ctx), HOST, params.query, { ...params, metadataOnly: true });
9420
- return text(formatSearchResults(results), results);
9690
+ const results = await searchCodebase(projectRoot2(ctx), HOST2, params.query, { ...params, metadataOnly: true });
9691
+ return text2(formatSearchResults(results), results);
9421
9692
  }
9422
9693
  });
9423
9694
  pi.registerTool({
9424
9695
  name: "find_similar",
9425
9696
  label: "Find Similar Code",
9426
9697
  description: "Find code similar to a snippet for duplicate detection and pattern discovery.",
9427
- parameters: import_typebox.Type.Object({
9428
- code: import_typebox.Type.String({ description: "Code snippet to compare" }),
9429
- limit: import_typebox.Type.Optional(import_typebox.Type.Number()),
9430
- fileType: import_typebox.Type.Optional(import_typebox.Type.String()),
9431
- directory: import_typebox.Type.Optional(import_typebox.Type.String()),
9432
- chunkType: import_typebox.Type.Optional(ChunkType),
9433
- excludeFile: import_typebox.Type.Optional(import_typebox.Type.String())
9698
+ parameters: import_typebox2.Type.Object({
9699
+ code: import_typebox2.Type.String({ description: "Code snippet to compare" }),
9700
+ limit: import_typebox2.Type.Optional(import_typebox2.Type.Number()),
9701
+ fileType: import_typebox2.Type.Optional(import_typebox2.Type.String()),
9702
+ directory: import_typebox2.Type.Optional(import_typebox2.Type.String()),
9703
+ chunkType: import_typebox2.Type.Optional(ChunkType),
9704
+ excludeFile: import_typebox2.Type.Optional(import_typebox2.Type.String())
9434
9705
  }),
9435
9706
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9436
- const results = await findSimilarCode(projectRoot(ctx), HOST, params.code, params);
9437
- return text(formatSearchResults(results, "similarity"), results);
9707
+ const results = await findSimilarCode(projectRoot2(ctx), HOST2, params.code, params);
9708
+ return text2(formatSearchResults(results, "similarity"), results);
9438
9709
  }
9439
9710
  });
9440
9711
  pi.registerTool({
9441
9712
  name: "implementation_lookup",
9442
9713
  label: "Implementation Lookup",
9443
9714
  description: "Find likely symbol definitions or implementations by name or natural language.",
9444
- parameters: import_typebox.Type.Object({
9445
- query: import_typebox.Type.String(),
9446
- limit: import_typebox.Type.Optional(import_typebox.Type.Number()),
9447
- fileType: import_typebox.Type.Optional(import_typebox.Type.String()),
9448
- directory: import_typebox.Type.Optional(import_typebox.Type.String())
9715
+ parameters: import_typebox2.Type.Object({
9716
+ query: import_typebox2.Type.String(),
9717
+ limit: import_typebox2.Type.Optional(import_typebox2.Type.Number()),
9718
+ fileType: import_typebox2.Type.Optional(import_typebox2.Type.String()),
9719
+ directory: import_typebox2.Type.Optional(import_typebox2.Type.String())
9449
9720
  }),
9450
9721
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9451
- const results = await implementationLookup(projectRoot(ctx), HOST, params.query, params);
9452
- return text(formatDefinitionLookup(results, params.query), results);
9722
+ const results = await implementationLookup(projectRoot2(ctx), HOST2, params.query, params);
9723
+ return text2(formatDefinitionLookup(results, params.query), results);
9453
9724
  }
9454
9725
  });
9455
9726
  pi.registerTool({
9456
9727
  name: "index_codebase",
9457
9728
  label: "Index Codebase",
9458
9729
  description: "Build or refresh the semantic codebase index.",
9459
- parameters: import_typebox.Type.Object({
9460
- force: import_typebox.Type.Optional(import_typebox.Type.Boolean({ default: false })),
9461
- estimateOnly: import_typebox.Type.Optional(import_typebox.Type.Boolean({ default: false })),
9462
- verbose: import_typebox.Type.Optional(import_typebox.Type.Boolean({ default: false }))
9730
+ parameters: import_typebox2.Type.Object({
9731
+ force: import_typebox2.Type.Optional(import_typebox2.Type.Boolean({ default: false })),
9732
+ estimateOnly: import_typebox2.Type.Optional(import_typebox2.Type.Boolean({ default: false })),
9733
+ verbose: import_typebox2.Type.Optional(import_typebox2.Type.Boolean({ default: false }))
9463
9734
  }),
9464
9735
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9465
- const result = await runIndexCodebase(projectRoot(ctx), HOST, params);
9466
- return result.kind === "estimate" ? text(formatCostEstimate(result.estimate), result.estimate) : text(formatIndexStats(result.stats, params.verbose ?? false), result.stats);
9736
+ const result = await runIndexCodebase(projectRoot2(ctx), HOST2, params);
9737
+ return result.kind === "estimate" ? text2(formatCostEstimate(result.estimate), result.estimate) : text2(formatIndexStats(result.stats, params.verbose ?? false), result.stats);
9467
9738
  }
9468
9739
  });
9469
9740
  pi.registerTool({
9470
9741
  name: "index_status",
9471
9742
  label: "Index Status",
9472
9743
  description: "Check index health and current status.",
9473
- parameters: import_typebox.Type.Object({}),
9744
+ parameters: import_typebox2.Type.Object({}),
9474
9745
  async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
9475
- const status = await getIndexStatus(projectRoot(ctx), HOST);
9476
- return text(formatStatus(status), status);
9746
+ const status = await getIndexStatus(projectRoot2(ctx), HOST2);
9747
+ return text2(formatStatus(status), status);
9477
9748
  }
9478
9749
  });
9479
9750
  pi.registerTool({
9480
9751
  name: "index_health_check",
9481
9752
  label: "Index Health Check",
9482
9753
  description: "Garbage collect orphaned embeddings/chunks and report health.",
9483
- parameters: import_typebox.Type.Object({}),
9754
+ parameters: import_typebox2.Type.Object({}),
9484
9755
  async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
9485
- const result = await getIndexHealthCheck(projectRoot(ctx), HOST);
9486
- return text(formatHealthCheck(result), result);
9756
+ const result = await getIndexHealthCheck(projectRoot2(ctx), HOST2);
9757
+ return text2(formatHealthCheck(result), result);
9487
9758
  }
9488
9759
  });
9489
9760
  pi.registerTool({
9490
9761
  name: "index_metrics",
9491
9762
  label: "Index Metrics",
9492
9763
  description: "Return collected performance metrics when debug metrics are enabled.",
9493
- parameters: import_typebox.Type.Object({}),
9764
+ parameters: import_typebox2.Type.Object({}),
9494
9765
  async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
9495
- const result = await getIndexMetrics(projectRoot(ctx), HOST);
9496
- return text(result.text, result);
9766
+ const result = await getIndexMetrics(projectRoot2(ctx), HOST2);
9767
+ return text2(result.text, result);
9497
9768
  }
9498
9769
  });
9499
9770
  pi.registerTool({
9500
9771
  name: "index_logs",
9501
9772
  label: "Index Logs",
9502
9773
  description: "Return recent debug logs when debug logging is enabled.",
9503
- parameters: import_typebox.Type.Object({
9504
- limit: import_typebox.Type.Optional(import_typebox.Type.Number()),
9505
- category: import_typebox.Type.Optional(import_typebox.Type.Union([
9506
- import_typebox.Type.Literal("search"),
9507
- import_typebox.Type.Literal("embedding"),
9508
- import_typebox.Type.Literal("cache"),
9509
- import_typebox.Type.Literal("gc"),
9510
- import_typebox.Type.Literal("branch"),
9511
- import_typebox.Type.Literal("general")
9774
+ parameters: import_typebox2.Type.Object({
9775
+ limit: import_typebox2.Type.Optional(import_typebox2.Type.Number()),
9776
+ category: import_typebox2.Type.Optional(import_typebox2.Type.Union([
9777
+ import_typebox2.Type.Literal("search"),
9778
+ import_typebox2.Type.Literal("embedding"),
9779
+ import_typebox2.Type.Literal("cache"),
9780
+ import_typebox2.Type.Literal("gc"),
9781
+ import_typebox2.Type.Literal("branch"),
9782
+ import_typebox2.Type.Literal("general")
9512
9783
  ])),
9513
- level: import_typebox.Type.Optional(import_typebox.Type.Union([import_typebox.Type.Literal("error"), import_typebox.Type.Literal("warn"), import_typebox.Type.Literal("info"), import_typebox.Type.Literal("debug")]))
9784
+ level: import_typebox2.Type.Optional(import_typebox2.Type.Union([import_typebox2.Type.Literal("error"), import_typebox2.Type.Literal("warn"), import_typebox2.Type.Literal("info"), import_typebox2.Type.Literal("debug")]))
9514
9785
  }),
9515
9786
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9516
- const result = await getIndexLogs(projectRoot(ctx), HOST, params);
9517
- return text(result.text, result);
9518
- }
9519
- });
9520
- pi.registerTool({
9521
- name: "call_graph",
9522
- label: "Call Graph",
9523
- description: "Find callers or callees of a function/method in the indexed call graph.",
9524
- parameters: import_typebox.Type.Object({
9525
- name: import_typebox.Type.String(),
9526
- direction: import_typebox.Type.Optional(import_typebox.Type.Union([import_typebox.Type.Literal("callers"), import_typebox.Type.Literal("callees")])),
9527
- symbolId: import_typebox.Type.Optional(import_typebox.Type.String()),
9528
- relationshipType: import_typebox.Type.Optional(RelationshipType)
9529
- }),
9530
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9531
- const result = await getCallGraphData(projectRoot(ctx), HOST, params);
9532
- return text(JSON.stringify(result, null, 2), result);
9533
- }
9534
- });
9535
- pi.registerTool({
9536
- name: "call_graph_path",
9537
- label: "Call Graph Path",
9538
- description: "Find a call path between two functions/methods.",
9539
- parameters: import_typebox.Type.Object({
9540
- from: import_typebox.Type.String(),
9541
- to: import_typebox.Type.String(),
9542
- maxDepth: import_typebox.Type.Optional(import_typebox.Type.Number({ default: 10 }))
9543
- }),
9544
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9545
- const result = await getCallGraphPath(projectRoot(ctx), HOST, params.from, params.to, params.maxDepth);
9546
- return text(JSON.stringify(result, null, 2), result);
9787
+ const result = await getIndexLogs(projectRoot2(ctx), HOST2, params);
9788
+ return text2(result.text, result);
9547
9789
  }
9548
9790
  });
9791
+ registerPiCallGraphTools(pi);
9549
9792
  pi.registerTool({
9550
9793
  name: "pr_impact",
9551
9794
  label: "PR Impact",
9552
9795
  description: "Analyze PR or branch impact through changed symbols and call graph neighborhoods.",
9553
- parameters: import_typebox.Type.Object({
9554
- pr: import_typebox.Type.Optional(import_typebox.Type.Number()),
9555
- branch: import_typebox.Type.Optional(import_typebox.Type.String()),
9556
- maxDepth: import_typebox.Type.Optional(import_typebox.Type.Number({ default: 5 })),
9557
- hubThreshold: import_typebox.Type.Optional(import_typebox.Type.Number({ default: 10 })),
9558
- checkConflicts: import_typebox.Type.Optional(import_typebox.Type.Boolean({ default: false })),
9559
- direction: import_typebox.Type.Optional(import_typebox.Type.Union([import_typebox.Type.Literal("callers"), import_typebox.Type.Literal("callees"), import_typebox.Type.Literal("both")]))
9796
+ parameters: import_typebox2.Type.Object({
9797
+ pr: import_typebox2.Type.Optional(import_typebox2.Type.Number()),
9798
+ branch: import_typebox2.Type.Optional(import_typebox2.Type.String()),
9799
+ maxDepth: import_typebox2.Type.Optional(import_typebox2.Type.Number({ default: 5 })),
9800
+ hubThreshold: import_typebox2.Type.Optional(import_typebox2.Type.Number({ default: 10 })),
9801
+ checkConflicts: import_typebox2.Type.Optional(import_typebox2.Type.Boolean({ default: false })),
9802
+ direction: import_typebox2.Type.Optional(import_typebox2.Type.Union([import_typebox2.Type.Literal("callers"), import_typebox2.Type.Literal("callees"), import_typebox2.Type.Literal("both")]))
9560
9803
  }),
9561
9804
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9562
- const result = await getPrImpact(projectRoot(ctx), HOST, params);
9563
- return text(formatPrImpact(result), result);
9805
+ const result = await getPrImpact(projectRoot2(ctx), HOST2, params);
9806
+ return text2(formatPrImpact(result), result);
9564
9807
  }
9565
9808
  });
9566
9809
  pi.registerTool({
9567
9810
  name: "knowledge_base_list",
9568
9811
  label: "List Knowledge Bases",
9569
9812
  description: "List configured knowledge-base paths included in the index.",
9570
- parameters: import_typebox.Type.Object({}),
9813
+ parameters: import_typebox2.Type.Object({}),
9571
9814
  async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
9572
- return text(listKnowledgeBases(projectRoot(ctx), HOST));
9815
+ return text2(listKnowledgeBases(projectRoot2(ctx), HOST2));
9573
9816
  }
9574
9817
  });
9575
9818
  pi.registerTool({
9576
9819
  name: "knowledge_base_add",
9577
9820
  label: "Add Knowledge Base",
9578
9821
  description: "Add a knowledge-base path to the codebase index config.",
9579
- parameters: import_typebox.Type.Object({ path: import_typebox.Type.String({ description: "File or directory path to add" }) }),
9822
+ parameters: import_typebox2.Type.Object({ path: import_typebox2.Type.String({ description: "File or directory path to add" }) }),
9580
9823
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9581
- return text(addKnowledgeBase(projectRoot(ctx), HOST, params.path));
9824
+ return text2(addKnowledgeBase(projectRoot2(ctx), HOST2, params.path));
9582
9825
  }
9583
9826
  });
9584
9827
  pi.registerTool({
9585
9828
  name: "knowledge_base_remove",
9586
9829
  label: "Remove Knowledge Base",
9587
9830
  description: "Remove a knowledge-base path from the codebase index config.",
9588
- parameters: import_typebox.Type.Object({ path: import_typebox.Type.String({ description: "File or directory path to remove" }) }),
9831
+ parameters: import_typebox2.Type.Object({ path: import_typebox2.Type.String({ description: "File or directory path to remove" }) }),
9589
9832
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
9590
- return text(removeKnowledgeBase(projectRoot(ctx), HOST, params.path));
9833
+ return text2(removeKnowledgeBase(projectRoot2(ctx), HOST2, params.path));
9591
9834
  }
9592
9835
  });
9593
9836
  }