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.js
CHANGED
|
@@ -490,7 +490,7 @@ var require_ignore = __commonJS({
|
|
|
490
490
|
// path matching.
|
|
491
491
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
492
492
|
// @returns {TestResult} true if a file is ignored
|
|
493
|
-
test(
|
|
493
|
+
test(path16, checkUnignored, mode) {
|
|
494
494
|
let ignored = false;
|
|
495
495
|
let unignored = false;
|
|
496
496
|
let matchedRule;
|
|
@@ -499,7 +499,7 @@ var require_ignore = __commonJS({
|
|
|
499
499
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
500
500
|
return;
|
|
501
501
|
}
|
|
502
|
-
const matched = rule[mode].test(
|
|
502
|
+
const matched = rule[mode].test(path16);
|
|
503
503
|
if (!matched) {
|
|
504
504
|
return;
|
|
505
505
|
}
|
|
@@ -520,17 +520,17 @@ var require_ignore = __commonJS({
|
|
|
520
520
|
var throwError = (message, Ctor) => {
|
|
521
521
|
throw new Ctor(message);
|
|
522
522
|
};
|
|
523
|
-
var checkPath = (
|
|
524
|
-
if (!isString(
|
|
523
|
+
var checkPath = (path16, originalPath, doThrow) => {
|
|
524
|
+
if (!isString(path16)) {
|
|
525
525
|
return doThrow(
|
|
526
526
|
`path must be a string, but got \`${originalPath}\``,
|
|
527
527
|
TypeError
|
|
528
528
|
);
|
|
529
529
|
}
|
|
530
|
-
if (!
|
|
530
|
+
if (!path16) {
|
|
531
531
|
return doThrow(`path must not be empty`, TypeError);
|
|
532
532
|
}
|
|
533
|
-
if (checkPath.isNotRelative(
|
|
533
|
+
if (checkPath.isNotRelative(path16)) {
|
|
534
534
|
const r = "`path.relative()`d";
|
|
535
535
|
return doThrow(
|
|
536
536
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -539,7 +539,7 @@ var require_ignore = __commonJS({
|
|
|
539
539
|
}
|
|
540
540
|
return true;
|
|
541
541
|
};
|
|
542
|
-
var isNotRelative = (
|
|
542
|
+
var isNotRelative = (path16) => REGEX_TEST_INVALID_PATH.test(path16);
|
|
543
543
|
checkPath.isNotRelative = isNotRelative;
|
|
544
544
|
checkPath.convert = (p) => p;
|
|
545
545
|
var Ignore2 = class {
|
|
@@ -569,19 +569,19 @@ var require_ignore = __commonJS({
|
|
|
569
569
|
}
|
|
570
570
|
// @returns {TestResult}
|
|
571
571
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
572
|
-
const
|
|
572
|
+
const path16 = originalPath && checkPath.convert(originalPath);
|
|
573
573
|
checkPath(
|
|
574
|
-
|
|
574
|
+
path16,
|
|
575
575
|
originalPath,
|
|
576
576
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
577
577
|
);
|
|
578
|
-
return this._t(
|
|
578
|
+
return this._t(path16, cache, checkUnignored, slices);
|
|
579
579
|
}
|
|
580
|
-
checkIgnore(
|
|
581
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
582
|
-
return this.test(
|
|
580
|
+
checkIgnore(path16) {
|
|
581
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path16)) {
|
|
582
|
+
return this.test(path16);
|
|
583
583
|
}
|
|
584
|
-
const slices =
|
|
584
|
+
const slices = path16.split(SLASH).filter(Boolean);
|
|
585
585
|
slices.pop();
|
|
586
586
|
if (slices.length) {
|
|
587
587
|
const parent = this._t(
|
|
@@ -594,18 +594,18 @@ var require_ignore = __commonJS({
|
|
|
594
594
|
return parent;
|
|
595
595
|
}
|
|
596
596
|
}
|
|
597
|
-
return this._rules.test(
|
|
597
|
+
return this._rules.test(path16, false, MODE_CHECK_IGNORE);
|
|
598
598
|
}
|
|
599
|
-
_t(
|
|
600
|
-
if (
|
|
601
|
-
return cache[
|
|
599
|
+
_t(path16, cache, checkUnignored, slices) {
|
|
600
|
+
if (path16 in cache) {
|
|
601
|
+
return cache[path16];
|
|
602
602
|
}
|
|
603
603
|
if (!slices) {
|
|
604
|
-
slices =
|
|
604
|
+
slices = path16.split(SLASH).filter(Boolean);
|
|
605
605
|
}
|
|
606
606
|
slices.pop();
|
|
607
607
|
if (!slices.length) {
|
|
608
|
-
return cache[
|
|
608
|
+
return cache[path16] = this._rules.test(path16, checkUnignored, MODE_IGNORE);
|
|
609
609
|
}
|
|
610
610
|
const parent = this._t(
|
|
611
611
|
slices.join(SLASH) + SLASH,
|
|
@@ -613,29 +613,29 @@ var require_ignore = __commonJS({
|
|
|
613
613
|
checkUnignored,
|
|
614
614
|
slices
|
|
615
615
|
);
|
|
616
|
-
return cache[
|
|
616
|
+
return cache[path16] = parent.ignored ? parent : this._rules.test(path16, checkUnignored, MODE_IGNORE);
|
|
617
617
|
}
|
|
618
|
-
ignores(
|
|
619
|
-
return this._test(
|
|
618
|
+
ignores(path16) {
|
|
619
|
+
return this._test(path16, this._ignoreCache, false).ignored;
|
|
620
620
|
}
|
|
621
621
|
createFilter() {
|
|
622
|
-
return (
|
|
622
|
+
return (path16) => !this.ignores(path16);
|
|
623
623
|
}
|
|
624
624
|
filter(paths) {
|
|
625
625
|
return makeArray(paths).filter(this.createFilter());
|
|
626
626
|
}
|
|
627
627
|
// @returns {TestResult}
|
|
628
|
-
test(
|
|
629
|
-
return this._test(
|
|
628
|
+
test(path16) {
|
|
629
|
+
return this._test(path16, this._testCache, true);
|
|
630
630
|
}
|
|
631
631
|
};
|
|
632
632
|
var factory = (options) => new Ignore2(options);
|
|
633
|
-
var isPathValid = (
|
|
633
|
+
var isPathValid = (path16) => checkPath(path16 && checkPath.convert(path16), path16, RETURN_FALSE);
|
|
634
634
|
var setupWindows = () => {
|
|
635
635
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
636
636
|
checkPath.convert = makePosix;
|
|
637
637
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
638
|
-
checkPath.isNotRelative = (
|
|
638
|
+
checkPath.isNotRelative = (path16) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path16) || isNotRelative(path16);
|
|
639
639
|
};
|
|
640
640
|
if (
|
|
641
641
|
// Detect `process` so that it can run in browsers.
|
|
@@ -651,7 +651,7 @@ var require_ignore = __commonJS({
|
|
|
651
651
|
});
|
|
652
652
|
|
|
653
653
|
// src/pi-extension.ts
|
|
654
|
-
import { Type } from "typebox";
|
|
654
|
+
import { Type as Type2 } from "typebox";
|
|
655
655
|
|
|
656
656
|
// src/config/constants.ts
|
|
657
657
|
var DEFAULT_INCLUDE = [
|
|
@@ -783,7 +783,8 @@ function getDefaultIndexingConfig() {
|
|
|
783
783
|
requireProjectMarker: true,
|
|
784
784
|
maxDepth: 5,
|
|
785
785
|
maxFilesPerDirectory: 100,
|
|
786
|
-
fallbackToTextOnMaxChunks: true
|
|
786
|
+
fallbackToTextOnMaxChunks: true,
|
|
787
|
+
gitBlame: { enabled: false }
|
|
787
788
|
};
|
|
788
789
|
}
|
|
789
790
|
function getDefaultSearchConfig() {
|
|
@@ -907,7 +908,10 @@ function parseConfig(raw) {
|
|
|
907
908
|
requireProjectMarker: typeof rawIndexing.requireProjectMarker === "boolean" ? rawIndexing.requireProjectMarker : defaultIndexing.requireProjectMarker,
|
|
908
909
|
maxDepth: typeof rawIndexing.maxDepth === "number" ? rawIndexing.maxDepth < -1 ? -1 : rawIndexing.maxDepth : defaultIndexing.maxDepth,
|
|
909
910
|
maxFilesPerDirectory: typeof rawIndexing.maxFilesPerDirectory === "number" ? Math.max(1, rawIndexing.maxFilesPerDirectory) : defaultIndexing.maxFilesPerDirectory,
|
|
910
|
-
fallbackToTextOnMaxChunks: typeof rawIndexing.fallbackToTextOnMaxChunks === "boolean" ? rawIndexing.fallbackToTextOnMaxChunks : defaultIndexing.fallbackToTextOnMaxChunks
|
|
911
|
+
fallbackToTextOnMaxChunks: typeof rawIndexing.fallbackToTextOnMaxChunks === "boolean" ? rawIndexing.fallbackToTextOnMaxChunks : defaultIndexing.fallbackToTextOnMaxChunks,
|
|
912
|
+
gitBlame: {
|
|
913
|
+
enabled: rawIndexing.gitBlame && typeof rawIndexing.gitBlame === "object" && typeof rawIndexing.gitBlame.enabled === "boolean" ? rawIndexing.gitBlame.enabled : defaultIndexing.gitBlame.enabled
|
|
914
|
+
}
|
|
911
915
|
};
|
|
912
916
|
const rawSearch = input.search && typeof input.search === "object" ? input.search : {};
|
|
913
917
|
const search = {
|
|
@@ -1324,7 +1328,7 @@ function formatPrImpact(result) {
|
|
|
1324
1328
|
|
|
1325
1329
|
// src/tools/operations.ts
|
|
1326
1330
|
import { existsSync as existsSync9, realpathSync, statSync as statSync3 } from "fs";
|
|
1327
|
-
import * as
|
|
1331
|
+
import * as path15 from "path";
|
|
1328
1332
|
|
|
1329
1333
|
// src/config/merger.ts
|
|
1330
1334
|
import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
|
|
@@ -1494,21 +1498,21 @@ function getProjectIndexRelativePath(host) {
|
|
|
1494
1498
|
return CODEBASE_PROJECT_INDEX_RELATIVE_PATH;
|
|
1495
1499
|
}
|
|
1496
1500
|
}
|
|
1497
|
-
function resolveWorktreeFallbackPath(
|
|
1498
|
-
const mainRepoRoot = resolveWorktreeMainRepoRoot(
|
|
1501
|
+
function resolveWorktreeFallbackPath(projectRoot3, relativePath) {
|
|
1502
|
+
const mainRepoRoot = resolveWorktreeMainRepoRoot(projectRoot3);
|
|
1499
1503
|
if (!mainRepoRoot) {
|
|
1500
1504
|
return null;
|
|
1501
1505
|
}
|
|
1502
1506
|
const fallbackPath = path4.join(mainRepoRoot, relativePath);
|
|
1503
1507
|
return existsSync4(fallbackPath) ? fallbackPath : null;
|
|
1504
1508
|
}
|
|
1505
|
-
function resolveWorktreeFallbackProjectIndexPath(
|
|
1506
|
-
const inheritedHostPath = resolveWorktreeFallbackPath(
|
|
1509
|
+
function resolveWorktreeFallbackProjectIndexPath(projectRoot3, host) {
|
|
1510
|
+
const inheritedHostPath = resolveWorktreeFallbackPath(projectRoot3, getProjectIndexRelativePath(host));
|
|
1507
1511
|
if (inheritedHostPath) {
|
|
1508
1512
|
return inheritedHostPath;
|
|
1509
1513
|
}
|
|
1510
1514
|
if (host !== "opencode") {
|
|
1511
|
-
return resolveWorktreeFallbackPath(
|
|
1515
|
+
return resolveWorktreeFallbackPath(projectRoot3, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
|
|
1512
1516
|
}
|
|
1513
1517
|
return null;
|
|
1514
1518
|
}
|
|
@@ -1518,8 +1522,8 @@ function getHostProjectConfigRelativePath(host) {
|
|
|
1518
1522
|
function getHostProjectIndexRelativePath(host) {
|
|
1519
1523
|
return getProjectIndexRelativePath(host);
|
|
1520
1524
|
}
|
|
1521
|
-
function hasHostProjectConfig(
|
|
1522
|
-
return existsSync4(path4.join(
|
|
1525
|
+
function hasHostProjectConfig(projectRoot3, host) {
|
|
1526
|
+
return existsSync4(path4.join(projectRoot3, getProjectConfigRelativePath(host)));
|
|
1523
1527
|
}
|
|
1524
1528
|
function getGlobalIndexPath(host = "opencode") {
|
|
1525
1529
|
switch (host) {
|
|
@@ -1567,55 +1571,55 @@ function resolveGlobalIndexPath(host = "opencode") {
|
|
|
1567
1571
|
}
|
|
1568
1572
|
return hostIndexPath;
|
|
1569
1573
|
}
|
|
1570
|
-
function resolveProjectConfigPath(
|
|
1571
|
-
const hostConfigPath = path4.join(
|
|
1574
|
+
function resolveProjectConfigPath(projectRoot3, host = "opencode") {
|
|
1575
|
+
const hostConfigPath = path4.join(projectRoot3, getProjectConfigRelativePath(host));
|
|
1572
1576
|
if (existsSync4(hostConfigPath)) {
|
|
1573
1577
|
return hostConfigPath;
|
|
1574
1578
|
}
|
|
1575
1579
|
if (host !== "opencode") {
|
|
1576
|
-
const legacyConfigPath = path4.join(
|
|
1580
|
+
const legacyConfigPath = path4.join(projectRoot3, OPENCODE_PROJECT_CONFIG_RELATIVE_PATH);
|
|
1577
1581
|
if (existsSync4(legacyConfigPath)) {
|
|
1578
1582
|
return legacyConfigPath;
|
|
1579
1583
|
}
|
|
1580
1584
|
}
|
|
1581
|
-
const hostFallback = resolveWorktreeFallbackPath(
|
|
1585
|
+
const hostFallback = resolveWorktreeFallbackPath(projectRoot3, getProjectConfigRelativePath(host));
|
|
1582
1586
|
if (hostFallback) {
|
|
1583
1587
|
return hostFallback;
|
|
1584
1588
|
}
|
|
1585
1589
|
if (host !== "opencode") {
|
|
1586
|
-
const legacyFallback = resolveWorktreeFallbackPath(
|
|
1590
|
+
const legacyFallback = resolveWorktreeFallbackPath(projectRoot3, OPENCODE_PROJECT_CONFIG_RELATIVE_PATH);
|
|
1587
1591
|
if (legacyFallback) {
|
|
1588
1592
|
return legacyFallback;
|
|
1589
1593
|
}
|
|
1590
1594
|
}
|
|
1591
1595
|
return hostConfigPath;
|
|
1592
1596
|
}
|
|
1593
|
-
function resolveWritableProjectConfigPath(
|
|
1594
|
-
return path4.join(
|
|
1597
|
+
function resolveWritableProjectConfigPath(projectRoot3, host = "opencode") {
|
|
1598
|
+
return path4.join(projectRoot3, getProjectConfigRelativePath(host));
|
|
1595
1599
|
}
|
|
1596
|
-
function resolveProjectIndexPath(
|
|
1600
|
+
function resolveProjectIndexPath(projectRoot3, scope, host = "opencode") {
|
|
1597
1601
|
if (scope === "global") {
|
|
1598
1602
|
return resolveGlobalIndexPath(host);
|
|
1599
1603
|
}
|
|
1600
|
-
const localIndexPath = path4.join(
|
|
1604
|
+
const localIndexPath = path4.join(projectRoot3, getProjectIndexRelativePath(host));
|
|
1601
1605
|
if (existsSync4(localIndexPath)) {
|
|
1602
1606
|
return localIndexPath;
|
|
1603
1607
|
}
|
|
1604
1608
|
if (host !== "opencode") {
|
|
1605
|
-
const legacyIndexPath = path4.join(
|
|
1606
|
-
if (existsSync4(legacyIndexPath) && !hasHostProjectConfig(
|
|
1609
|
+
const legacyIndexPath = path4.join(projectRoot3, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
|
|
1610
|
+
if (existsSync4(legacyIndexPath) && !hasHostProjectConfig(projectRoot3, host)) {
|
|
1607
1611
|
return legacyIndexPath;
|
|
1608
1612
|
}
|
|
1609
1613
|
}
|
|
1610
|
-
if (hasHostProjectConfig(
|
|
1614
|
+
if (hasHostProjectConfig(projectRoot3, host)) {
|
|
1611
1615
|
return localIndexPath;
|
|
1612
1616
|
}
|
|
1613
|
-
const hostFallback = resolveWorktreeFallbackPath(
|
|
1617
|
+
const hostFallback = resolveWorktreeFallbackPath(projectRoot3, getProjectIndexRelativePath(host));
|
|
1614
1618
|
if (hostFallback) {
|
|
1615
1619
|
return hostFallback;
|
|
1616
1620
|
}
|
|
1617
1621
|
if (host !== "opencode") {
|
|
1618
|
-
const legacyFallback = resolveWorktreeFallbackPath(
|
|
1622
|
+
const legacyFallback = resolveWorktreeFallbackPath(projectRoot3, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
|
|
1619
1623
|
if (legacyFallback) {
|
|
1620
1624
|
return legacyFallback;
|
|
1621
1625
|
}
|
|
@@ -1748,14 +1752,14 @@ function loadJsonFile(filePath) {
|
|
|
1748
1752
|
throw new Error(`Failed to load config file ${filePath}: ${message}`);
|
|
1749
1753
|
}
|
|
1750
1754
|
}
|
|
1751
|
-
function materializeLocalProjectConfig(
|
|
1752
|
-
const localConfigPath = resolveWritableProjectConfigPath(
|
|
1755
|
+
function materializeLocalProjectConfig(projectRoot3, config, host = "opencode") {
|
|
1756
|
+
const localConfigPath = resolveWritableProjectConfigPath(projectRoot3, host);
|
|
1753
1757
|
mkdirSync(path7.dirname(localConfigPath), { recursive: true });
|
|
1754
1758
|
writeFileSync(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
1755
1759
|
return localConfigPath;
|
|
1756
1760
|
}
|
|
1757
|
-
function loadProjectConfigLayer(
|
|
1758
|
-
const projectConfigPath = resolveProjectConfigPath(
|
|
1761
|
+
function loadProjectConfigLayer(projectRoot3, host = "opencode") {
|
|
1762
|
+
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
1759
1763
|
const projectConfig = loadJsonFile(projectConfigPath);
|
|
1760
1764
|
if (!projectConfig) {
|
|
1761
1765
|
return {};
|
|
@@ -1766,14 +1770,14 @@ function loadProjectConfigLayer(projectRoot2, host = "opencode") {
|
|
|
1766
1770
|
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
1767
1771
|
normalizedConfig.knowledgeBases,
|
|
1768
1772
|
projectConfigBaseDir,
|
|
1769
|
-
|
|
1773
|
+
projectRoot3
|
|
1770
1774
|
);
|
|
1771
1775
|
}
|
|
1772
1776
|
return normalizedConfig;
|
|
1773
1777
|
}
|
|
1774
|
-
function loadMergedConfig(
|
|
1778
|
+
function loadMergedConfig(projectRoot3, host = "opencode") {
|
|
1775
1779
|
const globalConfigPath = resolveGlobalConfigPath(host);
|
|
1776
|
-
const projectConfigPath = resolveProjectConfigPath(
|
|
1780
|
+
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
1777
1781
|
let globalConfig = null;
|
|
1778
1782
|
let globalConfigError = null;
|
|
1779
1783
|
try {
|
|
@@ -1782,7 +1786,7 @@ function loadMergedConfig(projectRoot2, host = "opencode") {
|
|
|
1782
1786
|
globalConfigError = error instanceof Error ? error : new Error(String(error));
|
|
1783
1787
|
}
|
|
1784
1788
|
const projectConfig = loadJsonFile(projectConfigPath);
|
|
1785
|
-
const normalizedProjectConfig = loadProjectConfigLayer(
|
|
1789
|
+
const normalizedProjectConfig = loadProjectConfigLayer(projectRoot3, host);
|
|
1786
1790
|
if (globalConfigError) {
|
|
1787
1791
|
if (!projectConfig) {
|
|
1788
1792
|
throw globalConfigError;
|
|
@@ -1826,10 +1830,10 @@ function loadMergedConfig(projectRoot2, host = "opencode") {
|
|
|
1826
1830
|
|
|
1827
1831
|
// src/indexer/index.ts
|
|
1828
1832
|
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync2, renameSync, unlinkSync, mkdirSync as mkdirSync2, promises as fsPromises2 } from "fs";
|
|
1829
|
-
import * as
|
|
1833
|
+
import * as path12 from "path";
|
|
1830
1834
|
import { performance as performance2 } from "perf_hooks";
|
|
1831
|
-
import { execFile as
|
|
1832
|
-
import { promisify as
|
|
1835
|
+
import { execFile as execFile3 } from "child_process";
|
|
1836
|
+
import { promisify as promisify3 } from "util";
|
|
1833
1837
|
|
|
1834
1838
|
// node_modules/eventemitter3/index.mjs
|
|
1835
1839
|
var import_index = __toESM(require_eventemitter3(), 1);
|
|
@@ -3137,10 +3141,10 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
|
|
|
3137
3141
|
}
|
|
3138
3142
|
const batchResults = await Promise.all(
|
|
3139
3143
|
batches.map(async (batch) => {
|
|
3140
|
-
const requests = batch.map((
|
|
3144
|
+
const requests = batch.map((text3) => ({
|
|
3141
3145
|
model: `models/${this.modelInfo.model}`,
|
|
3142
3146
|
content: {
|
|
3143
|
-
parts: [{ text:
|
|
3147
|
+
parts: [{ text: text3 }]
|
|
3144
3148
|
},
|
|
3145
3149
|
taskType,
|
|
3146
3150
|
outputDimensionality: this.modelInfo.dimensions
|
|
@@ -3163,7 +3167,7 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
|
|
|
3163
3167
|
const data = await response.json();
|
|
3164
3168
|
return {
|
|
3165
3169
|
embeddings: data.embeddings.map((e) => e.values),
|
|
3166
|
-
tokensUsed: batch.reduce((sum,
|
|
3170
|
+
tokensUsed: batch.reduce((sum, text3) => sum + Math.ceil(text3.length / 4), 0)
|
|
3167
3171
|
};
|
|
3168
3172
|
})
|
|
3169
3173
|
);
|
|
@@ -3180,28 +3184,28 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3180
3184
|
constructor(credentials, modelInfo) {
|
|
3181
3185
|
super(credentials, modelInfo);
|
|
3182
3186
|
}
|
|
3183
|
-
estimateTokens(
|
|
3184
|
-
return Math.ceil(
|
|
3187
|
+
estimateTokens(text3) {
|
|
3188
|
+
return Math.ceil(text3.length / 4);
|
|
3185
3189
|
}
|
|
3186
|
-
truncateToCharLimit(
|
|
3187
|
-
if (
|
|
3188
|
-
return
|
|
3190
|
+
truncateToCharLimit(text3, maxChars) {
|
|
3191
|
+
if (text3.length <= maxChars) {
|
|
3192
|
+
return text3;
|
|
3189
3193
|
}
|
|
3190
|
-
return `${
|
|
3194
|
+
return `${text3.slice(0, Math.max(0, maxChars - 17))}
|
|
3191
3195
|
... [truncated]`;
|
|
3192
3196
|
}
|
|
3193
3197
|
isContextLengthError(error) {
|
|
3194
3198
|
const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
|
|
3195
3199
|
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");
|
|
3196
3200
|
}
|
|
3197
|
-
buildTruncationCandidates(
|
|
3201
|
+
buildTruncationCandidates(text3) {
|
|
3198
3202
|
const baseMaxChars = Math.max(1, this.modelInfo.maxTokens * 4);
|
|
3199
3203
|
const candidateLimits = /* @__PURE__ */ new Set();
|
|
3200
|
-
const baselineLimit =
|
|
3204
|
+
const baselineLimit = text3.length > baseMaxChars ? baseMaxChars : Math.max(
|
|
3201
3205
|
_OllamaEmbeddingProvider.MIN_TRUNCATION_CHARS,
|
|
3202
|
-
Math.floor(
|
|
3206
|
+
Math.floor(text3.length * 0.9)
|
|
3203
3207
|
);
|
|
3204
|
-
if (baselineLimit <
|
|
3208
|
+
if (baselineLimit < text3.length) {
|
|
3205
3209
|
candidateLimits.add(baselineLimit);
|
|
3206
3210
|
}
|
|
3207
3211
|
for (const factor of [0.75, 0.6, 0.45, 0.35, 0.25]) {
|
|
@@ -3209,19 +3213,19 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3209
3213
|
_OllamaEmbeddingProvider.MIN_TRUNCATION_CHARS,
|
|
3210
3214
|
Math.floor(baselineLimit * factor)
|
|
3211
3215
|
);
|
|
3212
|
-
if (scaledLimit <
|
|
3216
|
+
if (scaledLimit < text3.length) {
|
|
3213
3217
|
candidateLimits.add(scaledLimit);
|
|
3214
3218
|
}
|
|
3215
3219
|
}
|
|
3216
|
-
candidateLimits.add(Math.min(
|
|
3220
|
+
candidateLimits.add(Math.min(text3.length - 1, _OllamaEmbeddingProvider.MIN_TRUNCATION_CHARS));
|
|
3217
3221
|
const candidates = [];
|
|
3218
3222
|
const seen = /* @__PURE__ */ new Set();
|
|
3219
3223
|
for (const limit of [...candidateLimits].sort((a, b) => b - a)) {
|
|
3220
|
-
if (limit <= 0 || limit >=
|
|
3224
|
+
if (limit <= 0 || limit >= text3.length) {
|
|
3221
3225
|
continue;
|
|
3222
3226
|
}
|
|
3223
|
-
const truncated = this.truncateToCharLimit(
|
|
3224
|
-
if (truncated ===
|
|
3227
|
+
const truncated = this.truncateToCharLimit(text3, limit);
|
|
3228
|
+
if (truncated === text3 || seen.has(truncated)) {
|
|
3225
3229
|
continue;
|
|
3226
3230
|
}
|
|
3227
3231
|
seen.add(truncated);
|
|
@@ -3229,15 +3233,15 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3229
3233
|
}
|
|
3230
3234
|
return candidates;
|
|
3231
3235
|
}
|
|
3232
|
-
async embedSingleWithFallback(
|
|
3236
|
+
async embedSingleWithFallback(text3) {
|
|
3233
3237
|
try {
|
|
3234
|
-
return await this.embedSingle(
|
|
3238
|
+
return await this.embedSingle(text3);
|
|
3235
3239
|
} catch (error) {
|
|
3236
3240
|
if (!this.isContextLengthError(error)) {
|
|
3237
3241
|
throw error;
|
|
3238
3242
|
}
|
|
3239
3243
|
let lastError = error;
|
|
3240
|
-
for (const truncated of this.buildTruncationCandidates(
|
|
3244
|
+
for (const truncated of this.buildTruncationCandidates(text3)) {
|
|
3241
3245
|
try {
|
|
3242
3246
|
return await this.embedSingle(truncated);
|
|
3243
3247
|
} catch (retryError) {
|
|
@@ -3250,7 +3254,7 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3250
3254
|
throw lastError;
|
|
3251
3255
|
}
|
|
3252
3256
|
}
|
|
3253
|
-
async embedSingle(
|
|
3257
|
+
async embedSingle(text3) {
|
|
3254
3258
|
const response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
|
|
3255
3259
|
method: "POST",
|
|
3256
3260
|
headers: {
|
|
@@ -3258,7 +3262,7 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3258
3262
|
},
|
|
3259
3263
|
body: JSON.stringify({
|
|
3260
3264
|
model: this.modelInfo.model,
|
|
3261
|
-
prompt:
|
|
3265
|
+
prompt: text3,
|
|
3262
3266
|
truncate: false
|
|
3263
3267
|
})
|
|
3264
3268
|
});
|
|
@@ -3269,13 +3273,13 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3269
3273
|
const data = await response.json();
|
|
3270
3274
|
return {
|
|
3271
3275
|
embedding: data.embedding,
|
|
3272
|
-
tokensUsed: this.estimateTokens(
|
|
3276
|
+
tokensUsed: this.estimateTokens(text3)
|
|
3273
3277
|
};
|
|
3274
3278
|
}
|
|
3275
3279
|
async embedBatch(texts) {
|
|
3276
3280
|
const results = [];
|
|
3277
|
-
for (const
|
|
3278
|
-
results.push(await this.embedSingleWithFallback(
|
|
3281
|
+
for (const text3 of texts) {
|
|
3282
|
+
results.push(await this.embedSingleWithFallback(text3));
|
|
3279
3283
|
}
|
|
3280
3284
|
return {
|
|
3281
3285
|
embeddings: results.map((r) => r.embedding),
|
|
@@ -3416,7 +3420,7 @@ var SiliconFlowReranker = class {
|
|
|
3416
3420
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
3417
3421
|
import { existsSync as existsSync6, readFileSync as readFileSync5, promises as fsPromises } from "fs";
|
|
3418
3422
|
import * as path8 from "path";
|
|
3419
|
-
function createIgnoreFilter(
|
|
3423
|
+
function createIgnoreFilter(projectRoot3) {
|
|
3420
3424
|
const ig = (0, import_ignore.default)();
|
|
3421
3425
|
const defaultIgnores = [
|
|
3422
3426
|
"node_modules",
|
|
@@ -3437,7 +3441,7 @@ function createIgnoreFilter(projectRoot2) {
|
|
|
3437
3441
|
"**/*build*/**"
|
|
3438
3442
|
];
|
|
3439
3443
|
ig.add(defaultIgnores);
|
|
3440
|
-
const gitignorePath = path8.join(
|
|
3444
|
+
const gitignorePath = path8.join(projectRoot3, ".gitignore");
|
|
3441
3445
|
if (existsSync6(gitignorePath)) {
|
|
3442
3446
|
const gitignoreContent = readFileSync5(gitignorePath, "utf-8");
|
|
3443
3447
|
ig.add(gitignoreContent);
|
|
@@ -3459,13 +3463,13 @@ function matchGlob(filePath, pattern) {
|
|
|
3459
3463
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
3460
3464
|
return regex.test(filePath);
|
|
3461
3465
|
}
|
|
3462
|
-
async function* walkDirectory(dir,
|
|
3466
|
+
async function* walkDirectory(dir, projectRoot3, includePatterns, excludePatterns, ignoreFilter, maxFileSize, skipped, options, currentDepth = 0) {
|
|
3463
3467
|
const entries = await fsPromises.readdir(dir, { withFileTypes: true });
|
|
3464
3468
|
const filesInDir = [];
|
|
3465
3469
|
const subdirs = [];
|
|
3466
3470
|
for (const entry of entries) {
|
|
3467
3471
|
const fullPath = path8.join(dir, entry.name);
|
|
3468
|
-
const relativePath = path8.relative(
|
|
3472
|
+
const relativePath = path8.relative(projectRoot3, fullPath);
|
|
3469
3473
|
if (isHiddenPathSegment(entry.name)) {
|
|
3470
3474
|
if (entry.isDirectory()) {
|
|
3471
3475
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
@@ -3514,14 +3518,14 @@ async function* walkDirectory(dir, projectRoot2, includePatterns, excludePattern
|
|
|
3514
3518
|
yield f;
|
|
3515
3519
|
}
|
|
3516
3520
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
3517
|
-
skipped.push({ path: path8.relative(
|
|
3521
|
+
skipped.push({ path: path8.relative(projectRoot3, filesInDir[i].path), reason: "excluded" });
|
|
3518
3522
|
}
|
|
3519
3523
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
3520
3524
|
if (canRecurse) {
|
|
3521
3525
|
for (const sub of subdirs) {
|
|
3522
3526
|
yield* walkDirectory(
|
|
3523
3527
|
sub.fullPath,
|
|
3524
|
-
|
|
3528
|
+
projectRoot3,
|
|
3525
3529
|
includePatterns,
|
|
3526
3530
|
excludePatterns,
|
|
3527
3531
|
ignoreFilter,
|
|
@@ -3533,14 +3537,14 @@ async function* walkDirectory(dir, projectRoot2, includePatterns, excludePattern
|
|
|
3533
3537
|
}
|
|
3534
3538
|
}
|
|
3535
3539
|
}
|
|
3536
|
-
async function collectFiles(
|
|
3540
|
+
async function collectFiles(projectRoot3, includePatterns, excludePatterns, maxFileSize, additionalRoots, walkOptions) {
|
|
3537
3541
|
const opts = walkOptions ?? { maxDepth: 5, maxFilesPerDirectory: 100 };
|
|
3538
|
-
const ignoreFilter = createIgnoreFilter(
|
|
3542
|
+
const ignoreFilter = createIgnoreFilter(projectRoot3);
|
|
3539
3543
|
const files = [];
|
|
3540
3544
|
const skipped = [];
|
|
3541
3545
|
for await (const file of walkDirectory(
|
|
3542
|
-
|
|
3543
|
-
|
|
3546
|
+
projectRoot3,
|
|
3547
|
+
projectRoot3,
|
|
3544
3548
|
includePatterns,
|
|
3545
3549
|
excludePatterns,
|
|
3546
3550
|
ignoreFilter,
|
|
@@ -3555,7 +3559,7 @@ async function collectFiles(projectRoot2, includePatterns, excludePatterns, maxF
|
|
|
3555
3559
|
const normalizedRoots = /* @__PURE__ */ new Set();
|
|
3556
3560
|
for (const kbRoot of additionalRoots) {
|
|
3557
3561
|
const resolved = path8.normalize(
|
|
3558
|
-
path8.isAbsolute(kbRoot) ? kbRoot : path8.resolve(
|
|
3562
|
+
path8.isAbsolute(kbRoot) ? kbRoot : path8.resolve(projectRoot3, kbRoot)
|
|
3559
3563
|
);
|
|
3560
3564
|
normalizedRoots.add(resolved);
|
|
3561
3565
|
}
|
|
@@ -4121,8 +4125,8 @@ var VectorStore = class {
|
|
|
4121
4125
|
var CHARS_PER_TOKEN = 4;
|
|
4122
4126
|
var MAX_BATCH_TOKENS = 7500;
|
|
4123
4127
|
var MAX_SINGLE_CHUNK_TOKENS = 2e3;
|
|
4124
|
-
function estimateTokens(
|
|
4125
|
-
return Math.ceil(
|
|
4128
|
+
function estimateTokens(text3) {
|
|
4129
|
+
return Math.ceil(text3.length / CHARS_PER_TOKEN);
|
|
4126
4130
|
}
|
|
4127
4131
|
function getEmbeddingHeaderParts(chunk, filePath) {
|
|
4128
4132
|
const parts = [];
|
|
@@ -4656,20 +4660,20 @@ function getErrorMessage(error) {
|
|
|
4656
4660
|
return String(error);
|
|
4657
4661
|
}
|
|
4658
4662
|
async function getChangedFiles(opts) {
|
|
4659
|
-
const { pr, branch, projectRoot:
|
|
4663
|
+
const { pr, branch, projectRoot: projectRoot3, baseBranch = "main" } = opts;
|
|
4660
4664
|
if (pr !== void 0) {
|
|
4661
|
-
return getChangedFilesForPr(pr,
|
|
4665
|
+
return getChangedFilesForPr(pr, projectRoot3, baseBranch);
|
|
4662
4666
|
}
|
|
4663
|
-
return getChangedFilesForBranch(branch,
|
|
4667
|
+
return getChangedFilesForBranch(branch, projectRoot3, baseBranch);
|
|
4664
4668
|
}
|
|
4665
|
-
async function getChangedFilesForPr(pr,
|
|
4669
|
+
async function getChangedFilesForPr(pr, projectRoot3, baseBranch) {
|
|
4666
4670
|
let headRefName;
|
|
4667
4671
|
let actualBaseBranch = baseBranch;
|
|
4668
4672
|
try {
|
|
4669
4673
|
const { stdout } = await execFileAsync(
|
|
4670
4674
|
"gh",
|
|
4671
4675
|
["pr", "view", String(pr), "--json", "headRefName,baseRefName,files"],
|
|
4672
|
-
{ cwd:
|
|
4676
|
+
{ cwd: projectRoot3, timeout: 3e4 }
|
|
4673
4677
|
);
|
|
4674
4678
|
const data = JSON.parse(stdout);
|
|
4675
4679
|
headRefName = data.headRefName;
|
|
@@ -4678,7 +4682,7 @@ async function getChangedFilesForPr(pr, projectRoot2, baseBranch) {
|
|
|
4678
4682
|
return {
|
|
4679
4683
|
files: normalizeFiles(
|
|
4680
4684
|
data.files.map((f) => f.path),
|
|
4681
|
-
|
|
4685
|
+
projectRoot3
|
|
4682
4686
|
),
|
|
4683
4687
|
baseBranch: actualBaseBranch,
|
|
4684
4688
|
source: "gh",
|
|
@@ -4695,49 +4699,49 @@ async function getChangedFilesForPr(pr, projectRoot2, baseBranch) {
|
|
|
4695
4699
|
`PR #${pr} returned no usable branch or file information.`
|
|
4696
4700
|
);
|
|
4697
4701
|
}
|
|
4698
|
-
const result = await getChangedFilesForBranch(headRefName,
|
|
4702
|
+
const result = await getChangedFilesForBranch(headRefName, projectRoot3, actualBaseBranch);
|
|
4699
4703
|
return { ...result, headRefName };
|
|
4700
4704
|
}
|
|
4701
|
-
async function getChangedFilesForBranch(branch,
|
|
4702
|
-
const targetBranch = branch || await getCurrentBranch2(
|
|
4703
|
-
const mergeBase = await getMergeBase(
|
|
4705
|
+
async function getChangedFilesForBranch(branch, projectRoot3, baseBranch) {
|
|
4706
|
+
const targetBranch = branch || await getCurrentBranch2(projectRoot3);
|
|
4707
|
+
const mergeBase = await getMergeBase(projectRoot3, baseBranch, targetBranch);
|
|
4704
4708
|
const { stdout } = await execFileAsync(
|
|
4705
4709
|
"git",
|
|
4706
4710
|
["diff", "--name-only", `${mergeBase}...${targetBranch}`],
|
|
4707
|
-
{ cwd:
|
|
4711
|
+
{ cwd: projectRoot3, timeout: 3e4 }
|
|
4708
4712
|
);
|
|
4709
4713
|
return {
|
|
4710
|
-
files: normalizeFiles(stdout.split("\n"),
|
|
4714
|
+
files: normalizeFiles(stdout.split("\n"), projectRoot3),
|
|
4711
4715
|
baseBranch,
|
|
4712
4716
|
source: "git",
|
|
4713
4717
|
headRefName: targetBranch
|
|
4714
4718
|
};
|
|
4715
4719
|
}
|
|
4716
|
-
async function getCurrentBranch2(
|
|
4720
|
+
async function getCurrentBranch2(projectRoot3) {
|
|
4717
4721
|
const { stdout } = await execFileAsync(
|
|
4718
4722
|
"git",
|
|
4719
4723
|
["branch", "--show-current"],
|
|
4720
|
-
{ cwd:
|
|
4724
|
+
{ cwd: projectRoot3, timeout: 3e4 }
|
|
4721
4725
|
);
|
|
4722
4726
|
return stdout.trim() || "HEAD";
|
|
4723
4727
|
}
|
|
4724
|
-
async function getMergeBase(
|
|
4728
|
+
async function getMergeBase(projectRoot3, baseBranch, branch) {
|
|
4725
4729
|
const { stdout } = await execFileAsync(
|
|
4726
4730
|
"git",
|
|
4727
4731
|
["merge-base", baseBranch, branch],
|
|
4728
|
-
{ cwd:
|
|
4732
|
+
{ cwd: projectRoot3, timeout: 3e4 }
|
|
4729
4733
|
);
|
|
4730
4734
|
return stdout.trim();
|
|
4731
4735
|
}
|
|
4732
|
-
function normalizeFiles(rawFiles,
|
|
4736
|
+
function normalizeFiles(rawFiles, projectRoot3) {
|
|
4733
4737
|
const seen = /* @__PURE__ */ new Set();
|
|
4734
4738
|
const result = [];
|
|
4735
4739
|
for (const raw of rawFiles) {
|
|
4736
4740
|
const trimmed = raw.trim();
|
|
4737
4741
|
if (!trimmed) continue;
|
|
4738
|
-
const absolute = path10.resolve(
|
|
4739
|
-
const
|
|
4740
|
-
const cleaned =
|
|
4742
|
+
const absolute = path10.resolve(projectRoot3, trimmed);
|
|
4743
|
+
const relative7 = path10.relative(projectRoot3, absolute);
|
|
4744
|
+
const cleaned = relative7.startsWith("./") ? relative7.slice(2) : relative7;
|
|
4741
4745
|
if (!seen.has(cleaned)) {
|
|
4742
4746
|
seen.add(cleaned);
|
|
4743
4747
|
result.push(cleaned);
|
|
@@ -4746,8 +4750,61 @@ function normalizeFiles(rawFiles, projectRoot2) {
|
|
|
4746
4750
|
return result;
|
|
4747
4751
|
}
|
|
4748
4752
|
|
|
4753
|
+
// src/indexer/git-blame.ts
|
|
4754
|
+
import { execFile as execFile2 } from "child_process";
|
|
4755
|
+
import * as path11 from "path";
|
|
4756
|
+
import { promisify as promisify2 } from "util";
|
|
4757
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
4758
|
+
function parseGitBlamePorcelain(output) {
|
|
4759
|
+
const commits = /* @__PURE__ */ new Map();
|
|
4760
|
+
let current;
|
|
4761
|
+
for (const line of output.split("\n")) {
|
|
4762
|
+
if (/^[0-9a-f]{40} /.test(line)) {
|
|
4763
|
+
const sha = line.slice(0, 40);
|
|
4764
|
+
current = commits.get(sha) ?? {
|
|
4765
|
+
sha,
|
|
4766
|
+
author: "",
|
|
4767
|
+
authorEmail: "",
|
|
4768
|
+
committedAt: 0,
|
|
4769
|
+
summary: "",
|
|
4770
|
+
lines: 0
|
|
4771
|
+
};
|
|
4772
|
+
commits.set(sha, current);
|
|
4773
|
+
continue;
|
|
4774
|
+
}
|
|
4775
|
+
if (!current) {
|
|
4776
|
+
continue;
|
|
4777
|
+
}
|
|
4778
|
+
if (line.startsWith("author ")) {
|
|
4779
|
+
current.author = line.slice("author ".length);
|
|
4780
|
+
} else if (line.startsWith("author-mail ")) {
|
|
4781
|
+
current.authorEmail = line.slice("author-mail ".length).replace(/^<|>$/g, "");
|
|
4782
|
+
} else if (line.startsWith("author-time ")) {
|
|
4783
|
+
current.committedAt = Number.parseInt(line.slice("author-time ".length), 10);
|
|
4784
|
+
} else if (line.startsWith("summary ")) {
|
|
4785
|
+
current.summary = line.slice("summary ".length);
|
|
4786
|
+
} else if (line.startsWith(" ")) {
|
|
4787
|
+
current.lines += 1;
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
|
|
4791
|
+
}
|
|
4792
|
+
async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
|
|
4793
|
+
const relativePath = path11.relative(projectRoot3, filePath);
|
|
4794
|
+
try {
|
|
4795
|
+
const { stdout } = await execFileAsync2(
|
|
4796
|
+
"git",
|
|
4797
|
+
["blame", "--line-porcelain", "-L", `${startLine},${endLine}`, "--", relativePath],
|
|
4798
|
+
{ cwd: projectRoot3, timeout: 3e4 }
|
|
4799
|
+
);
|
|
4800
|
+
return parseGitBlamePorcelain(stdout);
|
|
4801
|
+
} catch {
|
|
4802
|
+
return void 0;
|
|
4803
|
+
}
|
|
4804
|
+
}
|
|
4805
|
+
|
|
4749
4806
|
// src/indexer/index.ts
|
|
4750
|
-
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab"]);
|
|
4807
|
+
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab", "bash"]);
|
|
4751
4808
|
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
|
|
4752
4809
|
var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
4753
4810
|
"function_declaration",
|
|
@@ -4827,6 +4884,45 @@ function isSqliteCorruptionError(error) {
|
|
|
4827
4884
|
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");
|
|
4828
4885
|
}
|
|
4829
4886
|
var STARTUP_WARNING_METADATA_KEY = "index.startupWarning";
|
|
4887
|
+
function metadataFromBlame(blame) {
|
|
4888
|
+
if (!blame) {
|
|
4889
|
+
return {};
|
|
4890
|
+
}
|
|
4891
|
+
return {
|
|
4892
|
+
blameSha: blame.sha,
|
|
4893
|
+
blameAuthor: blame.author,
|
|
4894
|
+
blameAuthorEmail: blame.authorEmail,
|
|
4895
|
+
blameCommittedAt: blame.committedAt,
|
|
4896
|
+
blameSummary: blame.summary
|
|
4897
|
+
};
|
|
4898
|
+
}
|
|
4899
|
+
function blameFromChunkData(chunk) {
|
|
4900
|
+
if (!chunk?.blameSha || !chunk.blameAuthor || !chunk.blameAuthorEmail || chunk.blameCommittedAt === void 0 || !chunk.blameSummary) {
|
|
4901
|
+
return void 0;
|
|
4902
|
+
}
|
|
4903
|
+
return {
|
|
4904
|
+
sha: chunk.blameSha,
|
|
4905
|
+
author: chunk.blameAuthor,
|
|
4906
|
+
authorEmail: chunk.blameAuthorEmail,
|
|
4907
|
+
committedAt: chunk.blameCommittedAt,
|
|
4908
|
+
summary: chunk.blameSummary
|
|
4909
|
+
};
|
|
4910
|
+
}
|
|
4911
|
+
function blameFromMetadata(metadata) {
|
|
4912
|
+
if (!metadata.blameSha || !metadata.blameAuthor || !metadata.blameAuthorEmail || metadata.blameCommittedAt === void 0 || !metadata.blameSummary) {
|
|
4913
|
+
return void 0;
|
|
4914
|
+
}
|
|
4915
|
+
return {
|
|
4916
|
+
sha: metadata.blameSha,
|
|
4917
|
+
author: metadata.blameAuthor,
|
|
4918
|
+
authorEmail: metadata.blameAuthorEmail,
|
|
4919
|
+
committedAt: metadata.blameCommittedAt,
|
|
4920
|
+
summary: metadata.blameSummary
|
|
4921
|
+
};
|
|
4922
|
+
}
|
|
4923
|
+
function hasBlameMetadata(metadata) {
|
|
4924
|
+
return blameFromMetadata(metadata) !== void 0;
|
|
4925
|
+
}
|
|
4830
4926
|
var INDEX_METADATA_VERSION = "1";
|
|
4831
4927
|
var EMBEDDING_STRATEGY_VERSION = "2";
|
|
4832
4928
|
var RANKING_TOKEN_CACHE_LIMIT = 4096;
|
|
@@ -4870,9 +4966,9 @@ function normalizePendingChunk(rawChunk, maxChunkTokens) {
|
|
|
4870
4966
|
};
|
|
4871
4967
|
const filePath = typeof metadata.filePath === "string" ? metadata.filePath : "unknown";
|
|
4872
4968
|
texts.push(
|
|
4873
|
-
...createEmbeddingTexts(rebuiltChunk, filePath, maxChunkTokens).map((
|
|
4874
|
-
text:
|
|
4875
|
-
tokenCount: estimateTokens(
|
|
4969
|
+
...createEmbeddingTexts(rebuiltChunk, filePath, maxChunkTokens).map((text3) => ({
|
|
4970
|
+
text: text3,
|
|
4971
|
+
tokenCount: estimateTokens(text3)
|
|
4876
4972
|
}))
|
|
4877
4973
|
);
|
|
4878
4974
|
} else {
|
|
@@ -4985,9 +5081,9 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
4985
5081
|
return true;
|
|
4986
5082
|
}
|
|
4987
5083
|
function isPathWithinRoot(filePath, rootPath) {
|
|
4988
|
-
const normalizedFilePath =
|
|
4989
|
-
const normalizedRoot =
|
|
4990
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
5084
|
+
const normalizedFilePath = path12.resolve(filePath);
|
|
5085
|
+
const normalizedRoot = path12.resolve(rootPath);
|
|
5086
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path12.sep}`);
|
|
4991
5087
|
}
|
|
4992
5088
|
var rankingQueryTokenCache = /* @__PURE__ */ new Map();
|
|
4993
5089
|
var rankingNameTokenCache = /* @__PURE__ */ new Map();
|
|
@@ -5103,11 +5199,11 @@ function setBoundedCache(cache, key, value) {
|
|
|
5103
5199
|
}
|
|
5104
5200
|
cache.set(key, value);
|
|
5105
5201
|
}
|
|
5106
|
-
function tokenizeTextForRanking(
|
|
5107
|
-
if (!
|
|
5202
|
+
function tokenizeTextForRanking(text3) {
|
|
5203
|
+
if (!text3) {
|
|
5108
5204
|
return /* @__PURE__ */ new Set();
|
|
5109
5205
|
}
|
|
5110
|
-
const lowered =
|
|
5206
|
+
const lowered = text3.toLowerCase();
|
|
5111
5207
|
const cache = rankingQueryTokenCache.get(lowered) ?? rankingTextTokenCache.get(lowered);
|
|
5112
5208
|
if (cache) {
|
|
5113
5209
|
return cache;
|
|
@@ -5746,7 +5842,8 @@ function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCa
|
|
|
5746
5842
|
chunkType,
|
|
5747
5843
|
name: chunk.name ?? void 0,
|
|
5748
5844
|
language: chunk.language,
|
|
5749
|
-
hash: chunk.contentHash
|
|
5845
|
+
hash: chunk.contentHash,
|
|
5846
|
+
...metadataFromBlame(blameFromChunkData(chunk))
|
|
5750
5847
|
};
|
|
5751
5848
|
const baselineScore = existing?.score ?? 0.5;
|
|
5752
5849
|
candidateUnion.set(chunk.chunkId, {
|
|
@@ -5830,7 +5927,8 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
5830
5927
|
chunkType,
|
|
5831
5928
|
name: chunk.name ?? void 0,
|
|
5832
5929
|
language: chunk.language,
|
|
5833
|
-
hash: chunk.contentHash
|
|
5930
|
+
hash: chunk.contentHash,
|
|
5931
|
+
...metadataFromBlame(blameFromChunkData(chunk))
|
|
5834
5932
|
}
|
|
5835
5933
|
});
|
|
5836
5934
|
}
|
|
@@ -5999,6 +6097,21 @@ function matchesSearchFilters(candidate, options, minScore) {
|
|
|
5999
6097
|
if (options?.chunkType && candidate.metadata.chunkType !== options.chunkType) {
|
|
6000
6098
|
return false;
|
|
6001
6099
|
}
|
|
6100
|
+
if (options?.blameAuthor) {
|
|
6101
|
+
const author = options.blameAuthor.toLowerCase();
|
|
6102
|
+
const candidateAuthor = candidate.metadata.blameAuthor?.toLowerCase();
|
|
6103
|
+
const candidateEmail = candidate.metadata.blameAuthorEmail?.toLowerCase();
|
|
6104
|
+
if (candidateAuthor !== author && candidateEmail !== author) return false;
|
|
6105
|
+
}
|
|
6106
|
+
if (options?.blameSha && !candidate.metadata.blameSha?.toLowerCase().startsWith(options.blameSha.toLowerCase())) {
|
|
6107
|
+
return false;
|
|
6108
|
+
}
|
|
6109
|
+
if (options?.blameSince) {
|
|
6110
|
+
const sinceMs = Date.parse(options.blameSince);
|
|
6111
|
+
if (Number.isNaN(sinceMs)) return false;
|
|
6112
|
+
const committedAt = candidate.metadata.blameCommittedAt;
|
|
6113
|
+
if (committedAt === void 0 || committedAt < Math.floor(sinceMs / 1e3)) return false;
|
|
6114
|
+
}
|
|
6002
6115
|
return true;
|
|
6003
6116
|
}
|
|
6004
6117
|
function unionCandidates(semanticCandidates, keywordCandidates) {
|
|
@@ -6037,14 +6150,14 @@ var Indexer = class {
|
|
|
6037
6150
|
querySimilarityThreshold = 0.85;
|
|
6038
6151
|
indexCompatibility = null;
|
|
6039
6152
|
indexingLockPath = "";
|
|
6040
|
-
constructor(
|
|
6041
|
-
this.projectRoot =
|
|
6153
|
+
constructor(projectRoot3, config, host = "opencode") {
|
|
6154
|
+
this.projectRoot = projectRoot3;
|
|
6042
6155
|
this.config = config;
|
|
6043
6156
|
this.host = host;
|
|
6044
6157
|
this.indexPath = this.getIndexPath();
|
|
6045
|
-
this.fileHashCachePath =
|
|
6046
|
-
this.failedBatchesPath =
|
|
6047
|
-
this.indexingLockPath =
|
|
6158
|
+
this.fileHashCachePath = path12.join(this.indexPath, "file-hashes.json");
|
|
6159
|
+
this.failedBatchesPath = path12.join(this.indexPath, "failed-batches.json");
|
|
6160
|
+
this.indexingLockPath = path12.join(this.indexPath, "indexing.lock");
|
|
6048
6161
|
this.logger = initializeLogger(config.debug);
|
|
6049
6162
|
}
|
|
6050
6163
|
getIndexPath() {
|
|
@@ -6076,14 +6189,14 @@ var Indexer = class {
|
|
|
6076
6189
|
}
|
|
6077
6190
|
atomicWriteSync(targetPath, data) {
|
|
6078
6191
|
const tempPath = `${targetPath}.tmp`;
|
|
6079
|
-
mkdirSync2(
|
|
6192
|
+
mkdirSync2(path12.dirname(targetPath), { recursive: true });
|
|
6080
6193
|
writeFileSync2(tempPath, data);
|
|
6081
6194
|
renameSync(tempPath, targetPath);
|
|
6082
6195
|
}
|
|
6083
6196
|
getScopedRoots() {
|
|
6084
|
-
const roots = /* @__PURE__ */ new Set([
|
|
6197
|
+
const roots = /* @__PURE__ */ new Set([path12.resolve(this.projectRoot)]);
|
|
6085
6198
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
6086
|
-
roots.add(
|
|
6199
|
+
roots.add(path12.resolve(this.projectRoot, kbRoot));
|
|
6087
6200
|
}
|
|
6088
6201
|
return Array.from(roots);
|
|
6089
6202
|
}
|
|
@@ -6092,29 +6205,29 @@ var Indexer = class {
|
|
|
6092
6205
|
if (this.config.scope !== "global") {
|
|
6093
6206
|
return branchName;
|
|
6094
6207
|
}
|
|
6095
|
-
const projectHash = hashContent(
|
|
6208
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
6096
6209
|
return `${projectHash}:${branchName}`;
|
|
6097
6210
|
}
|
|
6098
6211
|
getBranchCatalogKeyFor(branchName) {
|
|
6099
6212
|
if (this.config.scope !== "global") {
|
|
6100
6213
|
return branchName;
|
|
6101
6214
|
}
|
|
6102
|
-
const projectHash = hashContent(
|
|
6215
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
6103
6216
|
return `${projectHash}:${branchName}`;
|
|
6104
6217
|
}
|
|
6105
6218
|
getLegacyBranchCatalogKey() {
|
|
6106
6219
|
return this.currentBranch || "default";
|
|
6107
6220
|
}
|
|
6108
6221
|
getLegacyMigrationMetadataKey() {
|
|
6109
|
-
const projectHash = hashContent(
|
|
6222
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
6110
6223
|
return `index.globalBranchMigration.${projectHash}`;
|
|
6111
6224
|
}
|
|
6112
6225
|
getProjectEmbeddingStrategyMetadataKey() {
|
|
6113
|
-
const projectHash = hashContent(
|
|
6226
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
6114
6227
|
return `index.embeddingStrategyVersion.${projectHash}`;
|
|
6115
6228
|
}
|
|
6116
6229
|
getProjectForceReembedMetadataKey() {
|
|
6117
|
-
const projectHash = hashContent(
|
|
6230
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
6118
6231
|
return `index.forceReembed.${projectHash}`;
|
|
6119
6232
|
}
|
|
6120
6233
|
hasProjectForceReembedPending() {
|
|
@@ -6208,7 +6321,7 @@ var Indexer = class {
|
|
|
6208
6321
|
if (!this.database) {
|
|
6209
6322
|
return { chunkIds, symbolIds };
|
|
6210
6323
|
}
|
|
6211
|
-
const projectRootPath =
|
|
6324
|
+
const projectRootPath = path12.resolve(this.projectRoot);
|
|
6212
6325
|
const projectLocalFilePaths = /* @__PURE__ */ new Set([
|
|
6213
6326
|
...Array.from(this.fileHashCache.keys()).filter(
|
|
6214
6327
|
(filePath) => this.isFileInCurrentScope(filePath, roots) && isPathWithinRoot(filePath, projectRootPath)
|
|
@@ -6231,7 +6344,7 @@ var Indexer = class {
|
|
|
6231
6344
|
if (this.config.scope !== "global") {
|
|
6232
6345
|
return this.getBranchCatalogCleanupKeys();
|
|
6233
6346
|
}
|
|
6234
|
-
const projectHash = hashContent(
|
|
6347
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
6235
6348
|
const keys = /* @__PURE__ */ new Set();
|
|
6236
6349
|
const projectChunkIdSet = new Set(projectChunkIds);
|
|
6237
6350
|
const projectSymbolIdSet = new Set(projectSymbolIds);
|
|
@@ -6315,7 +6428,7 @@ var Indexer = class {
|
|
|
6315
6428
|
if (!this.database || this.config.scope !== "global") {
|
|
6316
6429
|
return false;
|
|
6317
6430
|
}
|
|
6318
|
-
const projectHash = hashContent(
|
|
6431
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
6319
6432
|
const roots = this.getScopedRoots();
|
|
6320
6433
|
const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots);
|
|
6321
6434
|
return this.database.getAllBranches().some(
|
|
@@ -6349,7 +6462,7 @@ var Indexer = class {
|
|
|
6349
6462
|
...Array.from(this.fileHashCache.keys()).filter((filePath) => this.isFileInCurrentScope(filePath, roots)),
|
|
6350
6463
|
...scopedEntries.map(({ metadata }) => metadata.filePath)
|
|
6351
6464
|
]);
|
|
6352
|
-
const projectRootPath =
|
|
6465
|
+
const projectRootPath = path12.resolve(this.projectRoot);
|
|
6353
6466
|
const projectLocalFilePaths = new Set(
|
|
6354
6467
|
Array.from(filePaths).filter((filePath) => isPathWithinRoot(filePath, projectRootPath))
|
|
6355
6468
|
);
|
|
@@ -6709,13 +6822,13 @@ var Indexer = class {
|
|
|
6709
6822
|
}
|
|
6710
6823
|
await fsPromises2.mkdir(this.indexPath, { recursive: true });
|
|
6711
6824
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
6712
|
-
const storePath =
|
|
6825
|
+
const storePath = path12.join(this.indexPath, "vectors");
|
|
6713
6826
|
this.store = new VectorStore(storePath, dimensions);
|
|
6714
|
-
const indexFilePath =
|
|
6827
|
+
const indexFilePath = path12.join(this.indexPath, "vectors.usearch");
|
|
6715
6828
|
if (existsSync7(indexFilePath)) {
|
|
6716
6829
|
this.store.load();
|
|
6717
6830
|
}
|
|
6718
|
-
const invertedIndexPath =
|
|
6831
|
+
const invertedIndexPath = path12.join(this.indexPath, "inverted-index.json");
|
|
6719
6832
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
6720
6833
|
try {
|
|
6721
6834
|
this.invertedIndex.load();
|
|
@@ -6725,7 +6838,7 @@ var Indexer = class {
|
|
|
6725
6838
|
}
|
|
6726
6839
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
6727
6840
|
}
|
|
6728
|
-
const dbPath =
|
|
6841
|
+
const dbPath = path12.join(this.indexPath, "codebase.db");
|
|
6729
6842
|
let dbIsNew = !existsSync7(dbPath);
|
|
6730
6843
|
try {
|
|
6731
6844
|
this.database = new Database(dbPath);
|
|
@@ -6806,7 +6919,7 @@ var Indexer = class {
|
|
|
6806
6919
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
6807
6920
|
return {
|
|
6808
6921
|
resetCorruptedIndex: true,
|
|
6809
|
-
warning: this.getCorruptedIndexWarning(
|
|
6922
|
+
warning: this.getCorruptedIndexWarning(path12.join(this.indexPath, "codebase.db"))
|
|
6810
6923
|
};
|
|
6811
6924
|
}
|
|
6812
6925
|
throw error;
|
|
@@ -6821,7 +6934,7 @@ var Indexer = class {
|
|
|
6821
6934
|
return;
|
|
6822
6935
|
}
|
|
6823
6936
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
6824
|
-
const storeBasePath =
|
|
6937
|
+
const storeBasePath = path12.join(this.indexPath, "vectors");
|
|
6825
6938
|
const storeIndexPath = `${storeBasePath}.usearch`;
|
|
6826
6939
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
6827
6940
|
const backupIndexPath = `${storeIndexPath}.bak`;
|
|
@@ -6906,7 +7019,7 @@ var Indexer = class {
|
|
|
6906
7019
|
if (!isSqliteCorruptionError(error)) {
|
|
6907
7020
|
return false;
|
|
6908
7021
|
}
|
|
6909
|
-
const dbPath =
|
|
7022
|
+
const dbPath = path12.join(this.indexPath, "codebase.db");
|
|
6910
7023
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
6911
7024
|
const errorMessage = getErrorMessage2(error);
|
|
6912
7025
|
if (this.config.scope === "global") {
|
|
@@ -6929,15 +7042,15 @@ var Indexer = class {
|
|
|
6929
7042
|
this.indexCompatibility = null;
|
|
6930
7043
|
this.fileHashCache.clear();
|
|
6931
7044
|
const resetPaths = [
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
7045
|
+
path12.join(this.indexPath, "codebase.db"),
|
|
7046
|
+
path12.join(this.indexPath, "codebase.db-shm"),
|
|
7047
|
+
path12.join(this.indexPath, "codebase.db-wal"),
|
|
7048
|
+
path12.join(this.indexPath, "vectors.usearch"),
|
|
7049
|
+
path12.join(this.indexPath, "inverted-index.json"),
|
|
7050
|
+
path12.join(this.indexPath, "file-hashes.json"),
|
|
7051
|
+
path12.join(this.indexPath, "failed-batches.json"),
|
|
7052
|
+
path12.join(this.indexPath, "indexing.lock"),
|
|
7053
|
+
path12.join(this.indexPath, "vectors")
|
|
6941
7054
|
];
|
|
6942
7055
|
await Promise.all(resetPaths.map(async (targetPath) => {
|
|
6943
7056
|
try {
|
|
@@ -7174,6 +7287,7 @@ var Indexer = class {
|
|
|
7174
7287
|
this.logger.debug("Parsed changed files", { parsedCount: parsedFiles.length, parseMs: parseMs.toFixed(2) });
|
|
7175
7288
|
const existingChunks = /* @__PURE__ */ new Map();
|
|
7176
7289
|
const existingChunksByFile = /* @__PURE__ */ new Map();
|
|
7290
|
+
const existingMetadataById = /* @__PURE__ */ new Map();
|
|
7177
7291
|
for (const { key, metadata } of store.getAllMetadata()) {
|
|
7178
7292
|
if (scopedRoots && !this.isFileInCurrentScope(metadata.filePath, scopedRoots)) {
|
|
7179
7293
|
continue;
|
|
@@ -7182,6 +7296,7 @@ var Indexer = class {
|
|
|
7182
7296
|
continue;
|
|
7183
7297
|
}
|
|
7184
7298
|
existingChunks.set(key, metadata.hash);
|
|
7299
|
+
existingMetadataById.set(key, metadata);
|
|
7185
7300
|
const fileChunks = existingChunksByFile.get(metadata.filePath) || /* @__PURE__ */ new Set();
|
|
7186
7301
|
fileChunks.add(key);
|
|
7187
7302
|
existingChunksByFile.set(metadata.filePath, fileChunks);
|
|
@@ -7189,6 +7304,8 @@ var Indexer = class {
|
|
|
7189
7304
|
const currentChunkIds = /* @__PURE__ */ new Set();
|
|
7190
7305
|
const currentFilePaths = /* @__PURE__ */ new Set();
|
|
7191
7306
|
const pendingChunks = [];
|
|
7307
|
+
const gitBlameEnabled = this.config.indexing.gitBlame.enabled && isGitRepo(this.projectRoot);
|
|
7308
|
+
let backfilledBlameMetadata = false;
|
|
7192
7309
|
for (const filePath of unchangedFilePaths) {
|
|
7193
7310
|
currentFilePaths.add(filePath);
|
|
7194
7311
|
const fileChunks = existingChunksByFile.get(filePath);
|
|
@@ -7199,10 +7316,52 @@ var Indexer = class {
|
|
|
7199
7316
|
}
|
|
7200
7317
|
}
|
|
7201
7318
|
const chunkDataBatch = [];
|
|
7319
|
+
if (gitBlameEnabled) {
|
|
7320
|
+
const backfillItems = [];
|
|
7321
|
+
for (const chunkId of currentChunkIds) {
|
|
7322
|
+
const metadata = existingMetadataById.get(chunkId);
|
|
7323
|
+
if (!metadata || hasBlameMetadata(metadata)) {
|
|
7324
|
+
continue;
|
|
7325
|
+
}
|
|
7326
|
+
const chunk = database.getChunk(chunkId);
|
|
7327
|
+
if (!chunk) {
|
|
7328
|
+
continue;
|
|
7329
|
+
}
|
|
7330
|
+
const blame = await getChunkGitBlame(this.projectRoot, chunk.filePath, chunk.startLine, chunk.endLine);
|
|
7331
|
+
const blameMetadata = metadataFromBlame(blame);
|
|
7332
|
+
if (!blameMetadata.blameSha) {
|
|
7333
|
+
continue;
|
|
7334
|
+
}
|
|
7335
|
+
chunkDataBatch.push({
|
|
7336
|
+
...chunk,
|
|
7337
|
+
blameSha: blameMetadata.blameSha,
|
|
7338
|
+
blameAuthor: blameMetadata.blameAuthor,
|
|
7339
|
+
blameAuthorEmail: blameMetadata.blameAuthorEmail,
|
|
7340
|
+
blameCommittedAt: blameMetadata.blameCommittedAt,
|
|
7341
|
+
blameSummary: blameMetadata.blameSummary
|
|
7342
|
+
});
|
|
7343
|
+
const embeddingBuffer = database.getEmbedding(chunk.contentHash);
|
|
7344
|
+
if (!embeddingBuffer) {
|
|
7345
|
+
continue;
|
|
7346
|
+
}
|
|
7347
|
+
backfillItems.push({
|
|
7348
|
+
id: chunkId,
|
|
7349
|
+
vector: Array.from(bufferToFloat32Array(embeddingBuffer)),
|
|
7350
|
+
metadata: {
|
|
7351
|
+
...metadata,
|
|
7352
|
+
...blameMetadata
|
|
7353
|
+
}
|
|
7354
|
+
});
|
|
7355
|
+
}
|
|
7356
|
+
if (backfillItems.length > 0) {
|
|
7357
|
+
store.addBatch(backfillItems);
|
|
7358
|
+
backfilledBlameMetadata = true;
|
|
7359
|
+
}
|
|
7360
|
+
}
|
|
7202
7361
|
for (const parsed of parsedFiles) {
|
|
7203
7362
|
currentFilePaths.add(parsed.path);
|
|
7204
7363
|
if (parsed.chunks.length === 0) {
|
|
7205
|
-
const relativePath =
|
|
7364
|
+
const relativePath = path12.relative(this.projectRoot, parsed.path);
|
|
7206
7365
|
stats.parseFailures.push(relativePath);
|
|
7207
7366
|
}
|
|
7208
7367
|
let fileChunkCount = 0;
|
|
@@ -7223,6 +7382,10 @@ var Indexer = class {
|
|
|
7223
7382
|
}
|
|
7224
7383
|
const id = generateChunkId(parsed.path, chunk);
|
|
7225
7384
|
const contentHash = generateChunkHash(chunk);
|
|
7385
|
+
const existingContentHash = existingChunks.get(id);
|
|
7386
|
+
const existingChunk = gitBlameEnabled ? database.getChunk(id) : null;
|
|
7387
|
+
const blame = gitBlameEnabled && existingContentHash !== contentHash ? await getChunkGitBlame(this.projectRoot, parsed.path, chunk.startLine, chunk.endLine) : blameFromChunkData(existingChunk);
|
|
7388
|
+
const blameMetadata = metadataFromBlame(blame);
|
|
7226
7389
|
currentChunkIds.add(id);
|
|
7227
7390
|
chunkDataBatch.push({
|
|
7228
7391
|
chunkId: id,
|
|
@@ -7232,15 +7395,20 @@ var Indexer = class {
|
|
|
7232
7395
|
endLine: chunk.endLine,
|
|
7233
7396
|
nodeType: chunk.chunkType,
|
|
7234
7397
|
name: chunk.name,
|
|
7235
|
-
language: chunk.language
|
|
7398
|
+
language: chunk.language,
|
|
7399
|
+
blameSha: blameMetadata.blameSha,
|
|
7400
|
+
blameAuthor: blameMetadata.blameAuthor,
|
|
7401
|
+
blameAuthorEmail: blameMetadata.blameAuthorEmail,
|
|
7402
|
+
blameCommittedAt: blameMetadata.blameCommittedAt,
|
|
7403
|
+
blameSummary: blameMetadata.blameSummary
|
|
7236
7404
|
});
|
|
7237
|
-
if (
|
|
7405
|
+
if (existingContentHash === contentHash) {
|
|
7238
7406
|
fileChunkCount++;
|
|
7239
7407
|
continue;
|
|
7240
7408
|
}
|
|
7241
|
-
const texts = createEmbeddingTexts(chunk, parsed.path, getSafeEmbeddingChunkTokenLimit(configuredProviderInfo)).map((
|
|
7242
|
-
text:
|
|
7243
|
-
tokenCount: estimateTokens(
|
|
7409
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, getSafeEmbeddingChunkTokenLimit(configuredProviderInfo)).map((text3) => ({
|
|
7410
|
+
text: text3,
|
|
7411
|
+
tokenCount: estimateTokens(text3)
|
|
7244
7412
|
}));
|
|
7245
7413
|
const metadata = {
|
|
7246
7414
|
filePath: parsed.path,
|
|
@@ -7249,7 +7417,8 @@ var Indexer = class {
|
|
|
7249
7417
|
chunkType: chunk.chunkType,
|
|
7250
7418
|
name: chunk.name,
|
|
7251
7419
|
language: chunk.language,
|
|
7252
|
-
hash: contentHash
|
|
7420
|
+
hash: contentHash,
|
|
7421
|
+
...blameMetadata
|
|
7253
7422
|
};
|
|
7254
7423
|
pendingChunks.push({
|
|
7255
7424
|
id,
|
|
@@ -7392,6 +7561,9 @@ var Indexer = class {
|
|
|
7392
7561
|
database.addChunksToBranchBatch(branchCatalogKey, Array.from(currentChunkIds));
|
|
7393
7562
|
database.clearBranchSymbols(branchCatalogKey);
|
|
7394
7563
|
database.addSymbolsToBranchBatch(branchCatalogKey, Array.from(allSymbolIds));
|
|
7564
|
+
if (backfilledBlameMetadata) {
|
|
7565
|
+
store.save();
|
|
7566
|
+
}
|
|
7395
7567
|
if (scopedRoots) {
|
|
7396
7568
|
this.replaceScopedFileHashCache(currentFileHashes, scopedRoots);
|
|
7397
7569
|
this.clearScopedFailedBatches(scopedRoots);
|
|
@@ -7771,9 +7943,9 @@ var Indexer = class {
|
|
|
7771
7943
|
}
|
|
7772
7944
|
return bestMatch;
|
|
7773
7945
|
}
|
|
7774
|
-
tokenize(
|
|
7946
|
+
tokenize(text3) {
|
|
7775
7947
|
return new Set(
|
|
7776
|
-
|
|
7948
|
+
text3.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((t) => t.length > 1)
|
|
7777
7949
|
);
|
|
7778
7950
|
}
|
|
7779
7951
|
jaccardSimilarity(a, b) {
|
|
@@ -7955,7 +8127,8 @@ var Indexer = class {
|
|
|
7955
8127
|
content,
|
|
7956
8128
|
score: r.score,
|
|
7957
8129
|
chunkType: r.metadata.chunkType,
|
|
7958
|
-
name: r.metadata.name
|
|
8130
|
+
name: r.metadata.name,
|
|
8131
|
+
blame: blameFromMetadata(r.metadata)
|
|
7959
8132
|
};
|
|
7960
8133
|
})
|
|
7961
8134
|
);
|
|
@@ -8047,12 +8220,12 @@ var Indexer = class {
|
|
|
8047
8220
|
this.indexCompatibility = compatibility;
|
|
8048
8221
|
return;
|
|
8049
8222
|
}
|
|
8050
|
-
const localProjectIndexPaths = [
|
|
8223
|
+
const localProjectIndexPaths = [path12.join(this.projectRoot, getHostProjectIndexRelativePath(this.host))];
|
|
8051
8224
|
if (this.host !== "opencode") {
|
|
8052
|
-
localProjectIndexPaths.push(
|
|
8225
|
+
localProjectIndexPaths.push(path12.join(this.projectRoot, getHostProjectIndexRelativePath("opencode")));
|
|
8053
8226
|
}
|
|
8054
8227
|
const isLocalProjectIndex = localProjectIndexPaths.some(
|
|
8055
|
-
(localPath) =>
|
|
8228
|
+
(localPath) => path12.resolve(this.indexPath) === path12.resolve(localPath)
|
|
8056
8229
|
);
|
|
8057
8230
|
if (!isLocalProjectIndex) {
|
|
8058
8231
|
throw new Error(
|
|
@@ -8142,7 +8315,7 @@ var Indexer = class {
|
|
|
8142
8315
|
gcOrphanSymbols: 0,
|
|
8143
8316
|
gcOrphanCallEdges: 0,
|
|
8144
8317
|
resetCorruptedIndex: true,
|
|
8145
|
-
warning: this.getCorruptedIndexWarning(
|
|
8318
|
+
warning: this.getCorruptedIndexWarning(path12.join(this.indexPath, "codebase.db"))
|
|
8146
8319
|
};
|
|
8147
8320
|
}
|
|
8148
8321
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -8462,7 +8635,8 @@ var Indexer = class {
|
|
|
8462
8635
|
content,
|
|
8463
8636
|
score: r.score,
|
|
8464
8637
|
chunkType: r.metadata.chunkType,
|
|
8465
|
-
name: r.metadata.name
|
|
8638
|
+
name: r.metadata.name,
|
|
8639
|
+
blame: blameFromMetadata(r.metadata)
|
|
8466
8640
|
};
|
|
8467
8641
|
})
|
|
8468
8642
|
);
|
|
@@ -8499,9 +8673,9 @@ var Indexer = class {
|
|
|
8499
8673
|
const { database } = await this.ensureInitialized();
|
|
8500
8674
|
let shortest = [];
|
|
8501
8675
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
8502
|
-
const
|
|
8503
|
-
if (
|
|
8504
|
-
shortest =
|
|
8676
|
+
const path16 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
8677
|
+
if (path16.length > 0 && (shortest.length === 0 || path16.length < shortest.length)) {
|
|
8678
|
+
shortest = path16;
|
|
8505
8679
|
}
|
|
8506
8680
|
}
|
|
8507
8681
|
return shortest;
|
|
@@ -8533,7 +8707,7 @@ var Indexer = class {
|
|
|
8533
8707
|
}
|
|
8534
8708
|
async getPrImpact(opts) {
|
|
8535
8709
|
const { database } = await this.ensureInitialized();
|
|
8536
|
-
const
|
|
8710
|
+
const execFileAsync3 = promisify3(execFile3);
|
|
8537
8711
|
const changedFilesResult = await getChangedFiles({
|
|
8538
8712
|
pr: opts.pr,
|
|
8539
8713
|
branch: opts.branch,
|
|
@@ -8555,7 +8729,7 @@ var Indexer = class {
|
|
|
8555
8729
|
"Run index_codebase first to build the call graph and symbol index for this branch."
|
|
8556
8730
|
);
|
|
8557
8731
|
}
|
|
8558
|
-
const absoluteChangedFiles = changedFiles.map((f) =>
|
|
8732
|
+
const absoluteChangedFiles = changedFiles.map((f) => path12.resolve(this.projectRoot, f));
|
|
8559
8733
|
const directSymbols = database.getSymbolsForFiles(absoluteChangedFiles, branchKey);
|
|
8560
8734
|
const directIds = directSymbols.map((s) => s.id);
|
|
8561
8735
|
const direction = opts.direction ?? "both";
|
|
@@ -8617,7 +8791,7 @@ var Indexer = class {
|
|
|
8617
8791
|
if (opts.checkConflicts) {
|
|
8618
8792
|
conflictingPRs = [];
|
|
8619
8793
|
try {
|
|
8620
|
-
const { stdout } = await
|
|
8794
|
+
const { stdout } = await execFileAsync3(
|
|
8621
8795
|
"gh",
|
|
8622
8796
|
["pr", "list", "--state", "open", "--json", "number,headRefName", "--limit", "10000"],
|
|
8623
8797
|
{ cwd: this.projectRoot, timeout: 3e4 }
|
|
@@ -8638,7 +8812,7 @@ var Indexer = class {
|
|
|
8638
8812
|
projectRoot: this.projectRoot,
|
|
8639
8813
|
baseBranch: this.baseBranch
|
|
8640
8814
|
});
|
|
8641
|
-
const otherAbsolute = otherChanged.files.map((f) =>
|
|
8815
|
+
const otherAbsolute = otherChanged.files.map((f) => path12.resolve(this.projectRoot, f));
|
|
8642
8816
|
const otherBranchKey = this.getBranchCatalogKeyFor(openPr.headRefName);
|
|
8643
8817
|
const otherSymbols = database.getSymbolsForFiles(otherAbsolute, otherBranchKey);
|
|
8644
8818
|
const otherLabels = /* @__PURE__ */ new Set();
|
|
@@ -8701,12 +8875,12 @@ var Indexer = class {
|
|
|
8701
8875
|
if (meta.filePath) filePaths.add(meta.filePath);
|
|
8702
8876
|
}
|
|
8703
8877
|
const directory = options?.directory?.replace(/\/$/, "");
|
|
8704
|
-
const absoluteDirectoryFilter = directory ?
|
|
8878
|
+
const absoluteDirectoryFilter = directory ? path12.resolve(this.projectRoot, directory) : void 0;
|
|
8705
8879
|
for (const filePath of filePaths) {
|
|
8706
8880
|
if (directory) {
|
|
8707
|
-
const absoluteFilePath =
|
|
8881
|
+
const absoluteFilePath = path12.resolve(filePath);
|
|
8708
8882
|
const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
|
|
8709
|
-
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter +
|
|
8883
|
+
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path12.sep));
|
|
8710
8884
|
if (!matchesRelative && !matchesProjectRelative) {
|
|
8711
8885
|
continue;
|
|
8712
8886
|
}
|
|
@@ -8738,43 +8912,43 @@ var Indexer = class {
|
|
|
8738
8912
|
};
|
|
8739
8913
|
|
|
8740
8914
|
// src/tools/knowledge-base-paths.ts
|
|
8741
|
-
import * as
|
|
8915
|
+
import * as path13 from "path";
|
|
8742
8916
|
function resolveConfigPathValue(value, baseDir) {
|
|
8743
8917
|
const trimmed = value.trim();
|
|
8744
8918
|
if (!trimmed) {
|
|
8745
8919
|
return trimmed;
|
|
8746
8920
|
}
|
|
8747
|
-
const absolutePath =
|
|
8748
|
-
return
|
|
8921
|
+
const absolutePath = path13.isAbsolute(trimmed) ? trimmed : path13.resolve(baseDir, trimmed);
|
|
8922
|
+
return path13.normalize(absolutePath);
|
|
8749
8923
|
}
|
|
8750
8924
|
function serializeConfigPathValue(value, baseDir) {
|
|
8751
8925
|
const trimmed = value.trim();
|
|
8752
8926
|
if (!trimmed) {
|
|
8753
8927
|
return trimmed;
|
|
8754
8928
|
}
|
|
8755
|
-
if (!
|
|
8756
|
-
return normalizePathSeparators(
|
|
8929
|
+
if (!path13.isAbsolute(trimmed)) {
|
|
8930
|
+
return normalizePathSeparators(path13.normalize(trimmed));
|
|
8757
8931
|
}
|
|
8758
|
-
const relativePath =
|
|
8759
|
-
if (!relativePath || !relativePath.startsWith("..") && !
|
|
8760
|
-
return normalizePathSeparators(
|
|
8932
|
+
const relativePath = path13.relative(baseDir, trimmed);
|
|
8933
|
+
if (!relativePath || !relativePath.startsWith("..") && !path13.isAbsolute(relativePath)) {
|
|
8934
|
+
return normalizePathSeparators(path13.normalize(relativePath || "."));
|
|
8761
8935
|
}
|
|
8762
|
-
return
|
|
8936
|
+
return path13.normalize(trimmed);
|
|
8763
8937
|
}
|
|
8764
|
-
function resolveKnowledgeBasePath(value,
|
|
8765
|
-
return
|
|
8938
|
+
function resolveKnowledgeBasePath(value, projectRoot3) {
|
|
8939
|
+
return path13.isAbsolute(value) ? value : path13.resolve(projectRoot3, value);
|
|
8766
8940
|
}
|
|
8767
|
-
function normalizeKnowledgeBasePath2(value,
|
|
8768
|
-
return
|
|
8941
|
+
function normalizeKnowledgeBasePath2(value, projectRoot3) {
|
|
8942
|
+
return path13.normalize(resolveKnowledgeBasePath(value, projectRoot3));
|
|
8769
8943
|
}
|
|
8770
|
-
function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath,
|
|
8771
|
-
const normalizedInput =
|
|
8772
|
-
return knowledgeBases.some((kb) => normalizeKnowledgeBasePath2(kb,
|
|
8944
|
+
function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath, projectRoot3) {
|
|
8945
|
+
const normalizedInput = path13.normalize(inputPath);
|
|
8946
|
+
return knowledgeBases.some((kb) => normalizeKnowledgeBasePath2(kb, projectRoot3) === normalizedInput);
|
|
8773
8947
|
}
|
|
8774
|
-
function findKnowledgeBasePathIndex(knowledgeBases, inputPath,
|
|
8775
|
-
const normalizedInput =
|
|
8948
|
+
function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot3) {
|
|
8949
|
+
const normalizedInput = path13.normalize(inputPath);
|
|
8776
8950
|
return knowledgeBases.findIndex(
|
|
8777
|
-
(kb) =>
|
|
8951
|
+
(kb) => path13.normalize(kb) === normalizedInput || normalizeKnowledgeBasePath2(kb, projectRoot3) === normalizedInput
|
|
8778
8952
|
);
|
|
8779
8953
|
}
|
|
8780
8954
|
|
|
@@ -8947,16 +9121,57 @@ function formatHealthCheck(result) {
|
|
|
8947
9121
|
}
|
|
8948
9122
|
return lines.join("\n");
|
|
8949
9123
|
}
|
|
9124
|
+
function formatCallGraphCallers(name, callers, relationshipType) {
|
|
9125
|
+
if (callers.length === 0) {
|
|
9126
|
+
return `No callers found for "${name}"${relationshipType ? ` with type ${relationshipType}` : ""}. It may not be called by any tracked function, or the index needs updating.`;
|
|
9127
|
+
}
|
|
9128
|
+
const formatted = callers.map((edge, index) => {
|
|
9129
|
+
const confidence = edge.confidence !== "Direct" ? ` [${edge.confidence.toLowerCase()}]` : "";
|
|
9130
|
+
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]"}`;
|
|
9131
|
+
});
|
|
9132
|
+
return `"${name}" is called by ${callers.length} function(s):
|
|
9133
|
+
|
|
9134
|
+
${formatted.join("\n")}`;
|
|
9135
|
+
}
|
|
9136
|
+
function formatCallGraphCallees(symbolId, callees, relationshipType) {
|
|
9137
|
+
if (callees.length === 0) {
|
|
9138
|
+
return `No callees found for symbol ${symbolId}${relationshipType ? ` with type ${relationshipType}` : ""}. The function may not call any other tracked functions.`;
|
|
9139
|
+
}
|
|
9140
|
+
return callees.map((edge, index) => {
|
|
9141
|
+
const confidence = edge.confidence !== "Direct" ? ` [${edge.confidence.toLowerCase()}]` : "";
|
|
9142
|
+
return `[${index + 1}] \u2192 ${edge.targetName} (${edge.callType})${confidence} at line ${edge.line}${edge.isResolved ? ` [resolved: ${edge.toSymbolId}]` : " [unresolved]"}`;
|
|
9143
|
+
}).join("\n");
|
|
9144
|
+
}
|
|
9145
|
+
function formatCallGraphPath(from, to, path16) {
|
|
9146
|
+
if (path16.length === 0) {
|
|
9147
|
+
return `No path found between "${from}" and "${to}". They may be in disconnected components, or the call graph index needs updating.`;
|
|
9148
|
+
}
|
|
9149
|
+
const formatted = path16.map((hop, index) => {
|
|
9150
|
+
const prefix = index === 0 ? "[start]" : `--${hop.callType}-->`;
|
|
9151
|
+
const location = hop.filePath ? ` (${hop.filePath}:${hop.line})` : "";
|
|
9152
|
+
return `${prefix} ${hop.symbolName}${location}`;
|
|
9153
|
+
});
|
|
9154
|
+
return `Path (${path16.length} hops):
|
|
9155
|
+
${formatted.join("\n")}`;
|
|
9156
|
+
}
|
|
8950
9157
|
function formatResultHeader(result, index) {
|
|
8951
9158
|
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}`;
|
|
8952
9159
|
}
|
|
9160
|
+
function formatBlame(result) {
|
|
9161
|
+
if (!result.blame) {
|
|
9162
|
+
return "";
|
|
9163
|
+
}
|
|
9164
|
+
const date = new Date(result.blame.committedAt * 1e3).toISOString().slice(0, 10);
|
|
9165
|
+
return `
|
|
9166
|
+
${result.blame.sha.slice(0, 7)} | ${result.blame.author} | ${date} | ${result.blame.summary}`;
|
|
9167
|
+
}
|
|
8953
9168
|
function formatDefinitionLookup(results, query) {
|
|
8954
9169
|
if (results.length === 0) {
|
|
8955
9170
|
return `No definition found for "${query}". Try codebase_search for broader discovery, or verify the symbol name.`;
|
|
8956
9171
|
}
|
|
8957
9172
|
const formatted = results.map((r, idx) => {
|
|
8958
9173
|
const header = formatResultHeader(r, idx);
|
|
8959
|
-
return `${header} (score: ${r.score.toFixed(2)})
|
|
9174
|
+
return `${header} (score: ${r.score.toFixed(2)})${formatBlame(r)}
|
|
8960
9175
|
\`\`\`
|
|
8961
9176
|
${truncateContent(r.content)}
|
|
8962
9177
|
\`\`\``;
|
|
@@ -8967,7 +9182,7 @@ function formatSearchResults(results, scoreFormat = "similarity") {
|
|
|
8967
9182
|
const formatted = results.map((r, idx) => {
|
|
8968
9183
|
const header = formatResultHeader(r, idx);
|
|
8969
9184
|
const scoreLabel = scoreFormat === "similarity" ? `(similarity: ${(r.score * 100).toFixed(1)}%)` : `(score: ${r.score.toFixed(2)})`;
|
|
8970
|
-
return `${header} ${scoreLabel}
|
|
9185
|
+
return `${header} ${scoreLabel}${formatBlame(r)}
|
|
8971
9186
|
\`\`\`
|
|
8972
9187
|
${truncateContent(r.content)}
|
|
8973
9188
|
\`\`\``;
|
|
@@ -8977,12 +9192,12 @@ ${truncateContent(r.content)}
|
|
|
8977
9192
|
|
|
8978
9193
|
// src/tools/config-state.ts
|
|
8979
9194
|
import { existsSync as existsSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
8980
|
-
import * as
|
|
8981
|
-
function normalizeKnowledgeBasePaths(config,
|
|
9195
|
+
import * as path14 from "path";
|
|
9196
|
+
function normalizeKnowledgeBasePaths(config, projectRoot3) {
|
|
8982
9197
|
const normalized = { ...config };
|
|
8983
9198
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
8984
9199
|
normalized.knowledgeBases = normalized.knowledgeBases.map(
|
|
8985
|
-
(kb) => resolveConfigPathValue(kb,
|
|
9200
|
+
(kb) => resolveConfigPathValue(kb, projectRoot3)
|
|
8986
9201
|
);
|
|
8987
9202
|
}
|
|
8988
9203
|
return normalized;
|
|
@@ -8993,19 +9208,19 @@ function toConfigRecord(rawConfig) {
|
|
|
8993
9208
|
}
|
|
8994
9209
|
return { ...rawConfig };
|
|
8995
9210
|
}
|
|
8996
|
-
function getConfigPath(
|
|
8997
|
-
return resolveWritableProjectConfigPath(
|
|
9211
|
+
function getConfigPath(projectRoot3, host = "opencode") {
|
|
9212
|
+
return resolveWritableProjectConfigPath(projectRoot3, host);
|
|
8998
9213
|
}
|
|
8999
|
-
function loadRuntimeConfig(
|
|
9000
|
-
return normalizeKnowledgeBasePaths(toConfigRecord(loadMergedConfig(
|
|
9214
|
+
function loadRuntimeConfig(projectRoot3, host = "opencode") {
|
|
9215
|
+
return normalizeKnowledgeBasePaths(toConfigRecord(loadMergedConfig(projectRoot3, host)), projectRoot3);
|
|
9001
9216
|
}
|
|
9002
|
-
function loadEditableConfig(
|
|
9003
|
-
return normalizeKnowledgeBasePaths(toConfigRecord(loadProjectConfigLayer(
|
|
9217
|
+
function loadEditableConfig(projectRoot3, host = "opencode") {
|
|
9218
|
+
return normalizeKnowledgeBasePaths(toConfigRecord(loadProjectConfigLayer(projectRoot3, host)), projectRoot3);
|
|
9004
9219
|
}
|
|
9005
|
-
function saveConfig(
|
|
9006
|
-
const configPath = getConfigPath(
|
|
9007
|
-
const configDir =
|
|
9008
|
-
const configBaseDir =
|
|
9220
|
+
function saveConfig(projectRoot3, config, host = "opencode") {
|
|
9221
|
+
const configPath = getConfigPath(projectRoot3, host);
|
|
9222
|
+
const configDir = path14.dirname(configPath);
|
|
9223
|
+
const configBaseDir = path14.dirname(configDir);
|
|
9009
9224
|
if (!existsSync8(configDir)) {
|
|
9010
9225
|
mkdirSync3(configDir, { recursive: true });
|
|
9011
9226
|
}
|
|
@@ -9022,9 +9237,9 @@ function saveConfig(projectRoot2, config, host = "opencode") {
|
|
|
9022
9237
|
var indexerCache = /* @__PURE__ */ new Map();
|
|
9023
9238
|
var configCache = /* @__PURE__ */ new Map();
|
|
9024
9239
|
var defaultProjectRoots = /* @__PURE__ */ new Map();
|
|
9025
|
-
function getProjectRoot(
|
|
9026
|
-
if (
|
|
9027
|
-
return
|
|
9240
|
+
function getProjectRoot(projectRoot3, host) {
|
|
9241
|
+
if (projectRoot3) {
|
|
9242
|
+
return projectRoot3;
|
|
9028
9243
|
}
|
|
9029
9244
|
const root = defaultProjectRoots.get(host);
|
|
9030
9245
|
if (!root) {
|
|
@@ -9032,53 +9247,56 @@ function getProjectRoot(projectRoot2, host) {
|
|
|
9032
9247
|
}
|
|
9033
9248
|
return root;
|
|
9034
9249
|
}
|
|
9035
|
-
function getIndexerCacheKey(
|
|
9036
|
-
return `${host}::${
|
|
9250
|
+
function getIndexerCacheKey(projectRoot3, host) {
|
|
9251
|
+
return `${host}::${projectRoot3}`;
|
|
9037
9252
|
}
|
|
9038
|
-
function getOrCreateIndexer(
|
|
9039
|
-
const key = getIndexerCacheKey(
|
|
9253
|
+
function getOrCreateIndexer(projectRoot3, host) {
|
|
9254
|
+
const key = getIndexerCacheKey(projectRoot3, host);
|
|
9040
9255
|
const cached = indexerCache.get(key);
|
|
9041
9256
|
if (cached) {
|
|
9042
9257
|
return cached;
|
|
9043
9258
|
}
|
|
9044
|
-
const config = parseConfig(loadRuntimeConfig(
|
|
9045
|
-
const indexer = new Indexer(
|
|
9259
|
+
const config = parseConfig(loadRuntimeConfig(projectRoot3, host));
|
|
9260
|
+
const indexer = new Indexer(projectRoot3, config, host);
|
|
9046
9261
|
indexerCache.set(key, indexer);
|
|
9047
9262
|
configCache.set(key, config);
|
|
9048
9263
|
return indexer;
|
|
9049
9264
|
}
|
|
9050
|
-
function getIndexerForProject(
|
|
9051
|
-
const root = getProjectRoot(
|
|
9265
|
+
function getIndexerForProject(projectRoot3, host = "opencode") {
|
|
9266
|
+
const root = getProjectRoot(projectRoot3, host);
|
|
9052
9267
|
return getOrCreateIndexer(root, host);
|
|
9053
9268
|
}
|
|
9054
|
-
function refreshIndexerForDirectory(
|
|
9055
|
-
const key = getIndexerCacheKey(
|
|
9056
|
-
const indexer = new Indexer(
|
|
9269
|
+
function refreshIndexerForDirectory(projectRoot3, host = "opencode", config = parseConfig(loadRuntimeConfig(projectRoot3, host))) {
|
|
9270
|
+
const key = getIndexerCacheKey(projectRoot3, host);
|
|
9271
|
+
const indexer = new Indexer(projectRoot3, config, host);
|
|
9057
9272
|
indexerCache.set(key, indexer);
|
|
9058
9273
|
configCache.set(key, config);
|
|
9059
9274
|
}
|
|
9060
|
-
function shouldForceLocalizeProjectIndex(
|
|
9061
|
-
const root = getProjectRoot(
|
|
9062
|
-
const localIndexPath =
|
|
9275
|
+
function shouldForceLocalizeProjectIndex(projectRoot3, host = "opencode") {
|
|
9276
|
+
const root = getProjectRoot(projectRoot3, host);
|
|
9277
|
+
const localIndexPath = path15.join(root, getHostProjectIndexRelativePath(host));
|
|
9063
9278
|
if (existsSync9(localIndexPath)) {
|
|
9064
9279
|
return false;
|
|
9065
9280
|
}
|
|
9066
9281
|
const inheritedIndexPath = resolveWorktreeFallbackProjectIndexPath(root, host);
|
|
9067
9282
|
return inheritedIndexPath !== null;
|
|
9068
9283
|
}
|
|
9069
|
-
async function searchCodebase(
|
|
9070
|
-
const indexer = getIndexerForProject(
|
|
9284
|
+
async function searchCodebase(projectRoot3, host, query, options = {}) {
|
|
9285
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9071
9286
|
return indexer.search(query, options.limit, {
|
|
9072
9287
|
fileType: options.fileType,
|
|
9073
9288
|
directory: options.directory,
|
|
9074
9289
|
chunkType: options.chunkType,
|
|
9075
9290
|
contextLines: options.contextLines,
|
|
9076
9291
|
metadataOnly: options.metadataOnly,
|
|
9077
|
-
definitionIntent: options.definitionIntent
|
|
9292
|
+
definitionIntent: options.definitionIntent,
|
|
9293
|
+
blameAuthor: options.blameAuthor,
|
|
9294
|
+
blameSha: options.blameSha,
|
|
9295
|
+
blameSince: options.blameSince
|
|
9078
9296
|
});
|
|
9079
9297
|
}
|
|
9080
|
-
async function findSimilarCode(
|
|
9081
|
-
const indexer = getIndexerForProject(
|
|
9298
|
+
async function findSimilarCode(projectRoot3, host, code, options = {}) {
|
|
9299
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9082
9300
|
return indexer.findSimilar(code, options.limit, {
|
|
9083
9301
|
fileType: options.fileType,
|
|
9084
9302
|
directory: options.directory,
|
|
@@ -9086,16 +9304,16 @@ async function findSimilarCode(projectRoot2, host, code, options = {}) {
|
|
|
9086
9304
|
excludeFile: options.excludeFile
|
|
9087
9305
|
});
|
|
9088
9306
|
}
|
|
9089
|
-
async function implementationLookup(
|
|
9090
|
-
const indexer = getIndexerForProject(
|
|
9307
|
+
async function implementationLookup(projectRoot3, host, query, options = {}) {
|
|
9308
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9091
9309
|
return indexer.search(query, options.limit, {
|
|
9092
9310
|
fileType: options.fileType,
|
|
9093
9311
|
directory: options.directory,
|
|
9094
9312
|
definitionIntent: true
|
|
9095
9313
|
});
|
|
9096
9314
|
}
|
|
9097
|
-
async function getCallGraphData(
|
|
9098
|
-
const indexer = getIndexerForProject(
|
|
9315
|
+
async function getCallGraphData(projectRoot3, host, params) {
|
|
9316
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9099
9317
|
if (params.direction === "callees") {
|
|
9100
9318
|
if (!params.symbolId) {
|
|
9101
9319
|
return { direction: "callees", callees: [], callers: [] };
|
|
@@ -9106,12 +9324,12 @@ async function getCallGraphData(projectRoot2, host, params) {
|
|
|
9106
9324
|
const callers = await indexer.getCallers(params.name, params.relationshipType);
|
|
9107
9325
|
return { direction: "callers", callers, callees: [] };
|
|
9108
9326
|
}
|
|
9109
|
-
async function getCallGraphPath(
|
|
9110
|
-
const indexer = getIndexerForProject(
|
|
9327
|
+
async function getCallGraphPath(projectRoot3, host, from, to, maxDepth) {
|
|
9328
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9111
9329
|
return indexer.findCallPath(from, to, maxDepth);
|
|
9112
9330
|
}
|
|
9113
|
-
async function runIndexCodebase(
|
|
9114
|
-
const root = getProjectRoot(
|
|
9331
|
+
async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
9332
|
+
const root = getProjectRoot(projectRoot3, host);
|
|
9115
9333
|
const key = getIndexerCacheKey(root, host);
|
|
9116
9334
|
const cachedConfig = configCache.get(key);
|
|
9117
9335
|
let indexer = getIndexerForProject(root, host);
|
|
@@ -9143,16 +9361,16 @@ async function runIndexCodebase(projectRoot2, host, args, onProgress) {
|
|
|
9143
9361
|
});
|
|
9144
9362
|
return { kind: "stats", stats };
|
|
9145
9363
|
}
|
|
9146
|
-
async function getIndexStatus(
|
|
9147
|
-
const indexer = getIndexerForProject(
|
|
9364
|
+
async function getIndexStatus(projectRoot3, host) {
|
|
9365
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9148
9366
|
return indexer.getStatus();
|
|
9149
9367
|
}
|
|
9150
|
-
async function getIndexHealthCheck(
|
|
9151
|
-
const indexer = getIndexerForProject(
|
|
9368
|
+
async function getIndexHealthCheck(projectRoot3, host) {
|
|
9369
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9152
9370
|
return indexer.healthCheck();
|
|
9153
9371
|
}
|
|
9154
|
-
async function getPrImpact(
|
|
9155
|
-
const indexer = getIndexerForProject(
|
|
9372
|
+
async function getPrImpact(projectRoot3, host, params) {
|
|
9373
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9156
9374
|
return indexer.getPrImpact({
|
|
9157
9375
|
pr: params.pr,
|
|
9158
9376
|
branch: params.branch,
|
|
@@ -9162,8 +9380,8 @@ async function getPrImpact(projectRoot2, host, params) {
|
|
|
9162
9380
|
direction: params.direction
|
|
9163
9381
|
});
|
|
9164
9382
|
}
|
|
9165
|
-
async function getIndexMetrics(
|
|
9166
|
-
const indexer = getIndexerForProject(
|
|
9383
|
+
async function getIndexMetrics(projectRoot3, host) {
|
|
9384
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9167
9385
|
const logger = indexer.getLogger();
|
|
9168
9386
|
if (!logger.isEnabled()) {
|
|
9169
9387
|
return {
|
|
@@ -9185,8 +9403,8 @@ async function getIndexMetrics(projectRoot2, host) {
|
|
|
9185
9403
|
text: logger.formatMetrics()
|
|
9186
9404
|
};
|
|
9187
9405
|
}
|
|
9188
|
-
async function getIndexLogs(
|
|
9189
|
-
const indexer = getIndexerForProject(
|
|
9406
|
+
async function getIndexLogs(projectRoot3, host, args) {
|
|
9407
|
+
const indexer = getIndexerForProject(projectRoot3, host);
|
|
9190
9408
|
const logger = indexer.getLogger();
|
|
9191
9409
|
if (!logger.isEnabled()) {
|
|
9192
9410
|
return {
|
|
@@ -9208,17 +9426,17 @@ async function getIndexLogs(projectRoot2, host, args) {
|
|
|
9208
9426
|
text: "No logs recorded yet. Logs are captured during indexing and search operations."
|
|
9209
9427
|
};
|
|
9210
9428
|
}
|
|
9211
|
-
const
|
|
9429
|
+
const text3 = logs.map((entry) => {
|
|
9212
9430
|
const dataStr = entry.data ? ` ${JSON.stringify(entry.data)}` : "";
|
|
9213
9431
|
return `[${entry.timestamp}] [${entry.level.toUpperCase()}] [${entry.category}] ${entry.message}${dataStr}`;
|
|
9214
9432
|
}).join("\n");
|
|
9215
|
-
return { kind: "entries", text:
|
|
9433
|
+
return { kind: "entries", text: text3 };
|
|
9216
9434
|
}
|
|
9217
|
-
function addKnowledgeBase(
|
|
9218
|
-
const root = getProjectRoot(
|
|
9435
|
+
function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
9436
|
+
const root = getProjectRoot(projectRoot3, host);
|
|
9219
9437
|
const inputPath = knowledgeBasePath.trim();
|
|
9220
|
-
const normalizedPath =
|
|
9221
|
-
|
|
9438
|
+
const normalizedPath = path15.resolve(
|
|
9439
|
+
path15.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
9222
9440
|
);
|
|
9223
9441
|
if (!existsSync9(normalizedPath)) {
|
|
9224
9442
|
return `Error: Directory does not exist: ${normalizedPath}`;
|
|
@@ -9254,7 +9472,7 @@ function addKnowledgeBase(projectRoot2, host, knowledgeBasePath) {
|
|
|
9254
9472
|
}
|
|
9255
9473
|
}
|
|
9256
9474
|
for (const dotDir of sensitiveDotDirs) {
|
|
9257
|
-
const sensitiveDir =
|
|
9475
|
+
const sensitiveDir = path15.join(homeDir, dotDir);
|
|
9258
9476
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
9259
9477
|
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath}`;
|
|
9260
9478
|
}
|
|
@@ -9287,8 +9505,8 @@ function addKnowledgeBase(projectRoot2, host, knowledgeBasePath) {
|
|
|
9287
9505
|
Run /index to rebuild the index with the new knowledge base.`;
|
|
9288
9506
|
return result;
|
|
9289
9507
|
}
|
|
9290
|
-
function listKnowledgeBases(
|
|
9291
|
-
const root = getProjectRoot(
|
|
9508
|
+
function listKnowledgeBases(projectRoot3, host) {
|
|
9509
|
+
const root = getProjectRoot(projectRoot3, host);
|
|
9292
9510
|
const config = loadRuntimeConfig(root, host);
|
|
9293
9511
|
const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
|
|
9294
9512
|
if (knowledgeBases.length === 0) {
|
|
@@ -9317,7 +9535,7 @@ function listKnowledgeBases(projectRoot2, host) {
|
|
|
9317
9535
|
}
|
|
9318
9536
|
result += "\n";
|
|
9319
9537
|
}
|
|
9320
|
-
const hasHostConfig = existsSync9(
|
|
9538
|
+
const hasHostConfig = existsSync9(path15.join(root, getHostProjectConfigRelativePath(host)));
|
|
9321
9539
|
if (hasHostConfig) {
|
|
9322
9540
|
result += `
|
|
9323
9541
|
Config sources: 1 file(s).`;
|
|
@@ -9326,8 +9544,8 @@ Config sources: 1 file(s).`;
|
|
|
9326
9544
|
Config file: ${getConfigPath(root, host)}`;
|
|
9327
9545
|
return result;
|
|
9328
9546
|
}
|
|
9329
|
-
function removeKnowledgeBase(
|
|
9330
|
-
const root = getProjectRoot(
|
|
9547
|
+
function removeKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
9548
|
+
const root = getProjectRoot(projectRoot3, host);
|
|
9331
9549
|
const config = loadEditableConfig(root, host);
|
|
9332
9550
|
const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
|
|
9333
9551
|
const index = findKnowledgeBasePathIndex(knowledgeBases, knowledgeBasePath, root);
|
|
@@ -9350,17 +9568,9 @@ Run /index to rebuild the index without the removed knowledge base.`;
|
|
|
9350
9568
|
return result;
|
|
9351
9569
|
}
|
|
9352
9570
|
|
|
9353
|
-
// src/pi-
|
|
9571
|
+
// src/pi-call-graph.ts
|
|
9572
|
+
import { Type } from "typebox";
|
|
9354
9573
|
var HOST = "pi";
|
|
9355
|
-
var ChunkType = Type.Union([
|
|
9356
|
-
Type.Literal("function"),
|
|
9357
|
-
Type.Literal("class"),
|
|
9358
|
-
Type.Literal("method"),
|
|
9359
|
-
Type.Literal("interface"),
|
|
9360
|
-
Type.Literal("type"),
|
|
9361
|
-
Type.Literal("module"),
|
|
9362
|
-
Type.Literal("block")
|
|
9363
|
-
]);
|
|
9364
9574
|
var RelationshipType = Type.Union([
|
|
9365
9575
|
Type.Literal("Call"),
|
|
9366
9576
|
Type.Literal("MethodCall"),
|
|
@@ -9369,214 +9579,247 @@ var RelationshipType = Type.Union([
|
|
|
9369
9579
|
Type.Literal("Inherits"),
|
|
9370
9580
|
Type.Literal("Implements")
|
|
9371
9581
|
]);
|
|
9372
|
-
function text(
|
|
9373
|
-
return { content: [{ type: "text", text:
|
|
9582
|
+
function text(text3, details) {
|
|
9583
|
+
return { content: [{ type: "text", text: text3 }], details };
|
|
9374
9584
|
}
|
|
9375
9585
|
function projectRoot(ctx) {
|
|
9376
9586
|
return ctx?.cwd ?? process.cwd();
|
|
9377
9587
|
}
|
|
9588
|
+
function registerPiCallGraphTools(pi) {
|
|
9589
|
+
pi.registerTool({
|
|
9590
|
+
name: "call_graph",
|
|
9591
|
+
label: "Call Graph",
|
|
9592
|
+
description: "Find callers or callees of a function/method in the indexed call graph.",
|
|
9593
|
+
parameters: Type.Object({
|
|
9594
|
+
name: Type.String(),
|
|
9595
|
+
direction: Type.Optional(Type.Union([Type.Literal("callers"), Type.Literal("callees")])),
|
|
9596
|
+
symbolId: Type.Optional(Type.String()),
|
|
9597
|
+
relationshipType: Type.Optional(RelationshipType)
|
|
9598
|
+
}),
|
|
9599
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9600
|
+
const result = await getCallGraphData(projectRoot(ctx), HOST, params);
|
|
9601
|
+
if (result.direction === "callees") {
|
|
9602
|
+
return text(
|
|
9603
|
+
params.symbolId ? formatCallGraphCallees(params.symbolId, result.callees, params.relationshipType) : "Error: 'symbolId' is required when direction is 'callees'.",
|
|
9604
|
+
result
|
|
9605
|
+
);
|
|
9606
|
+
}
|
|
9607
|
+
return text(formatCallGraphCallers(params.name, result.callers, params.relationshipType), result);
|
|
9608
|
+
}
|
|
9609
|
+
});
|
|
9610
|
+
pi.registerTool({
|
|
9611
|
+
name: "call_graph_path",
|
|
9612
|
+
label: "Call Graph Path",
|
|
9613
|
+
description: "Find a call path between two functions/methods.",
|
|
9614
|
+
parameters: Type.Object({
|
|
9615
|
+
from: Type.String(),
|
|
9616
|
+
to: Type.String(),
|
|
9617
|
+
maxDepth: Type.Optional(Type.Number({ default: 10 }))
|
|
9618
|
+
}),
|
|
9619
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9620
|
+
const result = await getCallGraphPath(projectRoot(ctx), HOST, params.from, params.to, params.maxDepth);
|
|
9621
|
+
return text(formatCallGraphPath(params.from, params.to, result), result);
|
|
9622
|
+
}
|
|
9623
|
+
});
|
|
9624
|
+
}
|
|
9625
|
+
|
|
9626
|
+
// src/pi-extension.ts
|
|
9627
|
+
var HOST2 = "pi";
|
|
9628
|
+
var ChunkType = Type2.Union([
|
|
9629
|
+
Type2.Literal("function"),
|
|
9630
|
+
Type2.Literal("class"),
|
|
9631
|
+
Type2.Literal("method"),
|
|
9632
|
+
Type2.Literal("interface"),
|
|
9633
|
+
Type2.Literal("type"),
|
|
9634
|
+
Type2.Literal("module"),
|
|
9635
|
+
Type2.Literal("block")
|
|
9636
|
+
]);
|
|
9637
|
+
function text2(text3, details) {
|
|
9638
|
+
return { content: [{ type: "text", text: text3 }], details };
|
|
9639
|
+
}
|
|
9640
|
+
function projectRoot2(ctx) {
|
|
9641
|
+
return ctx?.cwd ?? process.cwd();
|
|
9642
|
+
}
|
|
9378
9643
|
function codebaseIndexPiExtension(pi) {
|
|
9379
9644
|
pi.registerTool({
|
|
9380
9645
|
name: "codebase_search",
|
|
9381
9646
|
label: "Codebase Search",
|
|
9382
9647
|
description: "Semantic search over the indexed codebase. Describe behavior, not syntax.",
|
|
9383
|
-
parameters:
|
|
9384
|
-
query:
|
|
9385
|
-
limit:
|
|
9386
|
-
fileType:
|
|
9387
|
-
directory:
|
|
9388
|
-
chunkType:
|
|
9389
|
-
contextLines:
|
|
9648
|
+
parameters: Type2.Object({
|
|
9649
|
+
query: Type2.String({ description: "Natural language description of what code you're looking for" }),
|
|
9650
|
+
limit: Type2.Optional(Type2.Number({ description: "Maximum results (default: 10)" })),
|
|
9651
|
+
fileType: Type2.Optional(Type2.String({ description: "Filter by extension, e.g. ts, py, rs" })),
|
|
9652
|
+
directory: Type2.Optional(Type2.String({ description: "Filter by directory path" })),
|
|
9653
|
+
chunkType: Type2.Optional(ChunkType),
|
|
9654
|
+
contextLines: Type2.Optional(Type2.Number({ description: "Extra lines around each match" })),
|
|
9655
|
+
blameAuthor: Type2.Optional(Type2.String({ description: "Filter by git blame author name or email" })),
|
|
9656
|
+
blameSha: Type2.Optional(Type2.String({ description: "Filter by git blame commit SHA or prefix" })),
|
|
9657
|
+
blameSince: Type2.Optional(Type2.String({ description: "Filter to chunks last changed on or after this date" }))
|
|
9390
9658
|
}),
|
|
9391
9659
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9392
|
-
const results = await searchCodebase(
|
|
9393
|
-
return
|
|
9660
|
+
const results = await searchCodebase(projectRoot2(ctx), HOST2, params.query, params);
|
|
9661
|
+
return text2(formatSearchResults(results), results);
|
|
9394
9662
|
}
|
|
9395
9663
|
});
|
|
9396
9664
|
pi.registerTool({
|
|
9397
9665
|
name: "codebase_peek",
|
|
9398
9666
|
label: "Codebase Peek",
|
|
9399
9667
|
description: "Semantic search returning only metadata (file, lines, symbol) to save tokens.",
|
|
9400
|
-
parameters:
|
|
9401
|
-
query:
|
|
9402
|
-
limit:
|
|
9403
|
-
fileType:
|
|
9404
|
-
directory:
|
|
9405
|
-
chunkType:
|
|
9668
|
+
parameters: Type2.Object({
|
|
9669
|
+
query: Type2.String(),
|
|
9670
|
+
limit: Type2.Optional(Type2.Number()),
|
|
9671
|
+
fileType: Type2.Optional(Type2.String()),
|
|
9672
|
+
directory: Type2.Optional(Type2.String()),
|
|
9673
|
+
chunkType: Type2.Optional(ChunkType),
|
|
9674
|
+
blameAuthor: Type2.Optional(Type2.String()),
|
|
9675
|
+
blameSha: Type2.Optional(Type2.String()),
|
|
9676
|
+
blameSince: Type2.Optional(Type2.String())
|
|
9406
9677
|
}),
|
|
9407
9678
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9408
|
-
const results = await searchCodebase(
|
|
9409
|
-
return
|
|
9679
|
+
const results = await searchCodebase(projectRoot2(ctx), HOST2, params.query, { ...params, metadataOnly: true });
|
|
9680
|
+
return text2(formatSearchResults(results), results);
|
|
9410
9681
|
}
|
|
9411
9682
|
});
|
|
9412
9683
|
pi.registerTool({
|
|
9413
9684
|
name: "find_similar",
|
|
9414
9685
|
label: "Find Similar Code",
|
|
9415
9686
|
description: "Find code similar to a snippet for duplicate detection and pattern discovery.",
|
|
9416
|
-
parameters:
|
|
9417
|
-
code:
|
|
9418
|
-
limit:
|
|
9419
|
-
fileType:
|
|
9420
|
-
directory:
|
|
9421
|
-
chunkType:
|
|
9422
|
-
excludeFile:
|
|
9687
|
+
parameters: Type2.Object({
|
|
9688
|
+
code: Type2.String({ description: "Code snippet to compare" }),
|
|
9689
|
+
limit: Type2.Optional(Type2.Number()),
|
|
9690
|
+
fileType: Type2.Optional(Type2.String()),
|
|
9691
|
+
directory: Type2.Optional(Type2.String()),
|
|
9692
|
+
chunkType: Type2.Optional(ChunkType),
|
|
9693
|
+
excludeFile: Type2.Optional(Type2.String())
|
|
9423
9694
|
}),
|
|
9424
9695
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9425
|
-
const results = await findSimilarCode(
|
|
9426
|
-
return
|
|
9696
|
+
const results = await findSimilarCode(projectRoot2(ctx), HOST2, params.code, params);
|
|
9697
|
+
return text2(formatSearchResults(results, "similarity"), results);
|
|
9427
9698
|
}
|
|
9428
9699
|
});
|
|
9429
9700
|
pi.registerTool({
|
|
9430
9701
|
name: "implementation_lookup",
|
|
9431
9702
|
label: "Implementation Lookup",
|
|
9432
9703
|
description: "Find likely symbol definitions or implementations by name or natural language.",
|
|
9433
|
-
parameters:
|
|
9434
|
-
query:
|
|
9435
|
-
limit:
|
|
9436
|
-
fileType:
|
|
9437
|
-
directory:
|
|
9704
|
+
parameters: Type2.Object({
|
|
9705
|
+
query: Type2.String(),
|
|
9706
|
+
limit: Type2.Optional(Type2.Number()),
|
|
9707
|
+
fileType: Type2.Optional(Type2.String()),
|
|
9708
|
+
directory: Type2.Optional(Type2.String())
|
|
9438
9709
|
}),
|
|
9439
9710
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9440
|
-
const results = await implementationLookup(
|
|
9441
|
-
return
|
|
9711
|
+
const results = await implementationLookup(projectRoot2(ctx), HOST2, params.query, params);
|
|
9712
|
+
return text2(formatDefinitionLookup(results, params.query), results);
|
|
9442
9713
|
}
|
|
9443
9714
|
});
|
|
9444
9715
|
pi.registerTool({
|
|
9445
9716
|
name: "index_codebase",
|
|
9446
9717
|
label: "Index Codebase",
|
|
9447
9718
|
description: "Build or refresh the semantic codebase index.",
|
|
9448
|
-
parameters:
|
|
9449
|
-
force:
|
|
9450
|
-
estimateOnly:
|
|
9451
|
-
verbose:
|
|
9719
|
+
parameters: Type2.Object({
|
|
9720
|
+
force: Type2.Optional(Type2.Boolean({ default: false })),
|
|
9721
|
+
estimateOnly: Type2.Optional(Type2.Boolean({ default: false })),
|
|
9722
|
+
verbose: Type2.Optional(Type2.Boolean({ default: false }))
|
|
9452
9723
|
}),
|
|
9453
9724
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9454
|
-
const result = await runIndexCodebase(
|
|
9455
|
-
return result.kind === "estimate" ?
|
|
9725
|
+
const result = await runIndexCodebase(projectRoot2(ctx), HOST2, params);
|
|
9726
|
+
return result.kind === "estimate" ? text2(formatCostEstimate(result.estimate), result.estimate) : text2(formatIndexStats(result.stats, params.verbose ?? false), result.stats);
|
|
9456
9727
|
}
|
|
9457
9728
|
});
|
|
9458
9729
|
pi.registerTool({
|
|
9459
9730
|
name: "index_status",
|
|
9460
9731
|
label: "Index Status",
|
|
9461
9732
|
description: "Check index health and current status.",
|
|
9462
|
-
parameters:
|
|
9733
|
+
parameters: Type2.Object({}),
|
|
9463
9734
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
9464
|
-
const status = await getIndexStatus(
|
|
9465
|
-
return
|
|
9735
|
+
const status = await getIndexStatus(projectRoot2(ctx), HOST2);
|
|
9736
|
+
return text2(formatStatus(status), status);
|
|
9466
9737
|
}
|
|
9467
9738
|
});
|
|
9468
9739
|
pi.registerTool({
|
|
9469
9740
|
name: "index_health_check",
|
|
9470
9741
|
label: "Index Health Check",
|
|
9471
9742
|
description: "Garbage collect orphaned embeddings/chunks and report health.",
|
|
9472
|
-
parameters:
|
|
9743
|
+
parameters: Type2.Object({}),
|
|
9473
9744
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
9474
|
-
const result = await getIndexHealthCheck(
|
|
9475
|
-
return
|
|
9745
|
+
const result = await getIndexHealthCheck(projectRoot2(ctx), HOST2);
|
|
9746
|
+
return text2(formatHealthCheck(result), result);
|
|
9476
9747
|
}
|
|
9477
9748
|
});
|
|
9478
9749
|
pi.registerTool({
|
|
9479
9750
|
name: "index_metrics",
|
|
9480
9751
|
label: "Index Metrics",
|
|
9481
9752
|
description: "Return collected performance metrics when debug metrics are enabled.",
|
|
9482
|
-
parameters:
|
|
9753
|
+
parameters: Type2.Object({}),
|
|
9483
9754
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
9484
|
-
const result = await getIndexMetrics(
|
|
9485
|
-
return
|
|
9755
|
+
const result = await getIndexMetrics(projectRoot2(ctx), HOST2);
|
|
9756
|
+
return text2(result.text, result);
|
|
9486
9757
|
}
|
|
9487
9758
|
});
|
|
9488
9759
|
pi.registerTool({
|
|
9489
9760
|
name: "index_logs",
|
|
9490
9761
|
label: "Index Logs",
|
|
9491
9762
|
description: "Return recent debug logs when debug logging is enabled.",
|
|
9492
|
-
parameters:
|
|
9493
|
-
limit:
|
|
9494
|
-
category:
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9763
|
+
parameters: Type2.Object({
|
|
9764
|
+
limit: Type2.Optional(Type2.Number()),
|
|
9765
|
+
category: Type2.Optional(Type2.Union([
|
|
9766
|
+
Type2.Literal("search"),
|
|
9767
|
+
Type2.Literal("embedding"),
|
|
9768
|
+
Type2.Literal("cache"),
|
|
9769
|
+
Type2.Literal("gc"),
|
|
9770
|
+
Type2.Literal("branch"),
|
|
9771
|
+
Type2.Literal("general")
|
|
9501
9772
|
])),
|
|
9502
|
-
level:
|
|
9773
|
+
level: Type2.Optional(Type2.Union([Type2.Literal("error"), Type2.Literal("warn"), Type2.Literal("info"), Type2.Literal("debug")]))
|
|
9503
9774
|
}),
|
|
9504
9775
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9505
|
-
const result = await getIndexLogs(
|
|
9506
|
-
return
|
|
9507
|
-
}
|
|
9508
|
-
});
|
|
9509
|
-
pi.registerTool({
|
|
9510
|
-
name: "call_graph",
|
|
9511
|
-
label: "Call Graph",
|
|
9512
|
-
description: "Find callers or callees of a function/method in the indexed call graph.",
|
|
9513
|
-
parameters: Type.Object({
|
|
9514
|
-
name: Type.String(),
|
|
9515
|
-
direction: Type.Optional(Type.Union([Type.Literal("callers"), Type.Literal("callees")])),
|
|
9516
|
-
symbolId: Type.Optional(Type.String()),
|
|
9517
|
-
relationshipType: Type.Optional(RelationshipType)
|
|
9518
|
-
}),
|
|
9519
|
-
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9520
|
-
const result = await getCallGraphData(projectRoot(ctx), HOST, params);
|
|
9521
|
-
return text(JSON.stringify(result, null, 2), result);
|
|
9522
|
-
}
|
|
9523
|
-
});
|
|
9524
|
-
pi.registerTool({
|
|
9525
|
-
name: "call_graph_path",
|
|
9526
|
-
label: "Call Graph Path",
|
|
9527
|
-
description: "Find a call path between two functions/methods.",
|
|
9528
|
-
parameters: Type.Object({
|
|
9529
|
-
from: Type.String(),
|
|
9530
|
-
to: Type.String(),
|
|
9531
|
-
maxDepth: Type.Optional(Type.Number({ default: 10 }))
|
|
9532
|
-
}),
|
|
9533
|
-
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9534
|
-
const result = await getCallGraphPath(projectRoot(ctx), HOST, params.from, params.to, params.maxDepth);
|
|
9535
|
-
return text(JSON.stringify(result, null, 2), result);
|
|
9776
|
+
const result = await getIndexLogs(projectRoot2(ctx), HOST2, params);
|
|
9777
|
+
return text2(result.text, result);
|
|
9536
9778
|
}
|
|
9537
9779
|
});
|
|
9780
|
+
registerPiCallGraphTools(pi);
|
|
9538
9781
|
pi.registerTool({
|
|
9539
9782
|
name: "pr_impact",
|
|
9540
9783
|
label: "PR Impact",
|
|
9541
9784
|
description: "Analyze PR or branch impact through changed symbols and call graph neighborhoods.",
|
|
9542
|
-
parameters:
|
|
9543
|
-
pr:
|
|
9544
|
-
branch:
|
|
9545
|
-
maxDepth:
|
|
9546
|
-
hubThreshold:
|
|
9547
|
-
checkConflicts:
|
|
9548
|
-
direction:
|
|
9785
|
+
parameters: Type2.Object({
|
|
9786
|
+
pr: Type2.Optional(Type2.Number()),
|
|
9787
|
+
branch: Type2.Optional(Type2.String()),
|
|
9788
|
+
maxDepth: Type2.Optional(Type2.Number({ default: 5 })),
|
|
9789
|
+
hubThreshold: Type2.Optional(Type2.Number({ default: 10 })),
|
|
9790
|
+
checkConflicts: Type2.Optional(Type2.Boolean({ default: false })),
|
|
9791
|
+
direction: Type2.Optional(Type2.Union([Type2.Literal("callers"), Type2.Literal("callees"), Type2.Literal("both")]))
|
|
9549
9792
|
}),
|
|
9550
9793
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9551
|
-
const result = await getPrImpact(
|
|
9552
|
-
return
|
|
9794
|
+
const result = await getPrImpact(projectRoot2(ctx), HOST2, params);
|
|
9795
|
+
return text2(formatPrImpact(result), result);
|
|
9553
9796
|
}
|
|
9554
9797
|
});
|
|
9555
9798
|
pi.registerTool({
|
|
9556
9799
|
name: "knowledge_base_list",
|
|
9557
9800
|
label: "List Knowledge Bases",
|
|
9558
9801
|
description: "List configured knowledge-base paths included in the index.",
|
|
9559
|
-
parameters:
|
|
9802
|
+
parameters: Type2.Object({}),
|
|
9560
9803
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
9561
|
-
return
|
|
9804
|
+
return text2(listKnowledgeBases(projectRoot2(ctx), HOST2));
|
|
9562
9805
|
}
|
|
9563
9806
|
});
|
|
9564
9807
|
pi.registerTool({
|
|
9565
9808
|
name: "knowledge_base_add",
|
|
9566
9809
|
label: "Add Knowledge Base",
|
|
9567
9810
|
description: "Add a knowledge-base path to the codebase index config.",
|
|
9568
|
-
parameters:
|
|
9811
|
+
parameters: Type2.Object({ path: Type2.String({ description: "File or directory path to add" }) }),
|
|
9569
9812
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9570
|
-
return
|
|
9813
|
+
return text2(addKnowledgeBase(projectRoot2(ctx), HOST2, params.path));
|
|
9571
9814
|
}
|
|
9572
9815
|
});
|
|
9573
9816
|
pi.registerTool({
|
|
9574
9817
|
name: "knowledge_base_remove",
|
|
9575
9818
|
label: "Remove Knowledge Base",
|
|
9576
9819
|
description: "Remove a knowledge-base path from the codebase index config.",
|
|
9577
|
-
parameters:
|
|
9820
|
+
parameters: Type2.Object({ path: Type2.String({ description: "File or directory path to remove" }) }),
|
|
9578
9821
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9579
|
-
return
|
|
9822
|
+
return text2(removeKnowledgeBase(projectRoot2(ctx), HOST2, params.path));
|
|
9580
9823
|
}
|
|
9581
9824
|
});
|
|
9582
9825
|
}
|