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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +22 -8
- package/commands/peek.md +4 -0
- package/commands/search.md +4 -0
- package/dist/cli.cjs +597 -398
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +595 -396
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +531 -322
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +529 -320
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +638 -395
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +638 -395
- package/dist/pi-extension.js.map +1 -1
- package/native/codebase-index-native.darwin-arm64.node +0 -0
- package/native/codebase-index-native.darwin-x64.node +0 -0
- package/native/codebase-index-native.linux-arm64-gnu.node +0 -0
- package/native/codebase-index-native.linux-x64-gnu.node +0 -0
- package/native/codebase-index-native.win32-x64-msvc.node +0 -0
- package/package.json +3 -1
- package/scripts/link-local-mcp-bin.mjs +25 -0
- package/skill/SKILL.md +5 -0
package/dist/pi-extension.cjs
CHANGED
|
@@ -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(
|
|
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(
|
|
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 = (
|
|
529
|
-
if (!isString(
|
|
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 (!
|
|
535
|
+
if (!path16) {
|
|
536
536
|
return doThrow(`path must not be empty`, TypeError);
|
|
537
537
|
}
|
|
538
|
-
if (checkPath.isNotRelative(
|
|
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 = (
|
|
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
|
|
577
|
+
const path16 = originalPath && checkPath.convert(originalPath);
|
|
578
578
|
checkPath(
|
|
579
|
-
|
|
579
|
+
path16,
|
|
580
580
|
originalPath,
|
|
581
581
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
582
582
|
);
|
|
583
|
-
return this._t(
|
|
583
|
+
return this._t(path16, cache, checkUnignored, slices);
|
|
584
584
|
}
|
|
585
|
-
checkIgnore(
|
|
586
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
587
|
-
return this.test(
|
|
585
|
+
checkIgnore(path16) {
|
|
586
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path16)) {
|
|
587
|
+
return this.test(path16);
|
|
588
588
|
}
|
|
589
|
-
const slices =
|
|
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(
|
|
602
|
+
return this._rules.test(path16, false, MODE_CHECK_IGNORE);
|
|
603
603
|
}
|
|
604
|
-
_t(
|
|
605
|
-
if (
|
|
606
|
-
return cache[
|
|
604
|
+
_t(path16, cache, checkUnignored, slices) {
|
|
605
|
+
if (path16 in cache) {
|
|
606
|
+
return cache[path16];
|
|
607
607
|
}
|
|
608
608
|
if (!slices) {
|
|
609
|
-
slices =
|
|
609
|
+
slices = path16.split(SLASH).filter(Boolean);
|
|
610
610
|
}
|
|
611
611
|
slices.pop();
|
|
612
612
|
if (!slices.length) {
|
|
613
|
-
return cache[
|
|
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[
|
|
621
|
+
return cache[path16] = parent.ignored ? parent : this._rules.test(path16, checkUnignored, MODE_IGNORE);
|
|
622
622
|
}
|
|
623
|
-
ignores(
|
|
624
|
-
return this._test(
|
|
623
|
+
ignores(path16) {
|
|
624
|
+
return this._test(path16, this._ignoreCache, false).ignored;
|
|
625
625
|
}
|
|
626
626
|
createFilter() {
|
|
627
|
-
return (
|
|
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(
|
|
634
|
-
return this._test(
|
|
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 = (
|
|
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 = (
|
|
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
|
|
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
|
|
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(
|
|
1508
|
-
const mainRepoRoot = resolveWorktreeMainRepoRoot(
|
|
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(
|
|
1516
|
-
const inheritedHostPath = resolveWorktreeFallbackPath(
|
|
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(
|
|
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(
|
|
1532
|
-
return (0, import_fs4.existsSync)(path4.join(
|
|
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(
|
|
1581
|
-
const hostConfigPath = path4.join(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
1604
|
-
return path4.join(
|
|
1607
|
+
function resolveWritableProjectConfigPath(projectRoot3, host = "opencode") {
|
|
1608
|
+
return path4.join(projectRoot3, getProjectConfigRelativePath(host));
|
|
1605
1609
|
}
|
|
1606
|
-
function resolveProjectIndexPath(
|
|
1610
|
+
function resolveProjectIndexPath(projectRoot3, scope, host = "opencode") {
|
|
1607
1611
|
if (scope === "global") {
|
|
1608
1612
|
return resolveGlobalIndexPath(host);
|
|
1609
1613
|
}
|
|
1610
|
-
const localIndexPath = path4.join(
|
|
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(
|
|
1616
|
-
if ((0, import_fs4.existsSync)(legacyIndexPath) && !hasHostProjectConfig(
|
|
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(
|
|
1624
|
+
if (hasHostProjectConfig(projectRoot3, host)) {
|
|
1621
1625
|
return localIndexPath;
|
|
1622
1626
|
}
|
|
1623
|
-
const hostFallback = resolveWorktreeFallbackPath(
|
|
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(
|
|
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(
|
|
1762
|
-
const localConfigPath = resolveWritableProjectConfigPath(
|
|
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(
|
|
1768
|
-
const projectConfigPath = resolveProjectConfigPath(
|
|
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
|
-
|
|
1783
|
+
projectRoot3
|
|
1780
1784
|
);
|
|
1781
1785
|
}
|
|
1782
1786
|
return normalizedConfig;
|
|
1783
1787
|
}
|
|
1784
|
-
function loadMergedConfig(
|
|
1788
|
+
function loadMergedConfig(projectRoot3, host = "opencode") {
|
|
1785
1789
|
const globalConfigPath = resolveGlobalConfigPath(host);
|
|
1786
|
-
const projectConfigPath = resolveProjectConfigPath(
|
|
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(
|
|
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
|
|
1843
|
+
var path12 = __toESM(require("path"), 1);
|
|
1840
1844
|
var import_perf_hooks = require("perf_hooks");
|
|
1841
|
-
var
|
|
1842
|
-
var
|
|
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((
|
|
3154
|
+
const requests = batch.map((text3) => ({
|
|
3151
3155
|
model: `models/${this.modelInfo.model}`,
|
|
3152
3156
|
content: {
|
|
3153
|
-
parts: [{ text:
|
|
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,
|
|
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(
|
|
3194
|
-
return Math.ceil(
|
|
3197
|
+
estimateTokens(text3) {
|
|
3198
|
+
return Math.ceil(text3.length / 4);
|
|
3195
3199
|
}
|
|
3196
|
-
truncateToCharLimit(
|
|
3197
|
-
if (
|
|
3198
|
-
return
|
|
3200
|
+
truncateToCharLimit(text3, maxChars) {
|
|
3201
|
+
if (text3.length <= maxChars) {
|
|
3202
|
+
return text3;
|
|
3199
3203
|
}
|
|
3200
|
-
return `${
|
|
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(
|
|
3211
|
+
buildTruncationCandidates(text3) {
|
|
3208
3212
|
const baseMaxChars = Math.max(1, this.modelInfo.maxTokens * 4);
|
|
3209
3213
|
const candidateLimits = /* @__PURE__ */ new Set();
|
|
3210
|
-
const baselineLimit =
|
|
3214
|
+
const baselineLimit = text3.length > baseMaxChars ? baseMaxChars : Math.max(
|
|
3211
3215
|
_OllamaEmbeddingProvider.MIN_TRUNCATION_CHARS,
|
|
3212
|
-
Math.floor(
|
|
3216
|
+
Math.floor(text3.length * 0.9)
|
|
3213
3217
|
);
|
|
3214
|
-
if (baselineLimit <
|
|
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 <
|
|
3226
|
+
if (scaledLimit < text3.length) {
|
|
3223
3227
|
candidateLimits.add(scaledLimit);
|
|
3224
3228
|
}
|
|
3225
3229
|
}
|
|
3226
|
-
candidateLimits.add(Math.min(
|
|
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 >=
|
|
3234
|
+
if (limit <= 0 || limit >= text3.length) {
|
|
3231
3235
|
continue;
|
|
3232
3236
|
}
|
|
3233
|
-
const truncated = this.truncateToCharLimit(
|
|
3234
|
-
if (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(
|
|
3246
|
+
async embedSingleWithFallback(text3) {
|
|
3243
3247
|
try {
|
|
3244
|
-
return await this.embedSingle(
|
|
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(
|
|
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(
|
|
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:
|
|
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(
|
|
3286
|
+
tokensUsed: this.estimateTokens(text3)
|
|
3283
3287
|
};
|
|
3284
3288
|
}
|
|
3285
3289
|
async embedBatch(texts) {
|
|
3286
3290
|
const results = [];
|
|
3287
|
-
for (const
|
|
3288
|
-
results.push(await this.embedSingleWithFallback(
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
3550
|
+
async function collectFiles(projectRoot3, includePatterns, excludePatterns, maxFileSize, additionalRoots, walkOptions) {
|
|
3547
3551
|
const opts = walkOptions ?? { maxDepth: 5, maxFilesPerDirectory: 100 };
|
|
3548
|
-
const ignoreFilter = createIgnoreFilter(
|
|
3552
|
+
const ignoreFilter = createIgnoreFilter(projectRoot3);
|
|
3549
3553
|
const files = [];
|
|
3550
3554
|
const skipped = [];
|
|
3551
3555
|
for await (const file of walkDirectory(
|
|
3552
|
-
|
|
3553
|
-
|
|
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(
|
|
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(
|
|
4136
|
-
return Math.ceil(
|
|
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:
|
|
4674
|
+
const { pr, branch, projectRoot: projectRoot3, baseBranch = "main" } = opts;
|
|
4671
4675
|
if (pr !== void 0) {
|
|
4672
|
-
return getChangedFilesForPr(pr,
|
|
4676
|
+
return getChangedFilesForPr(pr, projectRoot3, baseBranch);
|
|
4673
4677
|
}
|
|
4674
|
-
return getChangedFilesForBranch(branch,
|
|
4678
|
+
return getChangedFilesForBranch(branch, projectRoot3, baseBranch);
|
|
4675
4679
|
}
|
|
4676
|
-
async function getChangedFilesForPr(pr,
|
|
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:
|
|
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
|
-
|
|
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,
|
|
4713
|
+
const result = await getChangedFilesForBranch(headRefName, projectRoot3, actualBaseBranch);
|
|
4710
4714
|
return { ...result, headRefName };
|
|
4711
4715
|
}
|
|
4712
|
-
async function getChangedFilesForBranch(branch,
|
|
4713
|
-
const targetBranch = branch || await getCurrentBranch2(
|
|
4714
|
-
const mergeBase = await getMergeBase(
|
|
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:
|
|
4722
|
+
{ cwd: projectRoot3, timeout: 3e4 }
|
|
4719
4723
|
);
|
|
4720
4724
|
return {
|
|
4721
|
-
files: normalizeFiles(stdout.split("\n"),
|
|
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(
|
|
4731
|
+
async function getCurrentBranch2(projectRoot3) {
|
|
4728
4732
|
const { stdout } = await execFileAsync(
|
|
4729
4733
|
"git",
|
|
4730
4734
|
["branch", "--show-current"],
|
|
4731
|
-
{ cwd:
|
|
4735
|
+
{ cwd: projectRoot3, timeout: 3e4 }
|
|
4732
4736
|
);
|
|
4733
4737
|
return stdout.trim() || "HEAD";
|
|
4734
4738
|
}
|
|
4735
|
-
async function getMergeBase(
|
|
4739
|
+
async function getMergeBase(projectRoot3, baseBranch, branch) {
|
|
4736
4740
|
const { stdout } = await execFileAsync(
|
|
4737
4741
|
"git",
|
|
4738
4742
|
["merge-base", baseBranch, branch],
|
|
4739
|
-
{ cwd:
|
|
4743
|
+
{ cwd: projectRoot3, timeout: 3e4 }
|
|
4740
4744
|
);
|
|
4741
4745
|
return stdout.trim();
|
|
4742
4746
|
}
|
|
4743
|
-
function normalizeFiles(rawFiles,
|
|
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(
|
|
4750
|
-
const
|
|
4751
|
-
const cleaned =
|
|
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((
|
|
4885
|
-
text:
|
|
4886
|
-
tokenCount: estimateTokens(
|
|
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 =
|
|
5000
|
-
const normalizedRoot =
|
|
5001
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
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(
|
|
5118
|
-
if (!
|
|
5213
|
+
function tokenizeTextForRanking(text3) {
|
|
5214
|
+
if (!text3) {
|
|
5119
5215
|
return /* @__PURE__ */ new Set();
|
|
5120
5216
|
}
|
|
5121
|
-
const lowered =
|
|
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(
|
|
6052
|
-
this.projectRoot =
|
|
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 =
|
|
6057
|
-
this.failedBatchesPath =
|
|
6058
|
-
this.indexingLockPath =
|
|
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)(
|
|
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([
|
|
6208
|
+
const roots = /* @__PURE__ */ new Set([path12.resolve(this.projectRoot)]);
|
|
6096
6209
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
6097
|
-
roots.add(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
6836
|
+
const storePath = path12.join(this.indexPath, "vectors");
|
|
6724
6837
|
this.store = new VectorStore(storePath, dimensions);
|
|
6725
|
-
const indexFilePath =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
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 =
|
|
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 (
|
|
7416
|
+
if (existingContentHash === contentHash) {
|
|
7249
7417
|
fileChunkCount++;
|
|
7250
7418
|
continue;
|
|
7251
7419
|
}
|
|
7252
|
-
const texts = createEmbeddingTexts(chunk, parsed.path, getSafeEmbeddingChunkTokenLimit(configuredProviderInfo)).map((
|
|
7253
|
-
text:
|
|
7254
|
-
tokenCount: estimateTokens(
|
|
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(
|
|
7957
|
+
tokenize(text3) {
|
|
7786
7958
|
return new Set(
|
|
7787
|
-
|
|
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 = [
|
|
8234
|
+
const localProjectIndexPaths = [path12.join(this.projectRoot, getHostProjectIndexRelativePath(this.host))];
|
|
8062
8235
|
if (this.host !== "opencode") {
|
|
8063
|
-
localProjectIndexPaths.push(
|
|
8236
|
+
localProjectIndexPaths.push(path12.join(this.projectRoot, getHostProjectIndexRelativePath("opencode")));
|
|
8064
8237
|
}
|
|
8065
8238
|
const isLocalProjectIndex = localProjectIndexPaths.some(
|
|
8066
|
-
(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(
|
|
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
|
|
8514
|
-
if (
|
|
8515
|
-
shortest =
|
|
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
|
|
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) =>
|
|
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
|
|
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) =>
|
|
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 ?
|
|
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 =
|
|
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 +
|
|
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
|
|
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 =
|
|
8759
|
-
return
|
|
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 (!
|
|
8767
|
-
return normalizePathSeparators(
|
|
8940
|
+
if (!path13.isAbsolute(trimmed)) {
|
|
8941
|
+
return normalizePathSeparators(path13.normalize(trimmed));
|
|
8768
8942
|
}
|
|
8769
|
-
const relativePath =
|
|
8770
|
-
if (!relativePath || !relativePath.startsWith("..") && !
|
|
8771
|
-
return normalizePathSeparators(
|
|
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
|
|
8947
|
+
return path13.normalize(trimmed);
|
|
8774
8948
|
}
|
|
8775
|
-
function resolveKnowledgeBasePath(value,
|
|
8776
|
-
return
|
|
8949
|
+
function resolveKnowledgeBasePath(value, projectRoot3) {
|
|
8950
|
+
return path13.isAbsolute(value) ? value : path13.resolve(projectRoot3, value);
|
|
8777
8951
|
}
|
|
8778
|
-
function normalizeKnowledgeBasePath2(value,
|
|
8779
|
-
return
|
|
8952
|
+
function normalizeKnowledgeBasePath2(value, projectRoot3) {
|
|
8953
|
+
return path13.normalize(resolveKnowledgeBasePath(value, projectRoot3));
|
|
8780
8954
|
}
|
|
8781
|
-
function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath,
|
|
8782
|
-
const normalizedInput =
|
|
8783
|
-
return knowledgeBases.some((kb) => normalizeKnowledgeBasePath2(kb,
|
|
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,
|
|
8786
|
-
const normalizedInput =
|
|
8959
|
+
function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot3) {
|
|
8960
|
+
const normalizedInput = path13.normalize(inputPath);
|
|
8787
8961
|
return knowledgeBases.findIndex(
|
|
8788
|
-
(kb) =>
|
|
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
|
|
8992
|
-
function normalizeKnowledgeBasePaths(config,
|
|
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,
|
|
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(
|
|
9008
|
-
return resolveWritableProjectConfigPath(
|
|
9222
|
+
function getConfigPath(projectRoot3, host = "opencode") {
|
|
9223
|
+
return resolveWritableProjectConfigPath(projectRoot3, host);
|
|
9009
9224
|
}
|
|
9010
|
-
function loadRuntimeConfig(
|
|
9011
|
-
return normalizeKnowledgeBasePaths(toConfigRecord(loadMergedConfig(
|
|
9225
|
+
function loadRuntimeConfig(projectRoot3, host = "opencode") {
|
|
9226
|
+
return normalizeKnowledgeBasePaths(toConfigRecord(loadMergedConfig(projectRoot3, host)), projectRoot3);
|
|
9012
9227
|
}
|
|
9013
|
-
function loadEditableConfig(
|
|
9014
|
-
return normalizeKnowledgeBasePaths(toConfigRecord(loadProjectConfigLayer(
|
|
9228
|
+
function loadEditableConfig(projectRoot3, host = "opencode") {
|
|
9229
|
+
return normalizeKnowledgeBasePaths(toConfigRecord(loadProjectConfigLayer(projectRoot3, host)), projectRoot3);
|
|
9015
9230
|
}
|
|
9016
|
-
function saveConfig(
|
|
9017
|
-
const configPath = getConfigPath(
|
|
9018
|
-
const configDir =
|
|
9019
|
-
const configBaseDir =
|
|
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(
|
|
9037
|
-
if (
|
|
9038
|
-
return
|
|
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(
|
|
9047
|
-
return `${host}::${
|
|
9261
|
+
function getIndexerCacheKey(projectRoot3, host) {
|
|
9262
|
+
return `${host}::${projectRoot3}`;
|
|
9048
9263
|
}
|
|
9049
|
-
function getOrCreateIndexer(
|
|
9050
|
-
const key = getIndexerCacheKey(
|
|
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(
|
|
9056
|
-
const indexer = new Indexer(
|
|
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(
|
|
9062
|
-
const root = getProjectRoot(
|
|
9276
|
+
function getIndexerForProject(projectRoot3, host = "opencode") {
|
|
9277
|
+
const root = getProjectRoot(projectRoot3, host);
|
|
9063
9278
|
return getOrCreateIndexer(root, host);
|
|
9064
9279
|
}
|
|
9065
|
-
function refreshIndexerForDirectory(
|
|
9066
|
-
const key = getIndexerCacheKey(
|
|
9067
|
-
const indexer = new Indexer(
|
|
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(
|
|
9072
|
-
const root = getProjectRoot(
|
|
9073
|
-
const localIndexPath =
|
|
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(
|
|
9081
|
-
const indexer = getIndexerForProject(
|
|
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(
|
|
9092
|
-
const indexer = getIndexerForProject(
|
|
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(
|
|
9101
|
-
const indexer = getIndexerForProject(
|
|
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(
|
|
9109
|
-
const indexer = getIndexerForProject(
|
|
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(
|
|
9121
|
-
const indexer = getIndexerForProject(
|
|
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(
|
|
9125
|
-
const root = getProjectRoot(
|
|
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(
|
|
9158
|
-
const indexer = getIndexerForProject(
|
|
9375
|
+
async function getIndexStatus(projectRoot3, host) {
|
|
9376
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9159
9377
|
return indexer.getStatus();
|
|
9160
9378
|
}
|
|
9161
|
-
async function getIndexHealthCheck(
|
|
9162
|
-
const indexer = getIndexerForProject(
|
|
9379
|
+
async function getIndexHealthCheck(projectRoot3, host) {
|
|
9380
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9163
9381
|
return indexer.healthCheck();
|
|
9164
9382
|
}
|
|
9165
|
-
async function getPrImpact(
|
|
9166
|
-
const indexer = getIndexerForProject(
|
|
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(
|
|
9177
|
-
const indexer = getIndexerForProject(
|
|
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(
|
|
9200
|
-
const indexer = getIndexerForProject(
|
|
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
|
|
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:
|
|
9444
|
+
return { kind: "entries", text: text3 };
|
|
9227
9445
|
}
|
|
9228
|
-
function addKnowledgeBase(
|
|
9229
|
-
const root = getProjectRoot(
|
|
9446
|
+
function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
9447
|
+
const root = getProjectRoot(projectRoot3, host);
|
|
9230
9448
|
const inputPath = knowledgeBasePath.trim();
|
|
9231
|
-
const normalizedPath =
|
|
9232
|
-
|
|
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 =
|
|
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(
|
|
9302
|
-
const root = getProjectRoot(
|
|
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)(
|
|
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(
|
|
9341
|
-
const root = getProjectRoot(
|
|
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-
|
|
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(
|
|
9384
|
-
return { content: [{ type: "text", text:
|
|
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:
|
|
9395
|
-
query:
|
|
9396
|
-
limit:
|
|
9397
|
-
fileType:
|
|
9398
|
-
directory:
|
|
9399
|
-
chunkType:
|
|
9400
|
-
contextLines:
|
|
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(
|
|
9404
|
-
return
|
|
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:
|
|
9412
|
-
query:
|
|
9413
|
-
limit:
|
|
9414
|
-
fileType:
|
|
9415
|
-
directory:
|
|
9416
|
-
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(
|
|
9420
|
-
return
|
|
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:
|
|
9428
|
-
code:
|
|
9429
|
-
limit:
|
|
9430
|
-
fileType:
|
|
9431
|
-
directory:
|
|
9432
|
-
chunkType:
|
|
9433
|
-
excludeFile:
|
|
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(
|
|
9437
|
-
return
|
|
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:
|
|
9445
|
-
query:
|
|
9446
|
-
limit:
|
|
9447
|
-
fileType:
|
|
9448
|
-
directory:
|
|
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(
|
|
9452
|
-
return
|
|
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:
|
|
9460
|
-
force:
|
|
9461
|
-
estimateOnly:
|
|
9462
|
-
verbose:
|
|
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(
|
|
9466
|
-
return result.kind === "estimate" ?
|
|
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:
|
|
9744
|
+
parameters: import_typebox2.Type.Object({}),
|
|
9474
9745
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
9475
|
-
const status = await getIndexStatus(
|
|
9476
|
-
return
|
|
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:
|
|
9754
|
+
parameters: import_typebox2.Type.Object({}),
|
|
9484
9755
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
9485
|
-
const result = await getIndexHealthCheck(
|
|
9486
|
-
return
|
|
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:
|
|
9764
|
+
parameters: import_typebox2.Type.Object({}),
|
|
9494
9765
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
9495
|
-
const result = await getIndexMetrics(
|
|
9496
|
-
return
|
|
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:
|
|
9504
|
-
limit:
|
|
9505
|
-
category:
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
|
|
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:
|
|
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(
|
|
9517
|
-
return
|
|
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:
|
|
9554
|
-
pr:
|
|
9555
|
-
branch:
|
|
9556
|
-
maxDepth:
|
|
9557
|
-
hubThreshold:
|
|
9558
|
-
checkConflicts:
|
|
9559
|
-
direction:
|
|
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(
|
|
9563
|
-
return
|
|
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:
|
|
9813
|
+
parameters: import_typebox2.Type.Object({}),
|
|
9571
9814
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
9572
|
-
return
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
9833
|
+
return text2(removeKnowledgeBase(projectRoot2(ctx), HOST2, params.path));
|
|
9591
9834
|
}
|
|
9592
9835
|
});
|
|
9593
9836
|
}
|