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/cli.js
CHANGED
|
@@ -491,7 +491,7 @@ var require_ignore = __commonJS({
|
|
|
491
491
|
// path matching.
|
|
492
492
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
493
493
|
// @returns {TestResult} true if a file is ignored
|
|
494
|
-
test(
|
|
494
|
+
test(path26, checkUnignored, mode) {
|
|
495
495
|
let ignored = false;
|
|
496
496
|
let unignored = false;
|
|
497
497
|
let matchedRule;
|
|
@@ -500,7 +500,7 @@ var require_ignore = __commonJS({
|
|
|
500
500
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
501
501
|
return;
|
|
502
502
|
}
|
|
503
|
-
const matched = rule[mode].test(
|
|
503
|
+
const matched = rule[mode].test(path26);
|
|
504
504
|
if (!matched) {
|
|
505
505
|
return;
|
|
506
506
|
}
|
|
@@ -521,17 +521,17 @@ var require_ignore = __commonJS({
|
|
|
521
521
|
var throwError = (message, Ctor) => {
|
|
522
522
|
throw new Ctor(message);
|
|
523
523
|
};
|
|
524
|
-
var checkPath = (
|
|
525
|
-
if (!isString(
|
|
524
|
+
var checkPath = (path26, originalPath, doThrow) => {
|
|
525
|
+
if (!isString(path26)) {
|
|
526
526
|
return doThrow(
|
|
527
527
|
`path must be a string, but got \`${originalPath}\``,
|
|
528
528
|
TypeError
|
|
529
529
|
);
|
|
530
530
|
}
|
|
531
|
-
if (!
|
|
531
|
+
if (!path26) {
|
|
532
532
|
return doThrow(`path must not be empty`, TypeError);
|
|
533
533
|
}
|
|
534
|
-
if (checkPath.isNotRelative(
|
|
534
|
+
if (checkPath.isNotRelative(path26)) {
|
|
535
535
|
const r = "`path.relative()`d";
|
|
536
536
|
return doThrow(
|
|
537
537
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -540,7 +540,7 @@ var require_ignore = __commonJS({
|
|
|
540
540
|
}
|
|
541
541
|
return true;
|
|
542
542
|
};
|
|
543
|
-
var isNotRelative = (
|
|
543
|
+
var isNotRelative = (path26) => REGEX_TEST_INVALID_PATH.test(path26);
|
|
544
544
|
checkPath.isNotRelative = isNotRelative;
|
|
545
545
|
checkPath.convert = (p) => p;
|
|
546
546
|
var Ignore2 = class {
|
|
@@ -570,19 +570,19 @@ var require_ignore = __commonJS({
|
|
|
570
570
|
}
|
|
571
571
|
// @returns {TestResult}
|
|
572
572
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
573
|
-
const
|
|
573
|
+
const path26 = originalPath && checkPath.convert(originalPath);
|
|
574
574
|
checkPath(
|
|
575
|
-
|
|
575
|
+
path26,
|
|
576
576
|
originalPath,
|
|
577
577
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
578
578
|
);
|
|
579
|
-
return this._t(
|
|
579
|
+
return this._t(path26, cache, checkUnignored, slices);
|
|
580
580
|
}
|
|
581
|
-
checkIgnore(
|
|
582
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
583
|
-
return this.test(
|
|
581
|
+
checkIgnore(path26) {
|
|
582
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path26)) {
|
|
583
|
+
return this.test(path26);
|
|
584
584
|
}
|
|
585
|
-
const slices =
|
|
585
|
+
const slices = path26.split(SLASH2).filter(Boolean);
|
|
586
586
|
slices.pop();
|
|
587
587
|
if (slices.length) {
|
|
588
588
|
const parent = this._t(
|
|
@@ -595,18 +595,18 @@ var require_ignore = __commonJS({
|
|
|
595
595
|
return parent;
|
|
596
596
|
}
|
|
597
597
|
}
|
|
598
|
-
return this._rules.test(
|
|
598
|
+
return this._rules.test(path26, false, MODE_CHECK_IGNORE);
|
|
599
599
|
}
|
|
600
|
-
_t(
|
|
601
|
-
if (
|
|
602
|
-
return cache[
|
|
600
|
+
_t(path26, cache, checkUnignored, slices) {
|
|
601
|
+
if (path26 in cache) {
|
|
602
|
+
return cache[path26];
|
|
603
603
|
}
|
|
604
604
|
if (!slices) {
|
|
605
|
-
slices =
|
|
605
|
+
slices = path26.split(SLASH2).filter(Boolean);
|
|
606
606
|
}
|
|
607
607
|
slices.pop();
|
|
608
608
|
if (!slices.length) {
|
|
609
|
-
return cache[
|
|
609
|
+
return cache[path26] = this._rules.test(path26, checkUnignored, MODE_IGNORE);
|
|
610
610
|
}
|
|
611
611
|
const parent = this._t(
|
|
612
612
|
slices.join(SLASH2) + SLASH2,
|
|
@@ -614,29 +614,29 @@ var require_ignore = __commonJS({
|
|
|
614
614
|
checkUnignored,
|
|
615
615
|
slices
|
|
616
616
|
);
|
|
617
|
-
return cache[
|
|
617
|
+
return cache[path26] = parent.ignored ? parent : this._rules.test(path26, checkUnignored, MODE_IGNORE);
|
|
618
618
|
}
|
|
619
|
-
ignores(
|
|
620
|
-
return this._test(
|
|
619
|
+
ignores(path26) {
|
|
620
|
+
return this._test(path26, this._ignoreCache, false).ignored;
|
|
621
621
|
}
|
|
622
622
|
createFilter() {
|
|
623
|
-
return (
|
|
623
|
+
return (path26) => !this.ignores(path26);
|
|
624
624
|
}
|
|
625
625
|
filter(paths) {
|
|
626
626
|
return makeArray(paths).filter(this.createFilter());
|
|
627
627
|
}
|
|
628
628
|
// @returns {TestResult}
|
|
629
|
-
test(
|
|
630
|
-
return this._test(
|
|
629
|
+
test(path26) {
|
|
630
|
+
return this._test(path26, this._testCache, true);
|
|
631
631
|
}
|
|
632
632
|
};
|
|
633
633
|
var factory = (options) => new Ignore2(options);
|
|
634
|
-
var isPathValid = (
|
|
634
|
+
var isPathValid = (path26) => checkPath(path26 && checkPath.convert(path26), path26, RETURN_FALSE);
|
|
635
635
|
var setupWindows = () => {
|
|
636
636
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
637
637
|
checkPath.convert = makePosix;
|
|
638
638
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
639
|
-
checkPath.isNotRelative = (
|
|
639
|
+
checkPath.isNotRelative = (path26) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path26) || isNotRelative(path26);
|
|
640
640
|
};
|
|
641
641
|
if (
|
|
642
642
|
// Detect `process` so that it can run in browsers.
|
|
@@ -655,7 +655,7 @@ var require_ignore = __commonJS({
|
|
|
655
655
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
656
656
|
import { realpathSync as realpathSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
657
657
|
import * as os5 from "os";
|
|
658
|
-
import * as
|
|
658
|
+
import * as path25 from "path";
|
|
659
659
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
660
660
|
|
|
661
661
|
// src/config/constants.ts
|
|
@@ -788,7 +788,8 @@ function getDefaultIndexingConfig() {
|
|
|
788
788
|
requireProjectMarker: true,
|
|
789
789
|
maxDepth: 5,
|
|
790
790
|
maxFilesPerDirectory: 100,
|
|
791
|
-
fallbackToTextOnMaxChunks: true
|
|
791
|
+
fallbackToTextOnMaxChunks: true,
|
|
792
|
+
gitBlame: { enabled: false }
|
|
792
793
|
};
|
|
793
794
|
}
|
|
794
795
|
function getDefaultSearchConfig() {
|
|
@@ -912,7 +913,10 @@ function parseConfig(raw) {
|
|
|
912
913
|
requireProjectMarker: typeof rawIndexing.requireProjectMarker === "boolean" ? rawIndexing.requireProjectMarker : defaultIndexing.requireProjectMarker,
|
|
913
914
|
maxDepth: typeof rawIndexing.maxDepth === "number" ? rawIndexing.maxDepth < -1 ? -1 : rawIndexing.maxDepth : defaultIndexing.maxDepth,
|
|
914
915
|
maxFilesPerDirectory: typeof rawIndexing.maxFilesPerDirectory === "number" ? Math.max(1, rawIndexing.maxFilesPerDirectory) : defaultIndexing.maxFilesPerDirectory,
|
|
915
|
-
fallbackToTextOnMaxChunks: typeof rawIndexing.fallbackToTextOnMaxChunks === "boolean" ? rawIndexing.fallbackToTextOnMaxChunks : defaultIndexing.fallbackToTextOnMaxChunks
|
|
916
|
+
fallbackToTextOnMaxChunks: typeof rawIndexing.fallbackToTextOnMaxChunks === "boolean" ? rawIndexing.fallbackToTextOnMaxChunks : defaultIndexing.fallbackToTextOnMaxChunks,
|
|
917
|
+
gitBlame: {
|
|
918
|
+
enabled: rawIndexing.gitBlame && typeof rawIndexing.gitBlame === "object" && typeof rawIndexing.gitBlame.enabled === "boolean" ? rawIndexing.gitBlame.enabled : defaultIndexing.gitBlame.enabled
|
|
919
|
+
}
|
|
916
920
|
};
|
|
917
921
|
const rawSearch = input.search && typeof input.search === "object" ? input.search : {};
|
|
918
922
|
const search = {
|
|
@@ -1097,9 +1101,9 @@ import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
|
1097
1101
|
import * as path from "path";
|
|
1098
1102
|
|
|
1099
1103
|
// src/eval/report-formatters.ts
|
|
1100
|
-
function assertFiniteNumber(value,
|
|
1104
|
+
function assertFiniteNumber(value, path26) {
|
|
1101
1105
|
if (typeof value !== "number" || Number.isNaN(value) || !Number.isFinite(value)) {
|
|
1102
|
-
throw new Error(`${
|
|
1106
|
+
throw new Error(`${path26} must be a finite number`);
|
|
1103
1107
|
}
|
|
1104
1108
|
return value;
|
|
1105
1109
|
}
|
|
@@ -1288,15 +1292,15 @@ function buildPerQueryArtifact(perQuery) {
|
|
|
1288
1292
|
|
|
1289
1293
|
// src/eval/runner.ts
|
|
1290
1294
|
import { existsSync as existsSync8 } from "fs";
|
|
1291
|
-
import * as
|
|
1295
|
+
import * as path14 from "path";
|
|
1292
1296
|
import { performance as performance3 } from "perf_hooks";
|
|
1293
1297
|
|
|
1294
1298
|
// src/indexer/index.ts
|
|
1295
1299
|
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync2, renameSync, unlinkSync, mkdirSync as mkdirSync2, promises as fsPromises2 } from "fs";
|
|
1296
|
-
import * as
|
|
1300
|
+
import * as path11 from "path";
|
|
1297
1301
|
import { performance as performance2 } from "perf_hooks";
|
|
1298
|
-
import { execFile as
|
|
1299
|
-
import { promisify as
|
|
1302
|
+
import { execFile as execFile3 } from "child_process";
|
|
1303
|
+
import { promisify as promisify3 } from "util";
|
|
1300
1304
|
|
|
1301
1305
|
// node_modules/eventemitter3/index.mjs
|
|
1302
1306
|
var import_index = __toESM(require_eventemitter3(), 1);
|
|
@@ -4826,8 +4830,8 @@ function normalizeFiles(rawFiles, projectRoot) {
|
|
|
4826
4830
|
const trimmed = raw.trim();
|
|
4827
4831
|
if (!trimmed) continue;
|
|
4828
4832
|
const absolute = path9.resolve(projectRoot, trimmed);
|
|
4829
|
-
const
|
|
4830
|
-
const cleaned =
|
|
4833
|
+
const relative11 = path9.relative(projectRoot, absolute);
|
|
4834
|
+
const cleaned = relative11.startsWith("./") ? relative11.slice(2) : relative11;
|
|
4831
4835
|
if (!seen.has(cleaned)) {
|
|
4832
4836
|
seen.add(cleaned);
|
|
4833
4837
|
result.push(cleaned);
|
|
@@ -4836,8 +4840,61 @@ function normalizeFiles(rawFiles, projectRoot) {
|
|
|
4836
4840
|
return result;
|
|
4837
4841
|
}
|
|
4838
4842
|
|
|
4843
|
+
// src/indexer/git-blame.ts
|
|
4844
|
+
import { execFile as execFile2 } from "child_process";
|
|
4845
|
+
import * as path10 from "path";
|
|
4846
|
+
import { promisify as promisify2 } from "util";
|
|
4847
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
4848
|
+
function parseGitBlamePorcelain(output) {
|
|
4849
|
+
const commits = /* @__PURE__ */ new Map();
|
|
4850
|
+
let current;
|
|
4851
|
+
for (const line of output.split("\n")) {
|
|
4852
|
+
if (/^[0-9a-f]{40} /.test(line)) {
|
|
4853
|
+
const sha = line.slice(0, 40);
|
|
4854
|
+
current = commits.get(sha) ?? {
|
|
4855
|
+
sha,
|
|
4856
|
+
author: "",
|
|
4857
|
+
authorEmail: "",
|
|
4858
|
+
committedAt: 0,
|
|
4859
|
+
summary: "",
|
|
4860
|
+
lines: 0
|
|
4861
|
+
};
|
|
4862
|
+
commits.set(sha, current);
|
|
4863
|
+
continue;
|
|
4864
|
+
}
|
|
4865
|
+
if (!current) {
|
|
4866
|
+
continue;
|
|
4867
|
+
}
|
|
4868
|
+
if (line.startsWith("author ")) {
|
|
4869
|
+
current.author = line.slice("author ".length);
|
|
4870
|
+
} else if (line.startsWith("author-mail ")) {
|
|
4871
|
+
current.authorEmail = line.slice("author-mail ".length).replace(/^<|>$/g, "");
|
|
4872
|
+
} else if (line.startsWith("author-time ")) {
|
|
4873
|
+
current.committedAt = Number.parseInt(line.slice("author-time ".length), 10);
|
|
4874
|
+
} else if (line.startsWith("summary ")) {
|
|
4875
|
+
current.summary = line.slice("summary ".length);
|
|
4876
|
+
} else if (line.startsWith(" ")) {
|
|
4877
|
+
current.lines += 1;
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4880
|
+
return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
|
|
4881
|
+
}
|
|
4882
|
+
async function getChunkGitBlame(projectRoot, filePath, startLine, endLine) {
|
|
4883
|
+
const relativePath = path10.relative(projectRoot, filePath);
|
|
4884
|
+
try {
|
|
4885
|
+
const { stdout } = await execFileAsync2(
|
|
4886
|
+
"git",
|
|
4887
|
+
["blame", "--line-porcelain", "-L", `${startLine},${endLine}`, "--", relativePath],
|
|
4888
|
+
{ cwd: projectRoot, timeout: 3e4 }
|
|
4889
|
+
);
|
|
4890
|
+
return parseGitBlamePorcelain(stdout);
|
|
4891
|
+
} catch {
|
|
4892
|
+
return void 0;
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
|
|
4839
4896
|
// src/indexer/index.ts
|
|
4840
|
-
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab"]);
|
|
4897
|
+
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab", "bash"]);
|
|
4841
4898
|
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
|
|
4842
4899
|
var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
4843
4900
|
"function_declaration",
|
|
@@ -4917,6 +4974,45 @@ function isSqliteCorruptionError(error) {
|
|
|
4917
4974
|
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");
|
|
4918
4975
|
}
|
|
4919
4976
|
var STARTUP_WARNING_METADATA_KEY = "index.startupWarning";
|
|
4977
|
+
function metadataFromBlame(blame) {
|
|
4978
|
+
if (!blame) {
|
|
4979
|
+
return {};
|
|
4980
|
+
}
|
|
4981
|
+
return {
|
|
4982
|
+
blameSha: blame.sha,
|
|
4983
|
+
blameAuthor: blame.author,
|
|
4984
|
+
blameAuthorEmail: blame.authorEmail,
|
|
4985
|
+
blameCommittedAt: blame.committedAt,
|
|
4986
|
+
blameSummary: blame.summary
|
|
4987
|
+
};
|
|
4988
|
+
}
|
|
4989
|
+
function blameFromChunkData(chunk) {
|
|
4990
|
+
if (!chunk?.blameSha || !chunk.blameAuthor || !chunk.blameAuthorEmail || chunk.blameCommittedAt === void 0 || !chunk.blameSummary) {
|
|
4991
|
+
return void 0;
|
|
4992
|
+
}
|
|
4993
|
+
return {
|
|
4994
|
+
sha: chunk.blameSha,
|
|
4995
|
+
author: chunk.blameAuthor,
|
|
4996
|
+
authorEmail: chunk.blameAuthorEmail,
|
|
4997
|
+
committedAt: chunk.blameCommittedAt,
|
|
4998
|
+
summary: chunk.blameSummary
|
|
4999
|
+
};
|
|
5000
|
+
}
|
|
5001
|
+
function blameFromMetadata(metadata) {
|
|
5002
|
+
if (!metadata.blameSha || !metadata.blameAuthor || !metadata.blameAuthorEmail || metadata.blameCommittedAt === void 0 || !metadata.blameSummary) {
|
|
5003
|
+
return void 0;
|
|
5004
|
+
}
|
|
5005
|
+
return {
|
|
5006
|
+
sha: metadata.blameSha,
|
|
5007
|
+
author: metadata.blameAuthor,
|
|
5008
|
+
authorEmail: metadata.blameAuthorEmail,
|
|
5009
|
+
committedAt: metadata.blameCommittedAt,
|
|
5010
|
+
summary: metadata.blameSummary
|
|
5011
|
+
};
|
|
5012
|
+
}
|
|
5013
|
+
function hasBlameMetadata(metadata) {
|
|
5014
|
+
return blameFromMetadata(metadata) !== void 0;
|
|
5015
|
+
}
|
|
4920
5016
|
var INDEX_METADATA_VERSION = "1";
|
|
4921
5017
|
var EMBEDDING_STRATEGY_VERSION = "2";
|
|
4922
5018
|
var RANKING_TOKEN_CACHE_LIMIT = 4096;
|
|
@@ -5075,9 +5171,9 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
5075
5171
|
return true;
|
|
5076
5172
|
}
|
|
5077
5173
|
function isPathWithinRoot(filePath, rootPath) {
|
|
5078
|
-
const normalizedFilePath =
|
|
5079
|
-
const normalizedRoot =
|
|
5080
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
5174
|
+
const normalizedFilePath = path11.resolve(filePath);
|
|
5175
|
+
const normalizedRoot = path11.resolve(rootPath);
|
|
5176
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path11.sep}`);
|
|
5081
5177
|
}
|
|
5082
5178
|
var rankingQueryTokenCache = /* @__PURE__ */ new Map();
|
|
5083
5179
|
var rankingNameTokenCache = /* @__PURE__ */ new Map();
|
|
@@ -5836,7 +5932,8 @@ function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCa
|
|
|
5836
5932
|
chunkType,
|
|
5837
5933
|
name: chunk.name ?? void 0,
|
|
5838
5934
|
language: chunk.language,
|
|
5839
|
-
hash: chunk.contentHash
|
|
5935
|
+
hash: chunk.contentHash,
|
|
5936
|
+
...metadataFromBlame(blameFromChunkData(chunk))
|
|
5840
5937
|
};
|
|
5841
5938
|
const baselineScore = existing?.score ?? 0.5;
|
|
5842
5939
|
candidateUnion.set(chunk.chunkId, {
|
|
@@ -5920,7 +6017,8 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
5920
6017
|
chunkType,
|
|
5921
6018
|
name: chunk.name ?? void 0,
|
|
5922
6019
|
language: chunk.language,
|
|
5923
|
-
hash: chunk.contentHash
|
|
6020
|
+
hash: chunk.contentHash,
|
|
6021
|
+
...metadataFromBlame(blameFromChunkData(chunk))
|
|
5924
6022
|
}
|
|
5925
6023
|
});
|
|
5926
6024
|
}
|
|
@@ -6089,6 +6187,21 @@ function matchesSearchFilters(candidate, options, minScore) {
|
|
|
6089
6187
|
if (options?.chunkType && candidate.metadata.chunkType !== options.chunkType) {
|
|
6090
6188
|
return false;
|
|
6091
6189
|
}
|
|
6190
|
+
if (options?.blameAuthor) {
|
|
6191
|
+
const author = options.blameAuthor.toLowerCase();
|
|
6192
|
+
const candidateAuthor = candidate.metadata.blameAuthor?.toLowerCase();
|
|
6193
|
+
const candidateEmail = candidate.metadata.blameAuthorEmail?.toLowerCase();
|
|
6194
|
+
if (candidateAuthor !== author && candidateEmail !== author) return false;
|
|
6195
|
+
}
|
|
6196
|
+
if (options?.blameSha && !candidate.metadata.blameSha?.toLowerCase().startsWith(options.blameSha.toLowerCase())) {
|
|
6197
|
+
return false;
|
|
6198
|
+
}
|
|
6199
|
+
if (options?.blameSince) {
|
|
6200
|
+
const sinceMs = Date.parse(options.blameSince);
|
|
6201
|
+
if (Number.isNaN(sinceMs)) return false;
|
|
6202
|
+
const committedAt = candidate.metadata.blameCommittedAt;
|
|
6203
|
+
if (committedAt === void 0 || committedAt < Math.floor(sinceMs / 1e3)) return false;
|
|
6204
|
+
}
|
|
6092
6205
|
return true;
|
|
6093
6206
|
}
|
|
6094
6207
|
function unionCandidates(semanticCandidates, keywordCandidates) {
|
|
@@ -6132,9 +6245,9 @@ var Indexer = class {
|
|
|
6132
6245
|
this.config = config;
|
|
6133
6246
|
this.host = host;
|
|
6134
6247
|
this.indexPath = this.getIndexPath();
|
|
6135
|
-
this.fileHashCachePath =
|
|
6136
|
-
this.failedBatchesPath =
|
|
6137
|
-
this.indexingLockPath =
|
|
6248
|
+
this.fileHashCachePath = path11.join(this.indexPath, "file-hashes.json");
|
|
6249
|
+
this.failedBatchesPath = path11.join(this.indexPath, "failed-batches.json");
|
|
6250
|
+
this.indexingLockPath = path11.join(this.indexPath, "indexing.lock");
|
|
6138
6251
|
this.logger = initializeLogger(config.debug);
|
|
6139
6252
|
}
|
|
6140
6253
|
getIndexPath() {
|
|
@@ -6166,14 +6279,14 @@ var Indexer = class {
|
|
|
6166
6279
|
}
|
|
6167
6280
|
atomicWriteSync(targetPath, data) {
|
|
6168
6281
|
const tempPath = `${targetPath}.tmp`;
|
|
6169
|
-
mkdirSync2(
|
|
6282
|
+
mkdirSync2(path11.dirname(targetPath), { recursive: true });
|
|
6170
6283
|
writeFileSync2(tempPath, data);
|
|
6171
6284
|
renameSync(tempPath, targetPath);
|
|
6172
6285
|
}
|
|
6173
6286
|
getScopedRoots() {
|
|
6174
|
-
const roots = /* @__PURE__ */ new Set([
|
|
6287
|
+
const roots = /* @__PURE__ */ new Set([path11.resolve(this.projectRoot)]);
|
|
6175
6288
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
6176
|
-
roots.add(
|
|
6289
|
+
roots.add(path11.resolve(this.projectRoot, kbRoot));
|
|
6177
6290
|
}
|
|
6178
6291
|
return Array.from(roots);
|
|
6179
6292
|
}
|
|
@@ -6182,29 +6295,29 @@ var Indexer = class {
|
|
|
6182
6295
|
if (this.config.scope !== "global") {
|
|
6183
6296
|
return branchName;
|
|
6184
6297
|
}
|
|
6185
|
-
const projectHash = hashContent(
|
|
6298
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6186
6299
|
return `${projectHash}:${branchName}`;
|
|
6187
6300
|
}
|
|
6188
6301
|
getBranchCatalogKeyFor(branchName) {
|
|
6189
6302
|
if (this.config.scope !== "global") {
|
|
6190
6303
|
return branchName;
|
|
6191
6304
|
}
|
|
6192
|
-
const projectHash = hashContent(
|
|
6305
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6193
6306
|
return `${projectHash}:${branchName}`;
|
|
6194
6307
|
}
|
|
6195
6308
|
getLegacyBranchCatalogKey() {
|
|
6196
6309
|
return this.currentBranch || "default";
|
|
6197
6310
|
}
|
|
6198
6311
|
getLegacyMigrationMetadataKey() {
|
|
6199
|
-
const projectHash = hashContent(
|
|
6312
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6200
6313
|
return `index.globalBranchMigration.${projectHash}`;
|
|
6201
6314
|
}
|
|
6202
6315
|
getProjectEmbeddingStrategyMetadataKey() {
|
|
6203
|
-
const projectHash = hashContent(
|
|
6316
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6204
6317
|
return `index.embeddingStrategyVersion.${projectHash}`;
|
|
6205
6318
|
}
|
|
6206
6319
|
getProjectForceReembedMetadataKey() {
|
|
6207
|
-
const projectHash = hashContent(
|
|
6320
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6208
6321
|
return `index.forceReembed.${projectHash}`;
|
|
6209
6322
|
}
|
|
6210
6323
|
hasProjectForceReembedPending() {
|
|
@@ -6298,7 +6411,7 @@ var Indexer = class {
|
|
|
6298
6411
|
if (!this.database) {
|
|
6299
6412
|
return { chunkIds, symbolIds };
|
|
6300
6413
|
}
|
|
6301
|
-
const projectRootPath =
|
|
6414
|
+
const projectRootPath = path11.resolve(this.projectRoot);
|
|
6302
6415
|
const projectLocalFilePaths = /* @__PURE__ */ new Set([
|
|
6303
6416
|
...Array.from(this.fileHashCache.keys()).filter(
|
|
6304
6417
|
(filePath) => this.isFileInCurrentScope(filePath, roots) && isPathWithinRoot(filePath, projectRootPath)
|
|
@@ -6321,7 +6434,7 @@ var Indexer = class {
|
|
|
6321
6434
|
if (this.config.scope !== "global") {
|
|
6322
6435
|
return this.getBranchCatalogCleanupKeys();
|
|
6323
6436
|
}
|
|
6324
|
-
const projectHash = hashContent(
|
|
6437
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6325
6438
|
const keys = /* @__PURE__ */ new Set();
|
|
6326
6439
|
const projectChunkIdSet = new Set(projectChunkIds);
|
|
6327
6440
|
const projectSymbolIdSet = new Set(projectSymbolIds);
|
|
@@ -6405,7 +6518,7 @@ var Indexer = class {
|
|
|
6405
6518
|
if (!this.database || this.config.scope !== "global") {
|
|
6406
6519
|
return false;
|
|
6407
6520
|
}
|
|
6408
|
-
const projectHash = hashContent(
|
|
6521
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6409
6522
|
const roots = this.getScopedRoots();
|
|
6410
6523
|
const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots);
|
|
6411
6524
|
return this.database.getAllBranches().some(
|
|
@@ -6439,7 +6552,7 @@ var Indexer = class {
|
|
|
6439
6552
|
...Array.from(this.fileHashCache.keys()).filter((filePath) => this.isFileInCurrentScope(filePath, roots)),
|
|
6440
6553
|
...scopedEntries.map(({ metadata }) => metadata.filePath)
|
|
6441
6554
|
]);
|
|
6442
|
-
const projectRootPath =
|
|
6555
|
+
const projectRootPath = path11.resolve(this.projectRoot);
|
|
6443
6556
|
const projectLocalFilePaths = new Set(
|
|
6444
6557
|
Array.from(filePaths).filter((filePath) => isPathWithinRoot(filePath, projectRootPath))
|
|
6445
6558
|
);
|
|
@@ -6799,13 +6912,13 @@ var Indexer = class {
|
|
|
6799
6912
|
}
|
|
6800
6913
|
await fsPromises2.mkdir(this.indexPath, { recursive: true });
|
|
6801
6914
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
6802
|
-
const storePath =
|
|
6915
|
+
const storePath = path11.join(this.indexPath, "vectors");
|
|
6803
6916
|
this.store = new VectorStore(storePath, dimensions);
|
|
6804
|
-
const indexFilePath =
|
|
6917
|
+
const indexFilePath = path11.join(this.indexPath, "vectors.usearch");
|
|
6805
6918
|
if (existsSync6(indexFilePath)) {
|
|
6806
6919
|
this.store.load();
|
|
6807
6920
|
}
|
|
6808
|
-
const invertedIndexPath =
|
|
6921
|
+
const invertedIndexPath = path11.join(this.indexPath, "inverted-index.json");
|
|
6809
6922
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
6810
6923
|
try {
|
|
6811
6924
|
this.invertedIndex.load();
|
|
@@ -6815,7 +6928,7 @@ var Indexer = class {
|
|
|
6815
6928
|
}
|
|
6816
6929
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
6817
6930
|
}
|
|
6818
|
-
const dbPath =
|
|
6931
|
+
const dbPath = path11.join(this.indexPath, "codebase.db");
|
|
6819
6932
|
let dbIsNew = !existsSync6(dbPath);
|
|
6820
6933
|
try {
|
|
6821
6934
|
this.database = new Database(dbPath);
|
|
@@ -6896,7 +7009,7 @@ var Indexer = class {
|
|
|
6896
7009
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
6897
7010
|
return {
|
|
6898
7011
|
resetCorruptedIndex: true,
|
|
6899
|
-
warning: this.getCorruptedIndexWarning(
|
|
7012
|
+
warning: this.getCorruptedIndexWarning(path11.join(this.indexPath, "codebase.db"))
|
|
6900
7013
|
};
|
|
6901
7014
|
}
|
|
6902
7015
|
throw error;
|
|
@@ -6911,7 +7024,7 @@ var Indexer = class {
|
|
|
6911
7024
|
return;
|
|
6912
7025
|
}
|
|
6913
7026
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
6914
|
-
const storeBasePath =
|
|
7027
|
+
const storeBasePath = path11.join(this.indexPath, "vectors");
|
|
6915
7028
|
const storeIndexPath = `${storeBasePath}.usearch`;
|
|
6916
7029
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
6917
7030
|
const backupIndexPath = `${storeIndexPath}.bak`;
|
|
@@ -6996,7 +7109,7 @@ var Indexer = class {
|
|
|
6996
7109
|
if (!isSqliteCorruptionError(error)) {
|
|
6997
7110
|
return false;
|
|
6998
7111
|
}
|
|
6999
|
-
const dbPath =
|
|
7112
|
+
const dbPath = path11.join(this.indexPath, "codebase.db");
|
|
7000
7113
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
7001
7114
|
const errorMessage = getErrorMessage2(error);
|
|
7002
7115
|
if (this.config.scope === "global") {
|
|
@@ -7019,15 +7132,15 @@ var Indexer = class {
|
|
|
7019
7132
|
this.indexCompatibility = null;
|
|
7020
7133
|
this.fileHashCache.clear();
|
|
7021
7134
|
const resetPaths = [
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7135
|
+
path11.join(this.indexPath, "codebase.db"),
|
|
7136
|
+
path11.join(this.indexPath, "codebase.db-shm"),
|
|
7137
|
+
path11.join(this.indexPath, "codebase.db-wal"),
|
|
7138
|
+
path11.join(this.indexPath, "vectors.usearch"),
|
|
7139
|
+
path11.join(this.indexPath, "inverted-index.json"),
|
|
7140
|
+
path11.join(this.indexPath, "file-hashes.json"),
|
|
7141
|
+
path11.join(this.indexPath, "failed-batches.json"),
|
|
7142
|
+
path11.join(this.indexPath, "indexing.lock"),
|
|
7143
|
+
path11.join(this.indexPath, "vectors")
|
|
7031
7144
|
];
|
|
7032
7145
|
await Promise.all(resetPaths.map(async (targetPath) => {
|
|
7033
7146
|
try {
|
|
@@ -7264,6 +7377,7 @@ var Indexer = class {
|
|
|
7264
7377
|
this.logger.debug("Parsed changed files", { parsedCount: parsedFiles.length, parseMs: parseMs.toFixed(2) });
|
|
7265
7378
|
const existingChunks = /* @__PURE__ */ new Map();
|
|
7266
7379
|
const existingChunksByFile = /* @__PURE__ */ new Map();
|
|
7380
|
+
const existingMetadataById = /* @__PURE__ */ new Map();
|
|
7267
7381
|
for (const { key, metadata } of store.getAllMetadata()) {
|
|
7268
7382
|
if (scopedRoots && !this.isFileInCurrentScope(metadata.filePath, scopedRoots)) {
|
|
7269
7383
|
continue;
|
|
@@ -7272,6 +7386,7 @@ var Indexer = class {
|
|
|
7272
7386
|
continue;
|
|
7273
7387
|
}
|
|
7274
7388
|
existingChunks.set(key, metadata.hash);
|
|
7389
|
+
existingMetadataById.set(key, metadata);
|
|
7275
7390
|
const fileChunks = existingChunksByFile.get(metadata.filePath) || /* @__PURE__ */ new Set();
|
|
7276
7391
|
fileChunks.add(key);
|
|
7277
7392
|
existingChunksByFile.set(metadata.filePath, fileChunks);
|
|
@@ -7279,6 +7394,8 @@ var Indexer = class {
|
|
|
7279
7394
|
const currentChunkIds = /* @__PURE__ */ new Set();
|
|
7280
7395
|
const currentFilePaths = /* @__PURE__ */ new Set();
|
|
7281
7396
|
const pendingChunks = [];
|
|
7397
|
+
const gitBlameEnabled = this.config.indexing.gitBlame.enabled && isGitRepo(this.projectRoot);
|
|
7398
|
+
let backfilledBlameMetadata = false;
|
|
7282
7399
|
for (const filePath of unchangedFilePaths) {
|
|
7283
7400
|
currentFilePaths.add(filePath);
|
|
7284
7401
|
const fileChunks = existingChunksByFile.get(filePath);
|
|
@@ -7289,10 +7406,52 @@ var Indexer = class {
|
|
|
7289
7406
|
}
|
|
7290
7407
|
}
|
|
7291
7408
|
const chunkDataBatch = [];
|
|
7409
|
+
if (gitBlameEnabled) {
|
|
7410
|
+
const backfillItems = [];
|
|
7411
|
+
for (const chunkId of currentChunkIds) {
|
|
7412
|
+
const metadata = existingMetadataById.get(chunkId);
|
|
7413
|
+
if (!metadata || hasBlameMetadata(metadata)) {
|
|
7414
|
+
continue;
|
|
7415
|
+
}
|
|
7416
|
+
const chunk = database.getChunk(chunkId);
|
|
7417
|
+
if (!chunk) {
|
|
7418
|
+
continue;
|
|
7419
|
+
}
|
|
7420
|
+
const blame = await getChunkGitBlame(this.projectRoot, chunk.filePath, chunk.startLine, chunk.endLine);
|
|
7421
|
+
const blameMetadata = metadataFromBlame(blame);
|
|
7422
|
+
if (!blameMetadata.blameSha) {
|
|
7423
|
+
continue;
|
|
7424
|
+
}
|
|
7425
|
+
chunkDataBatch.push({
|
|
7426
|
+
...chunk,
|
|
7427
|
+
blameSha: blameMetadata.blameSha,
|
|
7428
|
+
blameAuthor: blameMetadata.blameAuthor,
|
|
7429
|
+
blameAuthorEmail: blameMetadata.blameAuthorEmail,
|
|
7430
|
+
blameCommittedAt: blameMetadata.blameCommittedAt,
|
|
7431
|
+
blameSummary: blameMetadata.blameSummary
|
|
7432
|
+
});
|
|
7433
|
+
const embeddingBuffer = database.getEmbedding(chunk.contentHash);
|
|
7434
|
+
if (!embeddingBuffer) {
|
|
7435
|
+
continue;
|
|
7436
|
+
}
|
|
7437
|
+
backfillItems.push({
|
|
7438
|
+
id: chunkId,
|
|
7439
|
+
vector: Array.from(bufferToFloat32Array(embeddingBuffer)),
|
|
7440
|
+
metadata: {
|
|
7441
|
+
...metadata,
|
|
7442
|
+
...blameMetadata
|
|
7443
|
+
}
|
|
7444
|
+
});
|
|
7445
|
+
}
|
|
7446
|
+
if (backfillItems.length > 0) {
|
|
7447
|
+
store.addBatch(backfillItems);
|
|
7448
|
+
backfilledBlameMetadata = true;
|
|
7449
|
+
}
|
|
7450
|
+
}
|
|
7292
7451
|
for (const parsed of parsedFiles) {
|
|
7293
7452
|
currentFilePaths.add(parsed.path);
|
|
7294
7453
|
if (parsed.chunks.length === 0) {
|
|
7295
|
-
const relativePath =
|
|
7454
|
+
const relativePath = path11.relative(this.projectRoot, parsed.path);
|
|
7296
7455
|
stats.parseFailures.push(relativePath);
|
|
7297
7456
|
}
|
|
7298
7457
|
let fileChunkCount = 0;
|
|
@@ -7313,6 +7472,10 @@ var Indexer = class {
|
|
|
7313
7472
|
}
|
|
7314
7473
|
const id = generateChunkId(parsed.path, chunk);
|
|
7315
7474
|
const contentHash = generateChunkHash(chunk);
|
|
7475
|
+
const existingContentHash = existingChunks.get(id);
|
|
7476
|
+
const existingChunk = gitBlameEnabled ? database.getChunk(id) : null;
|
|
7477
|
+
const blame = gitBlameEnabled && existingContentHash !== contentHash ? await getChunkGitBlame(this.projectRoot, parsed.path, chunk.startLine, chunk.endLine) : blameFromChunkData(existingChunk);
|
|
7478
|
+
const blameMetadata = metadataFromBlame(blame);
|
|
7316
7479
|
currentChunkIds.add(id);
|
|
7317
7480
|
chunkDataBatch.push({
|
|
7318
7481
|
chunkId: id,
|
|
@@ -7322,9 +7485,14 @@ var Indexer = class {
|
|
|
7322
7485
|
endLine: chunk.endLine,
|
|
7323
7486
|
nodeType: chunk.chunkType,
|
|
7324
7487
|
name: chunk.name,
|
|
7325
|
-
language: chunk.language
|
|
7488
|
+
language: chunk.language,
|
|
7489
|
+
blameSha: blameMetadata.blameSha,
|
|
7490
|
+
blameAuthor: blameMetadata.blameAuthor,
|
|
7491
|
+
blameAuthorEmail: blameMetadata.blameAuthorEmail,
|
|
7492
|
+
blameCommittedAt: blameMetadata.blameCommittedAt,
|
|
7493
|
+
blameSummary: blameMetadata.blameSummary
|
|
7326
7494
|
});
|
|
7327
|
-
if (
|
|
7495
|
+
if (existingContentHash === contentHash) {
|
|
7328
7496
|
fileChunkCount++;
|
|
7329
7497
|
continue;
|
|
7330
7498
|
}
|
|
@@ -7339,7 +7507,8 @@ var Indexer = class {
|
|
|
7339
7507
|
chunkType: chunk.chunkType,
|
|
7340
7508
|
name: chunk.name,
|
|
7341
7509
|
language: chunk.language,
|
|
7342
|
-
hash: contentHash
|
|
7510
|
+
hash: contentHash,
|
|
7511
|
+
...blameMetadata
|
|
7343
7512
|
};
|
|
7344
7513
|
pendingChunks.push({
|
|
7345
7514
|
id,
|
|
@@ -7482,6 +7651,9 @@ var Indexer = class {
|
|
|
7482
7651
|
database.addChunksToBranchBatch(branchCatalogKey, Array.from(currentChunkIds));
|
|
7483
7652
|
database.clearBranchSymbols(branchCatalogKey);
|
|
7484
7653
|
database.addSymbolsToBranchBatch(branchCatalogKey, Array.from(allSymbolIds));
|
|
7654
|
+
if (backfilledBlameMetadata) {
|
|
7655
|
+
store.save();
|
|
7656
|
+
}
|
|
7485
7657
|
if (scopedRoots) {
|
|
7486
7658
|
this.replaceScopedFileHashCache(currentFileHashes, scopedRoots);
|
|
7487
7659
|
this.clearScopedFailedBatches(scopedRoots);
|
|
@@ -8045,7 +8217,8 @@ var Indexer = class {
|
|
|
8045
8217
|
content,
|
|
8046
8218
|
score: r.score,
|
|
8047
8219
|
chunkType: r.metadata.chunkType,
|
|
8048
|
-
name: r.metadata.name
|
|
8220
|
+
name: r.metadata.name,
|
|
8221
|
+
blame: blameFromMetadata(r.metadata)
|
|
8049
8222
|
};
|
|
8050
8223
|
})
|
|
8051
8224
|
);
|
|
@@ -8137,12 +8310,12 @@ var Indexer = class {
|
|
|
8137
8310
|
this.indexCompatibility = compatibility;
|
|
8138
8311
|
return;
|
|
8139
8312
|
}
|
|
8140
|
-
const localProjectIndexPaths = [
|
|
8313
|
+
const localProjectIndexPaths = [path11.join(this.projectRoot, getHostProjectIndexRelativePath(this.host))];
|
|
8141
8314
|
if (this.host !== "opencode") {
|
|
8142
|
-
localProjectIndexPaths.push(
|
|
8315
|
+
localProjectIndexPaths.push(path11.join(this.projectRoot, getHostProjectIndexRelativePath("opencode")));
|
|
8143
8316
|
}
|
|
8144
8317
|
const isLocalProjectIndex = localProjectIndexPaths.some(
|
|
8145
|
-
(localPath) =>
|
|
8318
|
+
(localPath) => path11.resolve(this.indexPath) === path11.resolve(localPath)
|
|
8146
8319
|
);
|
|
8147
8320
|
if (!isLocalProjectIndex) {
|
|
8148
8321
|
throw new Error(
|
|
@@ -8232,7 +8405,7 @@ var Indexer = class {
|
|
|
8232
8405
|
gcOrphanSymbols: 0,
|
|
8233
8406
|
gcOrphanCallEdges: 0,
|
|
8234
8407
|
resetCorruptedIndex: true,
|
|
8235
|
-
warning: this.getCorruptedIndexWarning(
|
|
8408
|
+
warning: this.getCorruptedIndexWarning(path11.join(this.indexPath, "codebase.db"))
|
|
8236
8409
|
};
|
|
8237
8410
|
}
|
|
8238
8411
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -8552,7 +8725,8 @@ var Indexer = class {
|
|
|
8552
8725
|
content,
|
|
8553
8726
|
score: r.score,
|
|
8554
8727
|
chunkType: r.metadata.chunkType,
|
|
8555
|
-
name: r.metadata.name
|
|
8728
|
+
name: r.metadata.name,
|
|
8729
|
+
blame: blameFromMetadata(r.metadata)
|
|
8556
8730
|
};
|
|
8557
8731
|
})
|
|
8558
8732
|
);
|
|
@@ -8589,9 +8763,9 @@ var Indexer = class {
|
|
|
8589
8763
|
const { database } = await this.ensureInitialized();
|
|
8590
8764
|
let shortest = [];
|
|
8591
8765
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
8592
|
-
const
|
|
8593
|
-
if (
|
|
8594
|
-
shortest =
|
|
8766
|
+
const path26 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
8767
|
+
if (path26.length > 0 && (shortest.length === 0 || path26.length < shortest.length)) {
|
|
8768
|
+
shortest = path26;
|
|
8595
8769
|
}
|
|
8596
8770
|
}
|
|
8597
8771
|
return shortest;
|
|
@@ -8623,7 +8797,7 @@ var Indexer = class {
|
|
|
8623
8797
|
}
|
|
8624
8798
|
async getPrImpact(opts) {
|
|
8625
8799
|
const { database } = await this.ensureInitialized();
|
|
8626
|
-
const
|
|
8800
|
+
const execFileAsync3 = promisify3(execFile3);
|
|
8627
8801
|
const changedFilesResult = await getChangedFiles({
|
|
8628
8802
|
pr: opts.pr,
|
|
8629
8803
|
branch: opts.branch,
|
|
@@ -8645,7 +8819,7 @@ var Indexer = class {
|
|
|
8645
8819
|
"Run index_codebase first to build the call graph and symbol index for this branch."
|
|
8646
8820
|
);
|
|
8647
8821
|
}
|
|
8648
|
-
const absoluteChangedFiles = changedFiles.map((f) =>
|
|
8822
|
+
const absoluteChangedFiles = changedFiles.map((f) => path11.resolve(this.projectRoot, f));
|
|
8649
8823
|
const directSymbols = database.getSymbolsForFiles(absoluteChangedFiles, branchKey);
|
|
8650
8824
|
const directIds = directSymbols.map((s) => s.id);
|
|
8651
8825
|
const direction = opts.direction ?? "both";
|
|
@@ -8707,7 +8881,7 @@ var Indexer = class {
|
|
|
8707
8881
|
if (opts.checkConflicts) {
|
|
8708
8882
|
conflictingPRs = [];
|
|
8709
8883
|
try {
|
|
8710
|
-
const { stdout } = await
|
|
8884
|
+
const { stdout } = await execFileAsync3(
|
|
8711
8885
|
"gh",
|
|
8712
8886
|
["pr", "list", "--state", "open", "--json", "number,headRefName", "--limit", "10000"],
|
|
8713
8887
|
{ cwd: this.projectRoot, timeout: 3e4 }
|
|
@@ -8728,7 +8902,7 @@ var Indexer = class {
|
|
|
8728
8902
|
projectRoot: this.projectRoot,
|
|
8729
8903
|
baseBranch: this.baseBranch
|
|
8730
8904
|
});
|
|
8731
|
-
const otherAbsolute = otherChanged.files.map((f) =>
|
|
8905
|
+
const otherAbsolute = otherChanged.files.map((f) => path11.resolve(this.projectRoot, f));
|
|
8732
8906
|
const otherBranchKey = this.getBranchCatalogKeyFor(openPr.headRefName);
|
|
8733
8907
|
const otherSymbols = database.getSymbolsForFiles(otherAbsolute, otherBranchKey);
|
|
8734
8908
|
const otherLabels = /* @__PURE__ */ new Set();
|
|
@@ -8791,12 +8965,12 @@ var Indexer = class {
|
|
|
8791
8965
|
if (meta.filePath) filePaths.add(meta.filePath);
|
|
8792
8966
|
}
|
|
8793
8967
|
const directory = options?.directory?.replace(/\/$/, "");
|
|
8794
|
-
const absoluteDirectoryFilter = directory ?
|
|
8968
|
+
const absoluteDirectoryFilter = directory ? path11.resolve(this.projectRoot, directory) : void 0;
|
|
8795
8969
|
for (const filePath of filePaths) {
|
|
8796
8970
|
if (directory) {
|
|
8797
|
-
const absoluteFilePath =
|
|
8971
|
+
const absoluteFilePath = path11.resolve(filePath);
|
|
8798
8972
|
const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
|
|
8799
|
-
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter +
|
|
8973
|
+
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path11.sep));
|
|
8800
8974
|
if (!matchesRelative && !matchesProjectRelative) {
|
|
8801
8975
|
continue;
|
|
8802
8976
|
}
|
|
@@ -9076,13 +9250,13 @@ function computeEvalMetrics(queries, perQuery, embeddingCallCount, embeddingToke
|
|
|
9076
9250
|
// src/eval/runner-config.ts
|
|
9077
9251
|
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
9078
9252
|
import * as os4 from "os";
|
|
9079
|
-
import * as
|
|
9253
|
+
import * as path13 from "path";
|
|
9080
9254
|
|
|
9081
9255
|
// src/config/rebase.ts
|
|
9082
|
-
import * as
|
|
9256
|
+
import * as path12 from "path";
|
|
9083
9257
|
function isWithinRoot(rootDir, targetPath) {
|
|
9084
|
-
const relativePath =
|
|
9085
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
9258
|
+
const relativePath = path12.relative(rootDir, targetPath);
|
|
9259
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path12.isAbsolute(relativePath);
|
|
9086
9260
|
}
|
|
9087
9261
|
function rebasePathEntries(values, fromDir, toDir) {
|
|
9088
9262
|
if (!Array.isArray(values)) {
|
|
@@ -9090,10 +9264,10 @@ function rebasePathEntries(values, fromDir, toDir) {
|
|
|
9090
9264
|
}
|
|
9091
9265
|
return values.filter((value) => typeof value === "string").map((value) => {
|
|
9092
9266
|
const trimmed = value.trim();
|
|
9093
|
-
if (!trimmed ||
|
|
9267
|
+
if (!trimmed || path12.isAbsolute(trimmed)) {
|
|
9094
9268
|
return trimmed;
|
|
9095
9269
|
}
|
|
9096
|
-
return normalizePathSeparators(
|
|
9270
|
+
return normalizePathSeparators(path12.normalize(path12.relative(toDir, path12.resolve(fromDir, trimmed))));
|
|
9097
9271
|
}).filter(Boolean);
|
|
9098
9272
|
}
|
|
9099
9273
|
function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
@@ -9105,17 +9279,17 @@ function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
|
9105
9279
|
if (!trimmed) {
|
|
9106
9280
|
return trimmed;
|
|
9107
9281
|
}
|
|
9108
|
-
if (
|
|
9282
|
+
if (path12.isAbsolute(trimmed)) {
|
|
9109
9283
|
if (isWithinRoot(sourceRoot, trimmed)) {
|
|
9110
|
-
return normalizePathSeparators(
|
|
9284
|
+
return normalizePathSeparators(path12.normalize(path12.relative(sourceRoot, trimmed) || "."));
|
|
9111
9285
|
}
|
|
9112
|
-
return
|
|
9286
|
+
return path12.normalize(trimmed);
|
|
9113
9287
|
}
|
|
9114
|
-
const resolvedFromSource =
|
|
9288
|
+
const resolvedFromSource = path12.resolve(sourceRoot, trimmed);
|
|
9115
9289
|
if (isWithinRoot(sourceRoot, resolvedFromSource)) {
|
|
9116
|
-
return normalizePathSeparators(
|
|
9290
|
+
return normalizePathSeparators(path12.normalize(trimmed));
|
|
9117
9291
|
}
|
|
9118
|
-
return normalizePathSeparators(
|
|
9292
|
+
return normalizePathSeparators(path12.normalize(path12.relative(targetRoot, resolvedFromSource)));
|
|
9119
9293
|
}).filter(Boolean);
|
|
9120
9294
|
}
|
|
9121
9295
|
|
|
@@ -9163,20 +9337,20 @@ function parseJsonConfigFile(filePath) {
|
|
|
9163
9337
|
}
|
|
9164
9338
|
}
|
|
9165
9339
|
function toAbsolute(projectRoot, maybeRelative) {
|
|
9166
|
-
return
|
|
9340
|
+
return path13.isAbsolute(maybeRelative) ? maybeRelative : path13.join(projectRoot, maybeRelative);
|
|
9167
9341
|
}
|
|
9168
9342
|
function isProjectScopedConfigPath(configPath) {
|
|
9169
|
-
return
|
|
9343
|
+
return path13.basename(configPath) === "codebase-index.json" && path13.basename(path13.dirname(configPath)) === ".opencode";
|
|
9170
9344
|
}
|
|
9171
9345
|
function normalizeEvalConfigKnowledgeBases(rawConfig, projectRoot, resolvedConfigPath) {
|
|
9172
9346
|
const config = rawConfig && typeof rawConfig === "object" ? { ...rawConfig } : {};
|
|
9173
9347
|
const rebaseEntries = (values) => isProjectScopedConfigPath(resolvedConfigPath) ? resolveInheritedKnowledgeBaseEntries(
|
|
9174
9348
|
values,
|
|
9175
|
-
|
|
9349
|
+
path13.dirname(path13.dirname(resolvedConfigPath)),
|
|
9176
9350
|
projectRoot
|
|
9177
9351
|
) : rebasePathEntries(
|
|
9178
9352
|
values,
|
|
9179
|
-
|
|
9353
|
+
path13.dirname(resolvedConfigPath),
|
|
9180
9354
|
projectRoot
|
|
9181
9355
|
);
|
|
9182
9356
|
if (Array.isArray(config.knowledgeBases)) {
|
|
@@ -9204,7 +9378,7 @@ function loadRawConfig(projectRoot, configPath) {
|
|
|
9204
9378
|
projectConfig
|
|
9205
9379
|
);
|
|
9206
9380
|
}
|
|
9207
|
-
const globalConfig =
|
|
9381
|
+
const globalConfig = path13.join(os4.homedir(), ".config", "opencode", "codebase-index.json");
|
|
9208
9382
|
if (existsSync7(globalConfig)) {
|
|
9209
9383
|
return parseJsonConfigFile(globalConfig);
|
|
9210
9384
|
}
|
|
@@ -9214,10 +9388,10 @@ function getIndexRootPath(projectRoot, scope) {
|
|
|
9214
9388
|
return scope === "global" ? getGlobalIndexPath() : resolveProjectIndexPath(projectRoot, scope);
|
|
9215
9389
|
}
|
|
9216
9390
|
function getLocalProjectIndexRoot(projectRoot) {
|
|
9217
|
-
return
|
|
9391
|
+
return path13.join(projectRoot, ".opencode", "index");
|
|
9218
9392
|
}
|
|
9219
9393
|
function getLocalProjectConfigPath(projectRoot) {
|
|
9220
|
-
return
|
|
9394
|
+
return path13.join(projectRoot, ".opencode", "codebase-index.json");
|
|
9221
9395
|
}
|
|
9222
9396
|
function clearIndexRoot(projectRoot, scope) {
|
|
9223
9397
|
const indexRoot = scope === "global" ? getIndexRootPath(projectRoot, scope) : getLocalProjectIndexRoot(projectRoot);
|
|
@@ -9239,7 +9413,7 @@ function ensureLocalEvalProjectConfig(projectRoot, configPath) {
|
|
|
9239
9413
|
projectRoot,
|
|
9240
9414
|
resolvedConfigPath
|
|
9241
9415
|
);
|
|
9242
|
-
mkdirSync3(
|
|
9416
|
+
mkdirSync3(path13.dirname(localConfigPath), { recursive: true });
|
|
9243
9417
|
writeFileSync3(localConfigPath, JSON.stringify(sourceConfig, null, 2), "utf-8");
|
|
9244
9418
|
return localConfigPath;
|
|
9245
9419
|
}
|
|
@@ -9289,23 +9463,23 @@ function isRecord2(value) {
|
|
|
9289
9463
|
function isStringArray3(value) {
|
|
9290
9464
|
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
9291
9465
|
}
|
|
9292
|
-
function asPositiveNumber(value,
|
|
9466
|
+
function asPositiveNumber(value, path26) {
|
|
9293
9467
|
if (typeof value !== "number" || Number.isNaN(value) || value < 0) {
|
|
9294
|
-
throw new Error(`${
|
|
9468
|
+
throw new Error(`${path26} must be a non-negative number`);
|
|
9295
9469
|
}
|
|
9296
9470
|
return value;
|
|
9297
9471
|
}
|
|
9298
|
-
function parseQueryType(value,
|
|
9472
|
+
function parseQueryType(value, path26) {
|
|
9299
9473
|
if (value === "definition" || value === "implementation-intent" || value === "similarity" || value === "keyword-heavy") {
|
|
9300
9474
|
return value;
|
|
9301
9475
|
}
|
|
9302
9476
|
throw new Error(
|
|
9303
|
-
`${
|
|
9477
|
+
`${path26} must be one of: definition, implementation-intent, similarity, keyword-heavy`
|
|
9304
9478
|
);
|
|
9305
9479
|
}
|
|
9306
|
-
function parseExpected(input,
|
|
9480
|
+
function parseExpected(input, path26) {
|
|
9307
9481
|
if (!isRecord2(input)) {
|
|
9308
|
-
throw new Error(`${
|
|
9482
|
+
throw new Error(`${path26} must be an object`);
|
|
9309
9483
|
}
|
|
9310
9484
|
const filePathRaw = input.filePath;
|
|
9311
9485
|
const acceptableFilesRaw = input.acceptableFiles;
|
|
@@ -9314,16 +9488,16 @@ function parseExpected(input, path25) {
|
|
|
9314
9488
|
const filePath = typeof filePathRaw === "string" ? filePathRaw : void 0;
|
|
9315
9489
|
const acceptableFiles = isStringArray3(acceptableFilesRaw) ? acceptableFilesRaw : void 0;
|
|
9316
9490
|
if (!filePath && (!acceptableFiles || acceptableFiles.length === 0)) {
|
|
9317
|
-
throw new Error(`${
|
|
9491
|
+
throw new Error(`${path26} must include either expected.filePath or expected.acceptableFiles`);
|
|
9318
9492
|
}
|
|
9319
9493
|
if (acceptableFilesRaw !== void 0 && !isStringArray3(acceptableFilesRaw)) {
|
|
9320
|
-
throw new Error(`${
|
|
9494
|
+
throw new Error(`${path26}.acceptableFiles must be an array of strings`);
|
|
9321
9495
|
}
|
|
9322
9496
|
if (symbolRaw !== void 0 && typeof symbolRaw !== "string") {
|
|
9323
|
-
throw new Error(`${
|
|
9497
|
+
throw new Error(`${path26}.symbol must be a string when provided`);
|
|
9324
9498
|
}
|
|
9325
9499
|
if (branchRaw !== void 0 && typeof branchRaw !== "string") {
|
|
9326
|
-
throw new Error(`${
|
|
9500
|
+
throw new Error(`${path26}.branch must be a string when provided`);
|
|
9327
9501
|
}
|
|
9328
9502
|
return {
|
|
9329
9503
|
filePath,
|
|
@@ -9333,25 +9507,25 @@ function parseExpected(input, path25) {
|
|
|
9333
9507
|
};
|
|
9334
9508
|
}
|
|
9335
9509
|
function parseQuery(input, index) {
|
|
9336
|
-
const
|
|
9510
|
+
const path26 = `queries[${index}]`;
|
|
9337
9511
|
if (!isRecord2(input)) {
|
|
9338
|
-
throw new Error(`${
|
|
9512
|
+
throw new Error(`${path26} must be an object`);
|
|
9339
9513
|
}
|
|
9340
9514
|
const id = input.id;
|
|
9341
9515
|
const query = input.query;
|
|
9342
9516
|
const queryType = input.queryType;
|
|
9343
9517
|
const expected = input.expected;
|
|
9344
9518
|
if (typeof id !== "string" || id.trim().length === 0) {
|
|
9345
|
-
throw new Error(`${
|
|
9519
|
+
throw new Error(`${path26}.id must be a non-empty string`);
|
|
9346
9520
|
}
|
|
9347
9521
|
if (typeof query !== "string" || query.trim().length === 0) {
|
|
9348
|
-
throw new Error(`${
|
|
9522
|
+
throw new Error(`${path26}.query must be a non-empty string`);
|
|
9349
9523
|
}
|
|
9350
9524
|
return {
|
|
9351
9525
|
id,
|
|
9352
9526
|
query,
|
|
9353
|
-
queryType: parseQueryType(queryType, `${
|
|
9354
|
-
expected: parseExpected(expected, `${
|
|
9527
|
+
queryType: parseQueryType(queryType, `${path26}.queryType`),
|
|
9528
|
+
expected: parseExpected(expected, `${path26}.expected`)
|
|
9355
9529
|
};
|
|
9356
9530
|
}
|
|
9357
9531
|
function parseGoldenDataset(raw, sourceLabel) {
|
|
@@ -9534,13 +9708,13 @@ async function runEvaluation(options) {
|
|
|
9534
9708
|
};
|
|
9535
9709
|
const outputDir = createRunDirectory(toAbsolute(options.projectRoot, options.outputRoot));
|
|
9536
9710
|
const perQueryArtifact = buildPerQueryArtifact(perQuery);
|
|
9537
|
-
writeJson(
|
|
9538
|
-
writeJson(
|
|
9711
|
+
writeJson(path14.join(outputDir, "summary.json"), summary);
|
|
9712
|
+
writeJson(path14.join(outputDir, "per-query.json"), perQueryArtifact);
|
|
9539
9713
|
let comparison;
|
|
9540
9714
|
if (againstPath) {
|
|
9541
9715
|
const baseline = loadSummary(againstPath);
|
|
9542
9716
|
comparison = compareSummaries(summary, baseline, againstPath);
|
|
9543
|
-
writeJson(
|
|
9717
|
+
writeJson(path14.join(outputDir, "compare.json"), comparison);
|
|
9544
9718
|
}
|
|
9545
9719
|
let gate;
|
|
9546
9720
|
if (options.ciMode) {
|
|
@@ -9553,7 +9727,7 @@ async function runEvaluation(options) {
|
|
|
9553
9727
|
if (existsSync8(resolvedBaseline)) {
|
|
9554
9728
|
const baselineSummary = loadSummary(resolvedBaseline);
|
|
9555
9729
|
comparison = compareSummaries(summary, baselineSummary, resolvedBaseline);
|
|
9556
|
-
writeJson(
|
|
9730
|
+
writeJson(path14.join(outputDir, "compare.json"), comparison);
|
|
9557
9731
|
} else if (budget.failOnMissingBaseline) {
|
|
9558
9732
|
throw new Error(
|
|
9559
9733
|
`Budget baseline is missing: ${resolvedBaseline}. Set failOnMissingBaseline=false to allow CI run without baseline.`
|
|
@@ -9563,7 +9737,7 @@ async function runEvaluation(options) {
|
|
|
9563
9737
|
gate = evaluateBudgetGate(budget, summary, comparison);
|
|
9564
9738
|
}
|
|
9565
9739
|
const markdown = createSummaryMarkdown(summary, comparison, gate);
|
|
9566
|
-
writeText(
|
|
9740
|
+
writeText(path14.join(outputDir, "summary.md"), markdown);
|
|
9567
9741
|
return { outputDir, summary, perQuery, comparison, gate };
|
|
9568
9742
|
} finally {
|
|
9569
9743
|
await indexer.close();
|
|
@@ -9621,23 +9795,23 @@ async function runSweep(options, sweep) {
|
|
|
9621
9795
|
bestByMrrAt10,
|
|
9622
9796
|
bestByP95Latency
|
|
9623
9797
|
};
|
|
9624
|
-
writeJson(
|
|
9798
|
+
writeJson(path14.join(outputDir, "compare.json"), aggregate);
|
|
9625
9799
|
const md = createSummaryMarkdown(
|
|
9626
9800
|
bestByHitAt5?.summary ?? runs[0].summary,
|
|
9627
9801
|
bestByHitAt5?.comparison,
|
|
9628
9802
|
void 0,
|
|
9629
9803
|
aggregate
|
|
9630
9804
|
);
|
|
9631
|
-
writeText(
|
|
9632
|
-
writeJson(
|
|
9805
|
+
writeText(path14.join(outputDir, "summary.md"), md);
|
|
9806
|
+
writeJson(path14.join(outputDir, "summary.json"), bestByHitAt5?.summary ?? runs[0].summary);
|
|
9633
9807
|
return { outputDir, aggregate };
|
|
9634
9808
|
}
|
|
9635
9809
|
|
|
9636
9810
|
// src/eval/cli.ts
|
|
9637
|
-
import * as
|
|
9811
|
+
import * as path16 from "path";
|
|
9638
9812
|
|
|
9639
9813
|
// src/eval/cli-parser.ts
|
|
9640
|
-
import * as
|
|
9814
|
+
import * as path15 from "path";
|
|
9641
9815
|
function printUsage() {
|
|
9642
9816
|
console.log(`
|
|
9643
9817
|
Usage:
|
|
@@ -9709,12 +9883,12 @@ function parseEvalArgs(argv, cwd) {
|
|
|
9709
9883
|
const arg = argv[i];
|
|
9710
9884
|
const next = argv[i + 1];
|
|
9711
9885
|
if (arg === "--project" && next) {
|
|
9712
|
-
parsed.projectRoot =
|
|
9886
|
+
parsed.projectRoot = path15.resolve(cwd, next);
|
|
9713
9887
|
i += 1;
|
|
9714
9888
|
continue;
|
|
9715
9889
|
}
|
|
9716
9890
|
if (arg === "--config" && next) {
|
|
9717
|
-
parsed.configPath =
|
|
9891
|
+
parsed.configPath = path15.resolve(cwd, next);
|
|
9718
9892
|
i += 1;
|
|
9719
9893
|
continue;
|
|
9720
9894
|
}
|
|
@@ -9910,22 +10084,22 @@ async function handleEvalCommand(args, cwd) {
|
|
|
9910
10084
|
if (!parsed.againstPath.endsWith(".json")) {
|
|
9911
10085
|
throw new Error("eval diff --against must point to a summary JSON file");
|
|
9912
10086
|
}
|
|
9913
|
-
const currentSummary = loadSummary(
|
|
10087
|
+
const currentSummary = loadSummary(path16.resolve(parsed.projectRoot, currentPath), {
|
|
9914
10088
|
allowLegacyDiversityMetrics: true
|
|
9915
10089
|
});
|
|
9916
|
-
const baselineSummary = loadSummary(
|
|
10090
|
+
const baselineSummary = loadSummary(path16.resolve(parsed.projectRoot, parsed.againstPath), {
|
|
9917
10091
|
allowLegacyDiversityMetrics: true
|
|
9918
10092
|
});
|
|
9919
10093
|
const comparison = compareSummaries(
|
|
9920
10094
|
currentSummary,
|
|
9921
10095
|
baselineSummary,
|
|
9922
|
-
|
|
10096
|
+
path16.resolve(parsed.projectRoot, parsed.againstPath)
|
|
9923
10097
|
);
|
|
9924
|
-
const outputDir = createRunDirectory(
|
|
10098
|
+
const outputDir = createRunDirectory(path16.resolve(parsed.projectRoot, parsed.outputRoot));
|
|
9925
10099
|
const summaryMd = createSummaryMarkdown(currentSummary, comparison);
|
|
9926
|
-
writeJson(
|
|
9927
|
-
writeText(
|
|
9928
|
-
writeJson(
|
|
10100
|
+
writeJson(path16.join(outputDir, "compare.json"), comparison);
|
|
10101
|
+
writeText(path16.join(outputDir, "summary.md"), summaryMd);
|
|
10102
|
+
writeJson(path16.join(outputDir, "summary.json"), currentSummary);
|
|
9929
10103
|
console.log(`Eval diff complete. Artifacts: ${outputDir}`);
|
|
9930
10104
|
return 0;
|
|
9931
10105
|
}
|
|
@@ -10170,6 +10344,17 @@ function calculatePercentage(progress) {
|
|
|
10170
10344
|
if (progress.phase === "storing") return 95;
|
|
10171
10345
|
return 0;
|
|
10172
10346
|
}
|
|
10347
|
+
function formatCodebasePeek(results) {
|
|
10348
|
+
if (results.length === 0) {
|
|
10349
|
+
return "No matching code found. Try a different query or run index_codebase first.";
|
|
10350
|
+
}
|
|
10351
|
+
const formatted = results.map((r, idx) => {
|
|
10352
|
+
const location = `${r.filePath}:${r.startLine}-${r.endLine}`;
|
|
10353
|
+
const name = r.name ? `"${r.name}"` : "(anonymous)";
|
|
10354
|
+
return `[${idx + 1}] ${r.chunkType} ${name} at ${location} (score: ${r.score.toFixed(2)})${formatBlame(r)}`;
|
|
10355
|
+
});
|
|
10356
|
+
return formatted.join("\n");
|
|
10357
|
+
}
|
|
10173
10358
|
function formatHealthCheck(result) {
|
|
10174
10359
|
if (result.resetCorruptedIndex) {
|
|
10175
10360
|
return result.warning ?? "Detected a corrupted local index and reset it. Run index_codebase to rebuild search data.";
|
|
@@ -10198,16 +10383,68 @@ function formatHealthCheck(result) {
|
|
|
10198
10383
|
}
|
|
10199
10384
|
return lines.join("\n");
|
|
10200
10385
|
}
|
|
10386
|
+
function formatCallGraphCallers(name, callers, relationshipType) {
|
|
10387
|
+
if (callers.length === 0) {
|
|
10388
|
+
return `No callers found for "${name}"${relationshipType ? ` with type ${relationshipType}` : ""}. It may not be called by any tracked function, or the index needs updating.`;
|
|
10389
|
+
}
|
|
10390
|
+
const formatted = callers.map((edge, index) => {
|
|
10391
|
+
const confidence = edge.confidence !== "Direct" ? ` [${edge.confidence.toLowerCase()}]` : "";
|
|
10392
|
+
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]"}`;
|
|
10393
|
+
});
|
|
10394
|
+
return `"${name}" is called by ${callers.length} function(s):
|
|
10395
|
+
|
|
10396
|
+
${formatted.join("\n")}`;
|
|
10397
|
+
}
|
|
10398
|
+
function formatCallGraphCallees(symbolId, callees, relationshipType) {
|
|
10399
|
+
if (callees.length === 0) {
|
|
10400
|
+
return `No callees found for symbol ${symbolId}${relationshipType ? ` with type ${relationshipType}` : ""}. The function may not call any other tracked functions.`;
|
|
10401
|
+
}
|
|
10402
|
+
return callees.map((edge, index) => {
|
|
10403
|
+
const confidence = edge.confidence !== "Direct" ? ` [${edge.confidence.toLowerCase()}]` : "";
|
|
10404
|
+
return `[${index + 1}] \u2192 ${edge.targetName} (${edge.callType})${confidence} at line ${edge.line}${edge.isResolved ? ` [resolved: ${edge.toSymbolId}]` : " [unresolved]"}`;
|
|
10405
|
+
}).join("\n");
|
|
10406
|
+
}
|
|
10407
|
+
function formatCallGraphPath(from, to, path26) {
|
|
10408
|
+
if (path26.length === 0) {
|
|
10409
|
+
return `No path found between "${from}" and "${to}". They may be in disconnected components, or the call graph index needs updating.`;
|
|
10410
|
+
}
|
|
10411
|
+
const formatted = path26.map((hop, index) => {
|
|
10412
|
+
const prefix = index === 0 ? "[start]" : `--${hop.callType}-->`;
|
|
10413
|
+
const location = hop.filePath ? ` (${hop.filePath}:${hop.line})` : "";
|
|
10414
|
+
return `${prefix} ${hop.symbolName}${location}`;
|
|
10415
|
+
});
|
|
10416
|
+
return `Path (${path26.length} hops):
|
|
10417
|
+
${formatted.join("\n")}`;
|
|
10418
|
+
}
|
|
10201
10419
|
function formatResultHeader(result, index) {
|
|
10202
10420
|
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}`;
|
|
10203
10421
|
}
|
|
10422
|
+
function formatBlame(result) {
|
|
10423
|
+
if (!result.blame) {
|
|
10424
|
+
return "";
|
|
10425
|
+
}
|
|
10426
|
+
const date = new Date(result.blame.committedAt * 1e3).toISOString().slice(0, 10);
|
|
10427
|
+
return `
|
|
10428
|
+
${result.blame.sha.slice(0, 7)} | ${result.blame.author} | ${date} | ${result.blame.summary}`;
|
|
10429
|
+
}
|
|
10204
10430
|
function formatDefinitionLookup(results, query) {
|
|
10205
10431
|
if (results.length === 0) {
|
|
10206
10432
|
return `No definition found for "${query}". Try codebase_search for broader discovery, or verify the symbol name.`;
|
|
10207
10433
|
}
|
|
10208
10434
|
const formatted = results.map((r, idx) => {
|
|
10209
10435
|
const header = formatResultHeader(r, idx);
|
|
10210
|
-
return `${header} (score: ${r.score.toFixed(2)})
|
|
10436
|
+
return `${header} (score: ${r.score.toFixed(2)})${formatBlame(r)}
|
|
10437
|
+
\`\`\`
|
|
10438
|
+
${truncateContent(r.content)}
|
|
10439
|
+
\`\`\``;
|
|
10440
|
+
});
|
|
10441
|
+
return formatted.join("\n\n");
|
|
10442
|
+
}
|
|
10443
|
+
function formatSearchResults(results, scoreFormat = "similarity") {
|
|
10444
|
+
const formatted = results.map((r, idx) => {
|
|
10445
|
+
const header = formatResultHeader(r, idx);
|
|
10446
|
+
const scoreLabel = scoreFormat === "similarity" ? `(similarity: ${(r.score * 100).toFixed(1)}%)` : `(score: ${r.score.toFixed(2)})`;
|
|
10447
|
+
return `${header} ${scoreLabel}${formatBlame(r)}
|
|
10211
10448
|
\`\`\`
|
|
10212
10449
|
${truncateContent(r.content)}
|
|
10213
10450
|
\`\`\``;
|
|
@@ -10268,11 +10505,11 @@ function formatPrImpact(result) {
|
|
|
10268
10505
|
|
|
10269
10506
|
// src/tools/operations.ts
|
|
10270
10507
|
import { existsSync as existsSync11, realpathSync, statSync as statSync3 } from "fs";
|
|
10271
|
-
import * as
|
|
10508
|
+
import * as path20 from "path";
|
|
10272
10509
|
|
|
10273
10510
|
// src/config/merger.ts
|
|
10274
10511
|
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
|
|
10275
|
-
import * as
|
|
10512
|
+
import * as path17 from "path";
|
|
10276
10513
|
var PROJECT_OVERRIDE_KEYS = [
|
|
10277
10514
|
"embeddingProvider",
|
|
10278
10515
|
"customProvider",
|
|
@@ -10305,8 +10542,8 @@ function mergeUniqueStringArray(values) {
|
|
|
10305
10542
|
return [...new Set(values.map((value) => String(value).trim()))];
|
|
10306
10543
|
}
|
|
10307
10544
|
function normalizeKnowledgeBasePath(value) {
|
|
10308
|
-
let normalized =
|
|
10309
|
-
const root =
|
|
10545
|
+
let normalized = path17.normalize(String(value).trim());
|
|
10546
|
+
const root = path17.parse(normalized).root;
|
|
10310
10547
|
while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
|
|
10311
10548
|
normalized = normalized.slice(0, -1);
|
|
10312
10549
|
}
|
|
@@ -10359,7 +10596,7 @@ function loadConfigFile(filePath) {
|
|
|
10359
10596
|
}
|
|
10360
10597
|
function materializeLocalProjectConfig(projectRoot, config, host = "opencode") {
|
|
10361
10598
|
const localConfigPath = resolveWritableProjectConfigPath(projectRoot, host);
|
|
10362
|
-
mkdirSync4(
|
|
10599
|
+
mkdirSync4(path17.dirname(localConfigPath), { recursive: true });
|
|
10363
10600
|
writeFileSync4(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
10364
10601
|
return localConfigPath;
|
|
10365
10602
|
}
|
|
@@ -10370,7 +10607,7 @@ function loadProjectConfigLayer(projectRoot, host = "opencode") {
|
|
|
10370
10607
|
return {};
|
|
10371
10608
|
}
|
|
10372
10609
|
const normalizedConfig = { ...projectConfig };
|
|
10373
|
-
const projectConfigBaseDir =
|
|
10610
|
+
const projectConfigBaseDir = path17.dirname(path17.dirname(projectConfigPath));
|
|
10374
10611
|
if (Array.isArray(normalizedConfig.knowledgeBases)) {
|
|
10375
10612
|
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
10376
10613
|
normalizedConfig.knowledgeBases,
|
|
@@ -10434,19 +10671,19 @@ function loadMergedConfig(projectRoot, host = "opencode") {
|
|
|
10434
10671
|
}
|
|
10435
10672
|
|
|
10436
10673
|
// src/tools/knowledge-base-paths.ts
|
|
10437
|
-
import * as
|
|
10674
|
+
import * as path18 from "path";
|
|
10438
10675
|
function resolveConfigPathValue(value, baseDir) {
|
|
10439
10676
|
const trimmed = value.trim();
|
|
10440
10677
|
if (!trimmed) {
|
|
10441
10678
|
return trimmed;
|
|
10442
10679
|
}
|
|
10443
|
-
const absolutePath =
|
|
10444
|
-
return
|
|
10680
|
+
const absolutePath = path18.isAbsolute(trimmed) ? trimmed : path18.resolve(baseDir, trimmed);
|
|
10681
|
+
return path18.normalize(absolutePath);
|
|
10445
10682
|
}
|
|
10446
10683
|
|
|
10447
10684
|
// src/tools/config-state.ts
|
|
10448
10685
|
import { existsSync as existsSync10, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
10449
|
-
import * as
|
|
10686
|
+
import * as path19 from "path";
|
|
10450
10687
|
function normalizeKnowledgeBasePaths(config, projectRoot) {
|
|
10451
10688
|
const normalized = { ...config };
|
|
10452
10689
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
@@ -10514,7 +10751,7 @@ function refreshIndexerForDirectory(projectRoot, host = "opencode", config = par
|
|
|
10514
10751
|
}
|
|
10515
10752
|
function shouldForceLocalizeProjectIndex(projectRoot, host = "opencode") {
|
|
10516
10753
|
const root = getProjectRoot(projectRoot, host);
|
|
10517
|
-
const localIndexPath =
|
|
10754
|
+
const localIndexPath = path20.join(root, getHostProjectIndexRelativePath(host));
|
|
10518
10755
|
if (existsSync11(localIndexPath)) {
|
|
10519
10756
|
return false;
|
|
10520
10757
|
}
|
|
@@ -10529,7 +10766,10 @@ async function searchCodebase(projectRoot, host, query, options = {}) {
|
|
|
10529
10766
|
chunkType: options.chunkType,
|
|
10530
10767
|
contextLines: options.contextLines,
|
|
10531
10768
|
metadataOnly: options.metadataOnly,
|
|
10532
|
-
definitionIntent: options.definitionIntent
|
|
10769
|
+
definitionIntent: options.definitionIntent,
|
|
10770
|
+
blameAuthor: options.blameAuthor,
|
|
10771
|
+
blameSha: options.blameSha,
|
|
10772
|
+
blameSince: options.blameSince
|
|
10533
10773
|
});
|
|
10534
10774
|
}
|
|
10535
10775
|
async function findSimilarCode(projectRoot, host, code, options = {}) {
|
|
@@ -10671,13 +10911,6 @@ async function getIndexLogs(projectRoot, host, args) {
|
|
|
10671
10911
|
}
|
|
10672
10912
|
|
|
10673
10913
|
// src/mcp-server/shared.ts
|
|
10674
|
-
var MAX_CONTENT_LINES2 = 30;
|
|
10675
|
-
function truncateContent2(content) {
|
|
10676
|
-
const lines = content.split("\n");
|
|
10677
|
-
if (lines.length <= MAX_CONTENT_LINES2) return content;
|
|
10678
|
-
return lines.slice(0, MAX_CONTENT_LINES2).join("\n") + `
|
|
10679
|
-
// ... (${lines.length - MAX_CONTENT_LINES2} more lines)`;
|
|
10680
|
-
}
|
|
10681
10914
|
var CHUNK_TYPE_ENUM = [
|
|
10682
10915
|
"function",
|
|
10683
10916
|
"class",
|
|
@@ -10703,7 +10936,10 @@ function registerMcpTools(server, runtime) {
|
|
|
10703
10936
|
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
10704
10937
|
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
10705
10938
|
chunkType: z2.enum(CHUNK_TYPE_ENUM).optional().describe("Filter by code chunk type"),
|
|
10706
|
-
contextLines: z2.number().optional().describe("Number of extra lines to include before/after each match (default: 0)")
|
|
10939
|
+
contextLines: z2.number().optional().describe("Number of extra lines to include before/after each match (default: 0)"),
|
|
10940
|
+
blameAuthor: z2.string().optional().describe("Filter by git blame author name or email"),
|
|
10941
|
+
blameSha: z2.string().optional().describe("Filter by git blame commit SHA or prefix"),
|
|
10942
|
+
blameSince: z2.string().optional().describe("Filter to chunks last changed on or after this date")
|
|
10707
10943
|
},
|
|
10708
10944
|
async (args) => {
|
|
10709
10945
|
const results = await searchCodebase(runtime.projectRoot, runtime.host, args.query, {
|
|
@@ -10711,21 +10947,17 @@ function registerMcpTools(server, runtime) {
|
|
|
10711
10947
|
fileType: args.fileType,
|
|
10712
10948
|
directory: args.directory,
|
|
10713
10949
|
chunkType: args.chunkType,
|
|
10714
|
-
contextLines: args.contextLines
|
|
10950
|
+
contextLines: args.contextLines,
|
|
10951
|
+
blameAuthor: args.blameAuthor,
|
|
10952
|
+
blameSha: args.blameSha,
|
|
10953
|
+
blameSince: args.blameSince
|
|
10715
10954
|
});
|
|
10716
10955
|
if (results.length === 0) {
|
|
10717
10956
|
return { content: [{ type: "text", text: "No matching code found. Try a different query or run index_codebase first." }] };
|
|
10718
10957
|
}
|
|
10719
|
-
const formatted = results.map((r, idx) => {
|
|
10720
|
-
const header = r.name ? `[${idx + 1}] ${r.chunkType} "${r.name}" in ${r.filePath}:${r.startLine}-${r.endLine}` : `[${idx + 1}] ${r.chunkType} in ${r.filePath}:${r.startLine}-${r.endLine}`;
|
|
10721
|
-
return `${header} (score: ${r.score.toFixed(2)})
|
|
10722
|
-
\`\`\`
|
|
10723
|
-
${truncateContent2(r.content)}
|
|
10724
|
-
\`\`\``;
|
|
10725
|
-
});
|
|
10726
10958
|
return { content: [{ type: "text", text: `Found ${results.length} results for "${args.query}":
|
|
10727
10959
|
|
|
10728
|
-
${
|
|
10960
|
+
${formatSearchResults(results, "score")}` }] };
|
|
10729
10961
|
}
|
|
10730
10962
|
);
|
|
10731
10963
|
server.tool(
|
|
@@ -10736,7 +10968,10 @@ ${formatted.join("\n\n")}` }] };
|
|
|
10736
10968
|
limit: z2.number().optional().default(10).describe("Maximum number of results to return"),
|
|
10737
10969
|
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
10738
10970
|
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
10739
|
-
chunkType: z2.enum(CHUNK_TYPE_ENUM).optional().describe("Filter by code chunk type")
|
|
10971
|
+
chunkType: z2.enum(CHUNK_TYPE_ENUM).optional().describe("Filter by code chunk type"),
|
|
10972
|
+
blameAuthor: z2.string().optional().describe("Filter by git blame author name or email"),
|
|
10973
|
+
blameSha: z2.string().optional().describe("Filter by git blame commit SHA or prefix"),
|
|
10974
|
+
blameSince: z2.string().optional().describe("Filter to chunks last changed on or after this date")
|
|
10740
10975
|
},
|
|
10741
10976
|
async (args) => {
|
|
10742
10977
|
const results = await searchCodebase(runtime.projectRoot, runtime.host, args.query, {
|
|
@@ -10744,19 +10979,17 @@ ${formatted.join("\n\n")}` }] };
|
|
|
10744
10979
|
fileType: args.fileType,
|
|
10745
10980
|
directory: args.directory,
|
|
10746
10981
|
chunkType: args.chunkType,
|
|
10747
|
-
metadataOnly: true
|
|
10982
|
+
metadataOnly: true,
|
|
10983
|
+
blameAuthor: args.blameAuthor,
|
|
10984
|
+
blameSha: args.blameSha,
|
|
10985
|
+
blameSince: args.blameSince
|
|
10748
10986
|
});
|
|
10749
10987
|
if (results.length === 0) {
|
|
10750
10988
|
return { content: [{ type: "text", text: "No matching code found. Try a different query or run index_codebase first." }] };
|
|
10751
10989
|
}
|
|
10752
|
-
const formatted = results.map((r, idx) => {
|
|
10753
|
-
const location = `${r.filePath}:${r.startLine}-${r.endLine}`;
|
|
10754
|
-
const name = r.name ? `"${r.name}"` : "(anonymous)";
|
|
10755
|
-
return `[${idx + 1}] ${r.chunkType} ${name} at ${location} (score: ${r.score.toFixed(2)})`;
|
|
10756
|
-
});
|
|
10757
10990
|
return { content: [{ type: "text", text: `Found ${results.length} locations for "${args.query}":
|
|
10758
10991
|
|
|
10759
|
-
${
|
|
10992
|
+
${formatCodebasePeek(results)}
|
|
10760
10993
|
|
|
10761
10994
|
Use Read tool to examine specific files.` }] };
|
|
10762
10995
|
}
|
|
@@ -10837,16 +11070,9 @@ Use Read tool to examine specific files.` }] };
|
|
|
10837
11070
|
if (results.length === 0) {
|
|
10838
11071
|
return { content: [{ type: "text", text: "No similar code found. Try a different snippet or run index_codebase first." }] };
|
|
10839
11072
|
}
|
|
10840
|
-
const formatted = results.map((r, idx) => {
|
|
10841
|
-
const header = r.name ? `[${idx + 1}] ${r.chunkType} "${r.name}" in ${r.filePath}:${r.startLine}-${r.endLine}` : `[${idx + 1}] ${r.chunkType} in ${r.filePath}:${r.startLine}-${r.endLine}`;
|
|
10842
|
-
return `${header} (similarity: ${(r.score * 100).toFixed(1)}%)
|
|
10843
|
-
\`\`\`
|
|
10844
|
-
${truncateContent2(r.content)}
|
|
10845
|
-
\`\`\``;
|
|
10846
|
-
});
|
|
10847
11073
|
return { content: [{ type: "text", text: `Found ${results.length} similar code blocks:
|
|
10848
11074
|
|
|
10849
|
-
${
|
|
11075
|
+
${formatSearchResults(results)}` }] };
|
|
10850
11076
|
}
|
|
10851
11077
|
);
|
|
10852
11078
|
server.tool(
|
|
@@ -10882,28 +11108,10 @@ ${formatted.join("\n\n")}` }] };
|
|
|
10882
11108
|
return { content: [{ type: "text", text: "Error: 'symbolId' is required when direction is 'callees'." }] };
|
|
10883
11109
|
}
|
|
10884
11110
|
const { callees } = await getCallGraphData(runtime.projectRoot, runtime.host, args);
|
|
10885
|
-
|
|
10886
|
-
return { content: [{ type: "text", text: `No callees found for symbol ${args.symbolId}${args.relationshipType ? ` with type ${args.relationshipType}` : ""}.` }] };
|
|
10887
|
-
}
|
|
10888
|
-
const formatted2 = callees.map((e, i) => {
|
|
10889
|
-
const conf = e.confidence !== "Direct" ? ` [${e.confidence.toLowerCase()}]` : "";
|
|
10890
|
-
return `[${i + 1}] \u2192 ${e.targetName} (${e.callType})${conf} at line ${e.line}${e.isResolved ? ` [resolved: ${e.toSymbolId}]` : " [unresolved]"}`;
|
|
10891
|
-
});
|
|
10892
|
-
return { content: [{ type: "text", text: `Callees (${callees.length}):
|
|
10893
|
-
|
|
10894
|
-
${formatted2.join("\n")}` }] };
|
|
11111
|
+
return { content: [{ type: "text", text: formatCallGraphCallees(args.symbolId, callees, args.relationshipType) }] };
|
|
10895
11112
|
}
|
|
10896
11113
|
const { callers } = await getCallGraphData(runtime.projectRoot, runtime.host, args);
|
|
10897
|
-
|
|
10898
|
-
return { content: [{ type: "text", text: `No callers found for "${args.name}"${args.relationshipType ? ` with type ${args.relationshipType}` : ""}.` }] };
|
|
10899
|
-
}
|
|
10900
|
-
const formatted = callers.map((e, i) => {
|
|
10901
|
-
const conf = e.confidence !== "Direct" ? ` [${e.confidence.toLowerCase()}]` : "";
|
|
10902
|
-
return `[${i + 1}] \u2190 from ${e.fromSymbolName ?? "<unknown>"} in ${e.fromSymbolFilePath ?? "<unknown file>"} [${e.fromSymbolId}] (${e.callType})${conf} at line ${e.line}${e.isResolved ? " [resolved]" : " [unresolved]"}`;
|
|
10903
|
-
});
|
|
10904
|
-
return { content: [{ type: "text", text: `"${args.name}" is called by ${callers.length} function(s):
|
|
10905
|
-
|
|
10906
|
-
${formatted.join("\n")}` }] };
|
|
11114
|
+
return { content: [{ type: "text", text: formatCallGraphCallers(args.name, callers, args.relationshipType) }] };
|
|
10907
11115
|
}
|
|
10908
11116
|
);
|
|
10909
11117
|
server.tool(
|
|
@@ -10915,17 +11123,8 @@ ${formatted.join("\n")}` }] };
|
|
|
10915
11123
|
maxDepth: z2.number().optional().default(10).describe("Maximum traversal depth (default: 10)")
|
|
10916
11124
|
},
|
|
10917
11125
|
async (args) => {
|
|
10918
|
-
const
|
|
10919
|
-
|
|
10920
|
-
return { content: [{ type: "text", text: `No path found between "${args.from}" and "${args.to}". They may be in disconnected components, or the call graph index needs updating.` }] };
|
|
10921
|
-
}
|
|
10922
|
-
const formatted = path25.map((hop, i) => {
|
|
10923
|
-
const prefix = i === 0 ? "[start]" : `--${hop.callType}-->`;
|
|
10924
|
-
const location = hop.filePath ? ` (${hop.filePath}:${hop.line})` : "";
|
|
10925
|
-
return `${prefix} ${hop.symbolName}${location}`;
|
|
10926
|
-
});
|
|
10927
|
-
return { content: [{ type: "text", text: `Path (${path25.length} hops):
|
|
10928
|
-
${formatted.join("\n")}` }] };
|
|
11126
|
+
const path26 = await getCallGraphPath(runtime.projectRoot, runtime.host, args.from, args.to, args.maxDepth);
|
|
11127
|
+
return { content: [{ type: "text", text: formatCallGraphPath(args.from, args.to, path26) }] };
|
|
10929
11128
|
}
|
|
10930
11129
|
);
|
|
10931
11130
|
server.tool(
|
|
@@ -11084,7 +11283,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
11084
11283
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
11085
11284
|
const statMethod = opts.lstat ? lstat : stat;
|
|
11086
11285
|
if (wantBigintFsStats) {
|
|
11087
|
-
this._stat = (
|
|
11286
|
+
this._stat = (path26) => statMethod(path26, { bigint: true });
|
|
11088
11287
|
} else {
|
|
11089
11288
|
this._stat = statMethod;
|
|
11090
11289
|
}
|
|
@@ -11109,8 +11308,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
11109
11308
|
const par = this.parent;
|
|
11110
11309
|
const fil = par && par.files;
|
|
11111
11310
|
if (fil && fil.length > 0) {
|
|
11112
|
-
const { path:
|
|
11113
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
11311
|
+
const { path: path26, depth } = par;
|
|
11312
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path26));
|
|
11114
11313
|
const awaited = await Promise.all(slice);
|
|
11115
11314
|
for (const entry of awaited) {
|
|
11116
11315
|
if (!entry)
|
|
@@ -11150,20 +11349,20 @@ var ReaddirpStream = class extends Readable {
|
|
|
11150
11349
|
this.reading = false;
|
|
11151
11350
|
}
|
|
11152
11351
|
}
|
|
11153
|
-
async _exploreDir(
|
|
11352
|
+
async _exploreDir(path26, depth) {
|
|
11154
11353
|
let files;
|
|
11155
11354
|
try {
|
|
11156
|
-
files = await readdir(
|
|
11355
|
+
files = await readdir(path26, this._rdOptions);
|
|
11157
11356
|
} catch (error) {
|
|
11158
11357
|
this._onError(error);
|
|
11159
11358
|
}
|
|
11160
|
-
return { files, depth, path:
|
|
11359
|
+
return { files, depth, path: path26 };
|
|
11161
11360
|
}
|
|
11162
|
-
async _formatEntry(dirent,
|
|
11361
|
+
async _formatEntry(dirent, path26) {
|
|
11163
11362
|
let entry;
|
|
11164
11363
|
const basename5 = this._isDirent ? dirent.name : dirent;
|
|
11165
11364
|
try {
|
|
11166
|
-
const fullPath = presolve(pjoin(
|
|
11365
|
+
const fullPath = presolve(pjoin(path26, basename5));
|
|
11167
11366
|
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename5 };
|
|
11168
11367
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
11169
11368
|
} catch (err) {
|
|
@@ -11563,16 +11762,16 @@ var delFromSet = (main2, prop, item) => {
|
|
|
11563
11762
|
};
|
|
11564
11763
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
11565
11764
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
11566
|
-
function createFsWatchInstance(
|
|
11765
|
+
function createFsWatchInstance(path26, options, listener, errHandler, emitRaw) {
|
|
11567
11766
|
const handleEvent = (rawEvent, evPath) => {
|
|
11568
|
-
listener(
|
|
11569
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
11570
|
-
if (evPath &&
|
|
11571
|
-
fsWatchBroadcast(sp.resolve(
|
|
11767
|
+
listener(path26);
|
|
11768
|
+
emitRaw(rawEvent, evPath, { watchedPath: path26 });
|
|
11769
|
+
if (evPath && path26 !== evPath) {
|
|
11770
|
+
fsWatchBroadcast(sp.resolve(path26, evPath), KEY_LISTENERS, sp.join(path26, evPath));
|
|
11572
11771
|
}
|
|
11573
11772
|
};
|
|
11574
11773
|
try {
|
|
11575
|
-
return fs_watch(
|
|
11774
|
+
return fs_watch(path26, {
|
|
11576
11775
|
persistent: options.persistent
|
|
11577
11776
|
}, handleEvent);
|
|
11578
11777
|
} catch (error) {
|
|
@@ -11588,12 +11787,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
11588
11787
|
listener(val1, val2, val3);
|
|
11589
11788
|
});
|
|
11590
11789
|
};
|
|
11591
|
-
var setFsWatchListener = (
|
|
11790
|
+
var setFsWatchListener = (path26, fullPath, options, handlers) => {
|
|
11592
11791
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
11593
11792
|
let cont = FsWatchInstances.get(fullPath);
|
|
11594
11793
|
let watcher;
|
|
11595
11794
|
if (!options.persistent) {
|
|
11596
|
-
watcher = createFsWatchInstance(
|
|
11795
|
+
watcher = createFsWatchInstance(path26, options, listener, errHandler, rawEmitter);
|
|
11597
11796
|
if (!watcher)
|
|
11598
11797
|
return;
|
|
11599
11798
|
return watcher.close.bind(watcher);
|
|
@@ -11604,7 +11803,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
11604
11803
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
11605
11804
|
} else {
|
|
11606
11805
|
watcher = createFsWatchInstance(
|
|
11607
|
-
|
|
11806
|
+
path26,
|
|
11608
11807
|
options,
|
|
11609
11808
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
11610
11809
|
errHandler,
|
|
@@ -11619,7 +11818,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
11619
11818
|
cont.watcherUnusable = true;
|
|
11620
11819
|
if (isWindows && error.code === "EPERM") {
|
|
11621
11820
|
try {
|
|
11622
|
-
const fd = await open(
|
|
11821
|
+
const fd = await open(path26, "r");
|
|
11623
11822
|
await fd.close();
|
|
11624
11823
|
broadcastErr(error);
|
|
11625
11824
|
} catch (err) {
|
|
@@ -11650,7 +11849,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
11650
11849
|
};
|
|
11651
11850
|
};
|
|
11652
11851
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
11653
|
-
var setFsWatchFileListener = (
|
|
11852
|
+
var setFsWatchFileListener = (path26, fullPath, options, handlers) => {
|
|
11654
11853
|
const { listener, rawEmitter } = handlers;
|
|
11655
11854
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
11656
11855
|
const copts = cont && cont.options;
|
|
@@ -11672,7 +11871,7 @@ var setFsWatchFileListener = (path25, fullPath, options, handlers) => {
|
|
|
11672
11871
|
});
|
|
11673
11872
|
const currmtime = curr.mtimeMs;
|
|
11674
11873
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
11675
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
11874
|
+
foreach(cont.listeners, (listener2) => listener2(path26, curr));
|
|
11676
11875
|
}
|
|
11677
11876
|
})
|
|
11678
11877
|
};
|
|
@@ -11702,13 +11901,13 @@ var NodeFsHandler = class {
|
|
|
11702
11901
|
* @param listener on fs change
|
|
11703
11902
|
* @returns closer for the watcher instance
|
|
11704
11903
|
*/
|
|
11705
|
-
_watchWithNodeFs(
|
|
11904
|
+
_watchWithNodeFs(path26, listener) {
|
|
11706
11905
|
const opts = this.fsw.options;
|
|
11707
|
-
const directory = sp.dirname(
|
|
11708
|
-
const basename5 = sp.basename(
|
|
11906
|
+
const directory = sp.dirname(path26);
|
|
11907
|
+
const basename5 = sp.basename(path26);
|
|
11709
11908
|
const parent = this.fsw._getWatchedDir(directory);
|
|
11710
11909
|
parent.add(basename5);
|
|
11711
|
-
const absolutePath = sp.resolve(
|
|
11910
|
+
const absolutePath = sp.resolve(path26);
|
|
11712
11911
|
const options = {
|
|
11713
11912
|
persistent: opts.persistent
|
|
11714
11913
|
};
|
|
@@ -11718,12 +11917,12 @@ var NodeFsHandler = class {
|
|
|
11718
11917
|
if (opts.usePolling) {
|
|
11719
11918
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
11720
11919
|
options.interval = enableBin && isBinaryPath(basename5) ? opts.binaryInterval : opts.interval;
|
|
11721
|
-
closer = setFsWatchFileListener(
|
|
11920
|
+
closer = setFsWatchFileListener(path26, absolutePath, options, {
|
|
11722
11921
|
listener,
|
|
11723
11922
|
rawEmitter: this.fsw._emitRaw
|
|
11724
11923
|
});
|
|
11725
11924
|
} else {
|
|
11726
|
-
closer = setFsWatchListener(
|
|
11925
|
+
closer = setFsWatchListener(path26, absolutePath, options, {
|
|
11727
11926
|
listener,
|
|
11728
11927
|
errHandler: this._boundHandleError,
|
|
11729
11928
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -11745,7 +11944,7 @@ var NodeFsHandler = class {
|
|
|
11745
11944
|
let prevStats = stats;
|
|
11746
11945
|
if (parent.has(basename5))
|
|
11747
11946
|
return;
|
|
11748
|
-
const listener = async (
|
|
11947
|
+
const listener = async (path26, newStats) => {
|
|
11749
11948
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
11750
11949
|
return;
|
|
11751
11950
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -11759,11 +11958,11 @@ var NodeFsHandler = class {
|
|
|
11759
11958
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
11760
11959
|
}
|
|
11761
11960
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
11762
|
-
this.fsw._closeFile(
|
|
11961
|
+
this.fsw._closeFile(path26);
|
|
11763
11962
|
prevStats = newStats2;
|
|
11764
11963
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
11765
11964
|
if (closer2)
|
|
11766
|
-
this.fsw._addPathCloser(
|
|
11965
|
+
this.fsw._addPathCloser(path26, closer2);
|
|
11767
11966
|
} else {
|
|
11768
11967
|
prevStats = newStats2;
|
|
11769
11968
|
}
|
|
@@ -11795,7 +11994,7 @@ var NodeFsHandler = class {
|
|
|
11795
11994
|
* @param item basename of this item
|
|
11796
11995
|
* @returns true if no more processing is needed for this entry.
|
|
11797
11996
|
*/
|
|
11798
|
-
async _handleSymlink(entry, directory,
|
|
11997
|
+
async _handleSymlink(entry, directory, path26, item) {
|
|
11799
11998
|
if (this.fsw.closed) {
|
|
11800
11999
|
return;
|
|
11801
12000
|
}
|
|
@@ -11805,7 +12004,7 @@ var NodeFsHandler = class {
|
|
|
11805
12004
|
this.fsw._incrReadyCount();
|
|
11806
12005
|
let linkPath;
|
|
11807
12006
|
try {
|
|
11808
|
-
linkPath = await fsrealpath(
|
|
12007
|
+
linkPath = await fsrealpath(path26);
|
|
11809
12008
|
} catch (e) {
|
|
11810
12009
|
this.fsw._emitReady();
|
|
11811
12010
|
return true;
|
|
@@ -11815,12 +12014,12 @@ var NodeFsHandler = class {
|
|
|
11815
12014
|
if (dir.has(item)) {
|
|
11816
12015
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
11817
12016
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
11818
|
-
this.fsw._emit(EV.CHANGE,
|
|
12017
|
+
this.fsw._emit(EV.CHANGE, path26, entry.stats);
|
|
11819
12018
|
}
|
|
11820
12019
|
} else {
|
|
11821
12020
|
dir.add(item);
|
|
11822
12021
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
11823
|
-
this.fsw._emit(EV.ADD,
|
|
12022
|
+
this.fsw._emit(EV.ADD, path26, entry.stats);
|
|
11824
12023
|
}
|
|
11825
12024
|
this.fsw._emitReady();
|
|
11826
12025
|
return true;
|
|
@@ -11850,9 +12049,9 @@ var NodeFsHandler = class {
|
|
|
11850
12049
|
return;
|
|
11851
12050
|
}
|
|
11852
12051
|
const item = entry.path;
|
|
11853
|
-
let
|
|
12052
|
+
let path26 = sp.join(directory, item);
|
|
11854
12053
|
current.add(item);
|
|
11855
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
12054
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path26, item)) {
|
|
11856
12055
|
return;
|
|
11857
12056
|
}
|
|
11858
12057
|
if (this.fsw.closed) {
|
|
@@ -11861,8 +12060,8 @@ var NodeFsHandler = class {
|
|
|
11861
12060
|
}
|
|
11862
12061
|
if (item === target || !target && !previous.has(item)) {
|
|
11863
12062
|
this.fsw._incrReadyCount();
|
|
11864
|
-
|
|
11865
|
-
this._addToNodeFs(
|
|
12063
|
+
path26 = sp.join(dir, sp.relative(dir, path26));
|
|
12064
|
+
this._addToNodeFs(path26, initialAdd, wh, depth + 1);
|
|
11866
12065
|
}
|
|
11867
12066
|
}).on(EV.ERROR, this._boundHandleError);
|
|
11868
12067
|
return new Promise((resolve15, reject) => {
|
|
@@ -11931,13 +12130,13 @@ var NodeFsHandler = class {
|
|
|
11931
12130
|
* @param depth Child path actually targeted for watch
|
|
11932
12131
|
* @param target Child path actually targeted for watch
|
|
11933
12132
|
*/
|
|
11934
|
-
async _addToNodeFs(
|
|
12133
|
+
async _addToNodeFs(path26, initialAdd, priorWh, depth, target) {
|
|
11935
12134
|
const ready = this.fsw._emitReady;
|
|
11936
|
-
if (this.fsw._isIgnored(
|
|
12135
|
+
if (this.fsw._isIgnored(path26) || this.fsw.closed) {
|
|
11937
12136
|
ready();
|
|
11938
12137
|
return false;
|
|
11939
12138
|
}
|
|
11940
|
-
const wh = this.fsw._getWatchHelpers(
|
|
12139
|
+
const wh = this.fsw._getWatchHelpers(path26);
|
|
11941
12140
|
if (priorWh) {
|
|
11942
12141
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
11943
12142
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -11953,8 +12152,8 @@ var NodeFsHandler = class {
|
|
|
11953
12152
|
const follow = this.fsw.options.followSymlinks;
|
|
11954
12153
|
let closer;
|
|
11955
12154
|
if (stats.isDirectory()) {
|
|
11956
|
-
const absPath = sp.resolve(
|
|
11957
|
-
const targetPath = follow ? await fsrealpath(
|
|
12155
|
+
const absPath = sp.resolve(path26);
|
|
12156
|
+
const targetPath = follow ? await fsrealpath(path26) : path26;
|
|
11958
12157
|
if (this.fsw.closed)
|
|
11959
12158
|
return;
|
|
11960
12159
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -11964,29 +12163,29 @@ var NodeFsHandler = class {
|
|
|
11964
12163
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
11965
12164
|
}
|
|
11966
12165
|
} else if (stats.isSymbolicLink()) {
|
|
11967
|
-
const targetPath = follow ? await fsrealpath(
|
|
12166
|
+
const targetPath = follow ? await fsrealpath(path26) : path26;
|
|
11968
12167
|
if (this.fsw.closed)
|
|
11969
12168
|
return;
|
|
11970
12169
|
const parent = sp.dirname(wh.watchPath);
|
|
11971
12170
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
11972
12171
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
11973
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
12172
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path26, wh, targetPath);
|
|
11974
12173
|
if (this.fsw.closed)
|
|
11975
12174
|
return;
|
|
11976
12175
|
if (targetPath !== void 0) {
|
|
11977
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
12176
|
+
this.fsw._symlinkPaths.set(sp.resolve(path26), targetPath);
|
|
11978
12177
|
}
|
|
11979
12178
|
} else {
|
|
11980
12179
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
11981
12180
|
}
|
|
11982
12181
|
ready();
|
|
11983
12182
|
if (closer)
|
|
11984
|
-
this.fsw._addPathCloser(
|
|
12183
|
+
this.fsw._addPathCloser(path26, closer);
|
|
11985
12184
|
return false;
|
|
11986
12185
|
} catch (error) {
|
|
11987
12186
|
if (this.fsw._handleError(error)) {
|
|
11988
12187
|
ready();
|
|
11989
|
-
return
|
|
12188
|
+
return path26;
|
|
11990
12189
|
}
|
|
11991
12190
|
}
|
|
11992
12191
|
}
|
|
@@ -12018,35 +12217,35 @@ function createPattern(matcher) {
|
|
|
12018
12217
|
if (matcher.path === string)
|
|
12019
12218
|
return true;
|
|
12020
12219
|
if (matcher.recursive) {
|
|
12021
|
-
const
|
|
12022
|
-
if (!
|
|
12220
|
+
const relative11 = sp2.relative(matcher.path, string);
|
|
12221
|
+
if (!relative11) {
|
|
12023
12222
|
return false;
|
|
12024
12223
|
}
|
|
12025
|
-
return !
|
|
12224
|
+
return !relative11.startsWith("..") && !sp2.isAbsolute(relative11);
|
|
12026
12225
|
}
|
|
12027
12226
|
return false;
|
|
12028
12227
|
};
|
|
12029
12228
|
}
|
|
12030
12229
|
return () => false;
|
|
12031
12230
|
}
|
|
12032
|
-
function normalizePath2(
|
|
12033
|
-
if (typeof
|
|
12231
|
+
function normalizePath2(path26) {
|
|
12232
|
+
if (typeof path26 !== "string")
|
|
12034
12233
|
throw new Error("string expected");
|
|
12035
|
-
|
|
12036
|
-
|
|
12234
|
+
path26 = sp2.normalize(path26);
|
|
12235
|
+
path26 = path26.replace(/\\/g, "/");
|
|
12037
12236
|
let prepend = false;
|
|
12038
|
-
if (
|
|
12237
|
+
if (path26.startsWith("//"))
|
|
12039
12238
|
prepend = true;
|
|
12040
|
-
|
|
12239
|
+
path26 = path26.replace(DOUBLE_SLASH_RE, "/");
|
|
12041
12240
|
if (prepend)
|
|
12042
|
-
|
|
12043
|
-
return
|
|
12241
|
+
path26 = "/" + path26;
|
|
12242
|
+
return path26;
|
|
12044
12243
|
}
|
|
12045
12244
|
function matchPatterns(patterns, testString, stats) {
|
|
12046
|
-
const
|
|
12245
|
+
const path26 = normalizePath2(testString);
|
|
12047
12246
|
for (let index = 0; index < patterns.length; index++) {
|
|
12048
12247
|
const pattern = patterns[index];
|
|
12049
|
-
if (pattern(
|
|
12248
|
+
if (pattern(path26, stats)) {
|
|
12050
12249
|
return true;
|
|
12051
12250
|
}
|
|
12052
12251
|
}
|
|
@@ -12084,19 +12283,19 @@ var toUnix = (string) => {
|
|
|
12084
12283
|
}
|
|
12085
12284
|
return str;
|
|
12086
12285
|
};
|
|
12087
|
-
var normalizePathToUnix = (
|
|
12088
|
-
var normalizeIgnored = (cwd = "") => (
|
|
12089
|
-
if (typeof
|
|
12090
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
12286
|
+
var normalizePathToUnix = (path26) => toUnix(sp2.normalize(toUnix(path26)));
|
|
12287
|
+
var normalizeIgnored = (cwd = "") => (path26) => {
|
|
12288
|
+
if (typeof path26 === "string") {
|
|
12289
|
+
return normalizePathToUnix(sp2.isAbsolute(path26) ? path26 : sp2.join(cwd, path26));
|
|
12091
12290
|
} else {
|
|
12092
|
-
return
|
|
12291
|
+
return path26;
|
|
12093
12292
|
}
|
|
12094
12293
|
};
|
|
12095
|
-
var getAbsolutePath = (
|
|
12096
|
-
if (sp2.isAbsolute(
|
|
12097
|
-
return
|
|
12294
|
+
var getAbsolutePath = (path26, cwd) => {
|
|
12295
|
+
if (sp2.isAbsolute(path26)) {
|
|
12296
|
+
return path26;
|
|
12098
12297
|
}
|
|
12099
|
-
return sp2.join(cwd,
|
|
12298
|
+
return sp2.join(cwd, path26);
|
|
12100
12299
|
};
|
|
12101
12300
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
12102
12301
|
var DirEntry = class {
|
|
@@ -12161,10 +12360,10 @@ var WatchHelper = class {
|
|
|
12161
12360
|
dirParts;
|
|
12162
12361
|
followSymlinks;
|
|
12163
12362
|
statMethod;
|
|
12164
|
-
constructor(
|
|
12363
|
+
constructor(path26, follow, fsw) {
|
|
12165
12364
|
this.fsw = fsw;
|
|
12166
|
-
const watchPath =
|
|
12167
|
-
this.path =
|
|
12365
|
+
const watchPath = path26;
|
|
12366
|
+
this.path = path26 = path26.replace(REPLACER_RE, "");
|
|
12168
12367
|
this.watchPath = watchPath;
|
|
12169
12368
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
12170
12369
|
this.dirParts = [];
|
|
@@ -12304,20 +12503,20 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12304
12503
|
this._closePromise = void 0;
|
|
12305
12504
|
let paths = unifyPaths(paths_);
|
|
12306
12505
|
if (cwd) {
|
|
12307
|
-
paths = paths.map((
|
|
12308
|
-
const absPath = getAbsolutePath(
|
|
12506
|
+
paths = paths.map((path26) => {
|
|
12507
|
+
const absPath = getAbsolutePath(path26, cwd);
|
|
12309
12508
|
return absPath;
|
|
12310
12509
|
});
|
|
12311
12510
|
}
|
|
12312
|
-
paths.forEach((
|
|
12313
|
-
this._removeIgnoredPath(
|
|
12511
|
+
paths.forEach((path26) => {
|
|
12512
|
+
this._removeIgnoredPath(path26);
|
|
12314
12513
|
});
|
|
12315
12514
|
this._userIgnored = void 0;
|
|
12316
12515
|
if (!this._readyCount)
|
|
12317
12516
|
this._readyCount = 0;
|
|
12318
12517
|
this._readyCount += paths.length;
|
|
12319
|
-
Promise.all(paths.map(async (
|
|
12320
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
12518
|
+
Promise.all(paths.map(async (path26) => {
|
|
12519
|
+
const res = await this._nodeFsHandler._addToNodeFs(path26, !_internal, void 0, 0, _origAdd);
|
|
12321
12520
|
if (res)
|
|
12322
12521
|
this._emitReady();
|
|
12323
12522
|
return res;
|
|
@@ -12339,17 +12538,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12339
12538
|
return this;
|
|
12340
12539
|
const paths = unifyPaths(paths_);
|
|
12341
12540
|
const { cwd } = this.options;
|
|
12342
|
-
paths.forEach((
|
|
12343
|
-
if (!sp2.isAbsolute(
|
|
12541
|
+
paths.forEach((path26) => {
|
|
12542
|
+
if (!sp2.isAbsolute(path26) && !this._closers.has(path26)) {
|
|
12344
12543
|
if (cwd)
|
|
12345
|
-
|
|
12346
|
-
|
|
12544
|
+
path26 = sp2.join(cwd, path26);
|
|
12545
|
+
path26 = sp2.resolve(path26);
|
|
12347
12546
|
}
|
|
12348
|
-
this._closePath(
|
|
12349
|
-
this._addIgnoredPath(
|
|
12350
|
-
if (this._watched.has(
|
|
12547
|
+
this._closePath(path26);
|
|
12548
|
+
this._addIgnoredPath(path26);
|
|
12549
|
+
if (this._watched.has(path26)) {
|
|
12351
12550
|
this._addIgnoredPath({
|
|
12352
|
-
path:
|
|
12551
|
+
path: path26,
|
|
12353
12552
|
recursive: true
|
|
12354
12553
|
});
|
|
12355
12554
|
}
|
|
@@ -12413,38 +12612,38 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12413
12612
|
* @param stats arguments to be passed with event
|
|
12414
12613
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
12415
12614
|
*/
|
|
12416
|
-
async _emit(event,
|
|
12615
|
+
async _emit(event, path26, stats) {
|
|
12417
12616
|
if (this.closed)
|
|
12418
12617
|
return;
|
|
12419
12618
|
const opts = this.options;
|
|
12420
12619
|
if (isWindows)
|
|
12421
|
-
|
|
12620
|
+
path26 = sp2.normalize(path26);
|
|
12422
12621
|
if (opts.cwd)
|
|
12423
|
-
|
|
12424
|
-
const args = [
|
|
12622
|
+
path26 = sp2.relative(opts.cwd, path26);
|
|
12623
|
+
const args = [path26];
|
|
12425
12624
|
if (stats != null)
|
|
12426
12625
|
args.push(stats);
|
|
12427
12626
|
const awf = opts.awaitWriteFinish;
|
|
12428
12627
|
let pw;
|
|
12429
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
12628
|
+
if (awf && (pw = this._pendingWrites.get(path26))) {
|
|
12430
12629
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
12431
12630
|
return this;
|
|
12432
12631
|
}
|
|
12433
12632
|
if (opts.atomic) {
|
|
12434
12633
|
if (event === EVENTS.UNLINK) {
|
|
12435
|
-
this._pendingUnlinks.set(
|
|
12634
|
+
this._pendingUnlinks.set(path26, [event, ...args]);
|
|
12436
12635
|
setTimeout(() => {
|
|
12437
|
-
this._pendingUnlinks.forEach((entry,
|
|
12636
|
+
this._pendingUnlinks.forEach((entry, path27) => {
|
|
12438
12637
|
this.emit(...entry);
|
|
12439
12638
|
this.emit(EVENTS.ALL, ...entry);
|
|
12440
|
-
this._pendingUnlinks.delete(
|
|
12639
|
+
this._pendingUnlinks.delete(path27);
|
|
12441
12640
|
});
|
|
12442
12641
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
12443
12642
|
return this;
|
|
12444
12643
|
}
|
|
12445
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
12644
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path26)) {
|
|
12446
12645
|
event = EVENTS.CHANGE;
|
|
12447
|
-
this._pendingUnlinks.delete(
|
|
12646
|
+
this._pendingUnlinks.delete(path26);
|
|
12448
12647
|
}
|
|
12449
12648
|
}
|
|
12450
12649
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -12462,16 +12661,16 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12462
12661
|
this.emitWithAll(event, args);
|
|
12463
12662
|
}
|
|
12464
12663
|
};
|
|
12465
|
-
this._awaitWriteFinish(
|
|
12664
|
+
this._awaitWriteFinish(path26, awf.stabilityThreshold, event, awfEmit);
|
|
12466
12665
|
return this;
|
|
12467
12666
|
}
|
|
12468
12667
|
if (event === EVENTS.CHANGE) {
|
|
12469
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
12668
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path26, 50);
|
|
12470
12669
|
if (isThrottled)
|
|
12471
12670
|
return this;
|
|
12472
12671
|
}
|
|
12473
12672
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
12474
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
12673
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path26) : path26;
|
|
12475
12674
|
let stats2;
|
|
12476
12675
|
try {
|
|
12477
12676
|
stats2 = await stat3(fullPath);
|
|
@@ -12502,23 +12701,23 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12502
12701
|
* @param timeout duration of time to suppress duplicate actions
|
|
12503
12702
|
* @returns tracking object or false if action should be suppressed
|
|
12504
12703
|
*/
|
|
12505
|
-
_throttle(actionType,
|
|
12704
|
+
_throttle(actionType, path26, timeout) {
|
|
12506
12705
|
if (!this._throttled.has(actionType)) {
|
|
12507
12706
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
12508
12707
|
}
|
|
12509
12708
|
const action = this._throttled.get(actionType);
|
|
12510
12709
|
if (!action)
|
|
12511
12710
|
throw new Error("invalid throttle");
|
|
12512
|
-
const actionPath = action.get(
|
|
12711
|
+
const actionPath = action.get(path26);
|
|
12513
12712
|
if (actionPath) {
|
|
12514
12713
|
actionPath.count++;
|
|
12515
12714
|
return false;
|
|
12516
12715
|
}
|
|
12517
12716
|
let timeoutObject;
|
|
12518
12717
|
const clear = () => {
|
|
12519
|
-
const item = action.get(
|
|
12718
|
+
const item = action.get(path26);
|
|
12520
12719
|
const count = item ? item.count : 0;
|
|
12521
|
-
action.delete(
|
|
12720
|
+
action.delete(path26);
|
|
12522
12721
|
clearTimeout(timeoutObject);
|
|
12523
12722
|
if (item)
|
|
12524
12723
|
clearTimeout(item.timeoutObject);
|
|
@@ -12526,7 +12725,7 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12526
12725
|
};
|
|
12527
12726
|
timeoutObject = setTimeout(clear, timeout);
|
|
12528
12727
|
const thr = { timeoutObject, clear, count: 0 };
|
|
12529
|
-
action.set(
|
|
12728
|
+
action.set(path26, thr);
|
|
12530
12729
|
return thr;
|
|
12531
12730
|
}
|
|
12532
12731
|
_incrReadyCount() {
|
|
@@ -12540,44 +12739,44 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12540
12739
|
* @param event
|
|
12541
12740
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
12542
12741
|
*/
|
|
12543
|
-
_awaitWriteFinish(
|
|
12742
|
+
_awaitWriteFinish(path26, threshold, event, awfEmit) {
|
|
12544
12743
|
const awf = this.options.awaitWriteFinish;
|
|
12545
12744
|
if (typeof awf !== "object")
|
|
12546
12745
|
return;
|
|
12547
12746
|
const pollInterval = awf.pollInterval;
|
|
12548
12747
|
let timeoutHandler;
|
|
12549
|
-
let fullPath =
|
|
12550
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
12551
|
-
fullPath = sp2.join(this.options.cwd,
|
|
12748
|
+
let fullPath = path26;
|
|
12749
|
+
if (this.options.cwd && !sp2.isAbsolute(path26)) {
|
|
12750
|
+
fullPath = sp2.join(this.options.cwd, path26);
|
|
12552
12751
|
}
|
|
12553
12752
|
const now = /* @__PURE__ */ new Date();
|
|
12554
12753
|
const writes = this._pendingWrites;
|
|
12555
12754
|
function awaitWriteFinishFn(prevStat) {
|
|
12556
12755
|
statcb(fullPath, (err, curStat) => {
|
|
12557
|
-
if (err || !writes.has(
|
|
12756
|
+
if (err || !writes.has(path26)) {
|
|
12558
12757
|
if (err && err.code !== "ENOENT")
|
|
12559
12758
|
awfEmit(err);
|
|
12560
12759
|
return;
|
|
12561
12760
|
}
|
|
12562
12761
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
12563
12762
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
12564
|
-
writes.get(
|
|
12763
|
+
writes.get(path26).lastChange = now2;
|
|
12565
12764
|
}
|
|
12566
|
-
const pw = writes.get(
|
|
12765
|
+
const pw = writes.get(path26);
|
|
12567
12766
|
const df = now2 - pw.lastChange;
|
|
12568
12767
|
if (df >= threshold) {
|
|
12569
|
-
writes.delete(
|
|
12768
|
+
writes.delete(path26);
|
|
12570
12769
|
awfEmit(void 0, curStat);
|
|
12571
12770
|
} else {
|
|
12572
12771
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
12573
12772
|
}
|
|
12574
12773
|
});
|
|
12575
12774
|
}
|
|
12576
|
-
if (!writes.has(
|
|
12577
|
-
writes.set(
|
|
12775
|
+
if (!writes.has(path26)) {
|
|
12776
|
+
writes.set(path26, {
|
|
12578
12777
|
lastChange: now,
|
|
12579
12778
|
cancelWait: () => {
|
|
12580
|
-
writes.delete(
|
|
12779
|
+
writes.delete(path26);
|
|
12581
12780
|
clearTimeout(timeoutHandler);
|
|
12582
12781
|
return event;
|
|
12583
12782
|
}
|
|
@@ -12588,8 +12787,8 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12588
12787
|
/**
|
|
12589
12788
|
* Determines whether user has asked to ignore this path.
|
|
12590
12789
|
*/
|
|
12591
|
-
_isIgnored(
|
|
12592
|
-
if (this.options.atomic && DOT_RE.test(
|
|
12790
|
+
_isIgnored(path26, stats) {
|
|
12791
|
+
if (this.options.atomic && DOT_RE.test(path26))
|
|
12593
12792
|
return true;
|
|
12594
12793
|
if (!this._userIgnored) {
|
|
12595
12794
|
const { cwd } = this.options;
|
|
@@ -12599,17 +12798,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12599
12798
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
12600
12799
|
this._userIgnored = anymatch(list, void 0);
|
|
12601
12800
|
}
|
|
12602
|
-
return this._userIgnored(
|
|
12801
|
+
return this._userIgnored(path26, stats);
|
|
12603
12802
|
}
|
|
12604
|
-
_isntIgnored(
|
|
12605
|
-
return !this._isIgnored(
|
|
12803
|
+
_isntIgnored(path26, stat4) {
|
|
12804
|
+
return !this._isIgnored(path26, stat4);
|
|
12606
12805
|
}
|
|
12607
12806
|
/**
|
|
12608
12807
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
12609
12808
|
* @param path file or directory pattern being watched
|
|
12610
12809
|
*/
|
|
12611
|
-
_getWatchHelpers(
|
|
12612
|
-
return new WatchHelper(
|
|
12810
|
+
_getWatchHelpers(path26) {
|
|
12811
|
+
return new WatchHelper(path26, this.options.followSymlinks, this);
|
|
12613
12812
|
}
|
|
12614
12813
|
// Directory helpers
|
|
12615
12814
|
// -----------------
|
|
@@ -12641,63 +12840,63 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
12641
12840
|
* @param item base path of item/directory
|
|
12642
12841
|
*/
|
|
12643
12842
|
_remove(directory, item, isDirectory) {
|
|
12644
|
-
const
|
|
12645
|
-
const fullPath = sp2.resolve(
|
|
12646
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
12647
|
-
if (!this._throttle("remove",
|
|
12843
|
+
const path26 = sp2.join(directory, item);
|
|
12844
|
+
const fullPath = sp2.resolve(path26);
|
|
12845
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path26) || this._watched.has(fullPath);
|
|
12846
|
+
if (!this._throttle("remove", path26, 100))
|
|
12648
12847
|
return;
|
|
12649
12848
|
if (!isDirectory && this._watched.size === 1) {
|
|
12650
12849
|
this.add(directory, item, true);
|
|
12651
12850
|
}
|
|
12652
|
-
const wp = this._getWatchedDir(
|
|
12851
|
+
const wp = this._getWatchedDir(path26);
|
|
12653
12852
|
const nestedDirectoryChildren = wp.getChildren();
|
|
12654
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
12853
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path26, nested));
|
|
12655
12854
|
const parent = this._getWatchedDir(directory);
|
|
12656
12855
|
const wasTracked = parent.has(item);
|
|
12657
12856
|
parent.remove(item);
|
|
12658
12857
|
if (this._symlinkPaths.has(fullPath)) {
|
|
12659
12858
|
this._symlinkPaths.delete(fullPath);
|
|
12660
12859
|
}
|
|
12661
|
-
let relPath =
|
|
12860
|
+
let relPath = path26;
|
|
12662
12861
|
if (this.options.cwd)
|
|
12663
|
-
relPath = sp2.relative(this.options.cwd,
|
|
12862
|
+
relPath = sp2.relative(this.options.cwd, path26);
|
|
12664
12863
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
12665
12864
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
12666
12865
|
if (event === EVENTS.ADD)
|
|
12667
12866
|
return;
|
|
12668
12867
|
}
|
|
12669
|
-
this._watched.delete(
|
|
12868
|
+
this._watched.delete(path26);
|
|
12670
12869
|
this._watched.delete(fullPath);
|
|
12671
12870
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
12672
|
-
if (wasTracked && !this._isIgnored(
|
|
12673
|
-
this._emit(eventName,
|
|
12674
|
-
this._closePath(
|
|
12871
|
+
if (wasTracked && !this._isIgnored(path26))
|
|
12872
|
+
this._emit(eventName, path26);
|
|
12873
|
+
this._closePath(path26);
|
|
12675
12874
|
}
|
|
12676
12875
|
/**
|
|
12677
12876
|
* Closes all watchers for a path
|
|
12678
12877
|
*/
|
|
12679
|
-
_closePath(
|
|
12680
|
-
this._closeFile(
|
|
12681
|
-
const dir = sp2.dirname(
|
|
12682
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
12878
|
+
_closePath(path26) {
|
|
12879
|
+
this._closeFile(path26);
|
|
12880
|
+
const dir = sp2.dirname(path26);
|
|
12881
|
+
this._getWatchedDir(dir).remove(sp2.basename(path26));
|
|
12683
12882
|
}
|
|
12684
12883
|
/**
|
|
12685
12884
|
* Closes only file-specific watchers
|
|
12686
12885
|
*/
|
|
12687
|
-
_closeFile(
|
|
12688
|
-
const closers = this._closers.get(
|
|
12886
|
+
_closeFile(path26) {
|
|
12887
|
+
const closers = this._closers.get(path26);
|
|
12689
12888
|
if (!closers)
|
|
12690
12889
|
return;
|
|
12691
12890
|
closers.forEach((closer) => closer());
|
|
12692
|
-
this._closers.delete(
|
|
12891
|
+
this._closers.delete(path26);
|
|
12693
12892
|
}
|
|
12694
|
-
_addPathCloser(
|
|
12893
|
+
_addPathCloser(path26, closer) {
|
|
12695
12894
|
if (!closer)
|
|
12696
12895
|
return;
|
|
12697
|
-
let list = this._closers.get(
|
|
12896
|
+
let list = this._closers.get(path26);
|
|
12698
12897
|
if (!list) {
|
|
12699
12898
|
list = [];
|
|
12700
|
-
this._closers.set(
|
|
12899
|
+
this._closers.set(path26, list);
|
|
12701
12900
|
}
|
|
12702
12901
|
list.push(closer);
|
|
12703
12902
|
}
|
|
@@ -12727,7 +12926,7 @@ function watch(paths, options = {}) {
|
|
|
12727
12926
|
var chokidar_default = { watch, FSWatcher };
|
|
12728
12927
|
|
|
12729
12928
|
// src/watcher/file-watcher.ts
|
|
12730
|
-
import * as
|
|
12929
|
+
import * as path21 from "path";
|
|
12731
12930
|
var FileWatcher = class {
|
|
12732
12931
|
watcher = null;
|
|
12733
12932
|
projectRoot;
|
|
@@ -12753,15 +12952,15 @@ var FileWatcher = class {
|
|
|
12753
12952
|
const watchTargets = this.configPath ? [this.projectRoot, this.configPath] : this.projectRoot;
|
|
12754
12953
|
this.watcher = chokidar_default.watch(watchTargets, {
|
|
12755
12954
|
ignored: (filePath) => {
|
|
12756
|
-
const relativePath =
|
|
12955
|
+
const relativePath = path21.relative(this.projectRoot, filePath);
|
|
12757
12956
|
if (!relativePath) return false;
|
|
12758
12957
|
if (this.isProjectConfigPathOrAncestor(relativePath)) {
|
|
12759
12958
|
return false;
|
|
12760
12959
|
}
|
|
12761
|
-
if (hasFilteredPathSegment(relativePath,
|
|
12960
|
+
if (hasFilteredPathSegment(relativePath, path21.sep)) {
|
|
12762
12961
|
return true;
|
|
12763
12962
|
}
|
|
12764
|
-
if (isRestrictedDirectory(relativePath,
|
|
12963
|
+
if (isRestrictedDirectory(relativePath, path21.sep)) {
|
|
12765
12964
|
return true;
|
|
12766
12965
|
}
|
|
12767
12966
|
if (ignoreFilter.ignores(relativePath)) {
|
|
@@ -12807,24 +13006,24 @@ var FileWatcher = class {
|
|
|
12807
13006
|
this.scheduleFlush();
|
|
12808
13007
|
}
|
|
12809
13008
|
isProjectConfigPath(filePath) {
|
|
12810
|
-
const relativePath =
|
|
12811
|
-
const normalizedRelativePath =
|
|
13009
|
+
const relativePath = path21.relative(this.projectRoot, filePath);
|
|
13010
|
+
const normalizedRelativePath = path21.normalize(relativePath);
|
|
12812
13011
|
return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
|
|
12813
13012
|
}
|
|
12814
13013
|
isProjectConfigPathOrAncestor(relativePath) {
|
|
12815
|
-
const normalizedRelativePath =
|
|
13014
|
+
const normalizedRelativePath = path21.normalize(relativePath);
|
|
12816
13015
|
return this.getProjectConfigRelativePaths().some(
|
|
12817
|
-
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${
|
|
13016
|
+
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path21.sep}`)
|
|
12818
13017
|
);
|
|
12819
13018
|
}
|
|
12820
13019
|
getProjectConfigRelativePaths() {
|
|
12821
13020
|
if (this.configPath) {
|
|
12822
|
-
return [
|
|
13021
|
+
return [path21.normalize(path21.relative(this.projectRoot, this.configPath))];
|
|
12823
13022
|
}
|
|
12824
13023
|
return [
|
|
12825
13024
|
resolveProjectConfigPath(this.projectRoot, this.host),
|
|
12826
13025
|
resolveWritableProjectConfigPath(this.projectRoot, this.host)
|
|
12827
|
-
].map((configPath) =>
|
|
13026
|
+
].map((configPath) => path21.normalize(path21.relative(this.projectRoot, configPath)));
|
|
12828
13027
|
}
|
|
12829
13028
|
scheduleFlush() {
|
|
12830
13029
|
if (this.debounceTimer) {
|
|
@@ -12839,7 +13038,7 @@ var FileWatcher = class {
|
|
|
12839
13038
|
return;
|
|
12840
13039
|
}
|
|
12841
13040
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
12842
|
-
([
|
|
13041
|
+
([path26, type]) => ({ path: path26, type })
|
|
12843
13042
|
);
|
|
12844
13043
|
this.pendingChanges.clear();
|
|
12845
13044
|
try {
|
|
@@ -12866,7 +13065,7 @@ var FileWatcher = class {
|
|
|
12866
13065
|
};
|
|
12867
13066
|
|
|
12868
13067
|
// src/watcher/git-head-watcher.ts
|
|
12869
|
-
import * as
|
|
13068
|
+
import * as path22 from "path";
|
|
12870
13069
|
var GitHeadWatcher = class {
|
|
12871
13070
|
watcher = null;
|
|
12872
13071
|
projectRoot;
|
|
@@ -12888,7 +13087,7 @@ var GitHeadWatcher = class {
|
|
|
12888
13087
|
this.onBranchChange = handler;
|
|
12889
13088
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
12890
13089
|
const headPath = getHeadPath(this.projectRoot);
|
|
12891
|
-
const refsPath =
|
|
13090
|
+
const refsPath = path22.join(this.projectRoot, ".git", "refs", "heads");
|
|
12892
13091
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
12893
13092
|
persistent: true,
|
|
12894
13093
|
ignoreInitial: true,
|
|
@@ -13032,7 +13231,7 @@ function getConfigPaths(projectRoot, host, options) {
|
|
|
13032
13231
|
|
|
13033
13232
|
// src/tools/visualize/activity.ts
|
|
13034
13233
|
import { execFileSync } from "child_process";
|
|
13035
|
-
import * as
|
|
13234
|
+
import * as path23 from "path";
|
|
13036
13235
|
function attachRecentActivity(data, projectRoot) {
|
|
13037
13236
|
const activity = readGitActivity(projectRoot);
|
|
13038
13237
|
const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
|
|
@@ -13194,7 +13393,7 @@ function normalizePath3(filePath) {
|
|
|
13194
13393
|
return filePath.replace(/\\/g, "/");
|
|
13195
13394
|
}
|
|
13196
13395
|
function toGitRelativePath(projectRoot, filePath) {
|
|
13197
|
-
const relativePath =
|
|
13396
|
+
const relativePath = path23.isAbsolute(filePath) ? path23.relative(projectRoot, filePath) : filePath;
|
|
13198
13397
|
return normalizePath3(relativePath);
|
|
13199
13398
|
}
|
|
13200
13399
|
|
|
@@ -13452,7 +13651,7 @@ render();
|
|
|
13452
13651
|
}
|
|
13453
13652
|
|
|
13454
13653
|
// src/tools/visualize/transform.ts
|
|
13455
|
-
import * as
|
|
13654
|
+
import * as path24 from "path";
|
|
13456
13655
|
|
|
13457
13656
|
// src/tools/visualize/modules.ts
|
|
13458
13657
|
var MAX_MODULES = 18;
|
|
@@ -13585,8 +13784,8 @@ function compactModules(prefixToNodes) {
|
|
|
13585
13784
|
function deriveModules(nodes) {
|
|
13586
13785
|
const initial = /* @__PURE__ */ new Map();
|
|
13587
13786
|
for (const node of nodes) {
|
|
13588
|
-
const
|
|
13589
|
-
const prefix = modulePrefixFromRelativePath(
|
|
13787
|
+
const relative11 = stripToProjectRelative(node.filePath);
|
|
13788
|
+
const prefix = modulePrefixFromRelativePath(relative11);
|
|
13590
13789
|
if (!initial.has(prefix)) initial.set(prefix, []);
|
|
13591
13790
|
initial.get(prefix)?.push(node);
|
|
13592
13791
|
}
|
|
@@ -13712,7 +13911,7 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
13712
13911
|
filePath: s.filePath,
|
|
13713
13912
|
kind: s.kind,
|
|
13714
13913
|
line: s.startLine,
|
|
13715
|
-
directory:
|
|
13914
|
+
directory: path24.dirname(s.filePath),
|
|
13716
13915
|
moduleId: "",
|
|
13717
13916
|
moduleLabel: ""
|
|
13718
13917
|
}));
|
|
@@ -13740,9 +13939,9 @@ function parseArgs(argv) {
|
|
|
13740
13939
|
let host = "opencode";
|
|
13741
13940
|
for (let i = 2; i < argv.length; i++) {
|
|
13742
13941
|
if (argv[i] === "--project" && argv[i + 1]) {
|
|
13743
|
-
project =
|
|
13942
|
+
project = path25.resolve(argv[++i]);
|
|
13744
13943
|
} else if (argv[i] === "--config" && argv[i + 1]) {
|
|
13745
|
-
config =
|
|
13944
|
+
config = path25.resolve(argv[++i]);
|
|
13746
13945
|
} else if (argv[i] === "--host" && argv[i + 1]) {
|
|
13747
13946
|
host = parseHostMode(argv[++i]);
|
|
13748
13947
|
} else if (argv[i] === "--host") {
|
|
@@ -13765,7 +13964,7 @@ function parseVisualizeArgs(argv, cwd) {
|
|
|
13765
13964
|
for (let i = 0; i < argv.length; i++) {
|
|
13766
13965
|
const arg = argv[i];
|
|
13767
13966
|
if (arg === "--project" && argv[i + 1]) {
|
|
13768
|
-
project =
|
|
13967
|
+
project = path25.resolve(argv[++i]);
|
|
13769
13968
|
} else if (arg === "--max" && argv[i + 1]) {
|
|
13770
13969
|
maxNodes = Number(argv[++i]);
|
|
13771
13970
|
} else if (arg.startsWith("--max=") || arg.startsWith("max=")) {
|
|
@@ -13802,7 +14001,7 @@ async function handleVisualizeCommand(argv, cwd) {
|
|
|
13802
14001
|
console.error("No connected symbols found. Retry with: npm run visualize -- orphans");
|
|
13803
14002
|
return 1;
|
|
13804
14003
|
}
|
|
13805
|
-
const outputPath =
|
|
14004
|
+
const outputPath = path25.join(os5.tmpdir(), `call-graph-${Date.now()}.html`);
|
|
13806
14005
|
writeFileSync6(outputPath, generateVisualizationHtml(vizData), "utf-8");
|
|
13807
14006
|
console.log(`Temporal call graph visualization generated: ${outputPath}`);
|
|
13808
14007
|
console.log(`Nodes: ${vizData.nodes.length} | Edges: ${vizData.edges.length}`);
|
|
@@ -13832,7 +14031,7 @@ async function main() {
|
|
|
13832
14031
|
const transport = new StdioServerTransport();
|
|
13833
14032
|
await server.connect(transport);
|
|
13834
14033
|
let watcher = null;
|
|
13835
|
-
const isHomeDir =
|
|
14034
|
+
const isHomeDir = path25.resolve(args.project) === path25.resolve(os5.homedir());
|
|
13836
14035
|
const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(args.project));
|
|
13837
14036
|
if (config.indexing.autoIndex && isValidProject) {
|
|
13838
14037
|
const indexer = getIndexerForProject(args.project, args.host);
|