token-goat 2.8.4 → 2.9.1
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/README.md +20 -8
- package/dist/{token-goat-chunk-NZFTWBGV.mjs → token-goat-chunk-4KD2N46D.mjs} +28 -27
- package/dist/{token-goat-chunk-CZALRRGN.mjs → token-goat-chunk-4ZDRTNGV.mjs} +9942 -95
- package/dist/{token-goat-chunk-L6YP6FKQ.mjs → token-goat-chunk-AUM22UQ2.mjs} +5 -5
- package/dist/{token-goat-chunk-LZOAPGWR.mjs → token-goat-chunk-CD6U5OD6.mjs} +28 -4
- package/dist/{token-goat-chunk-4OTIB7SB.mjs → token-goat-chunk-FDXINYK4.mjs} +2120 -3658
- package/dist/token-goat-chunk-LHMC5ENL.mjs +79 -0
- package/dist/{token-goat-chunk-IZRXU64B.mjs → token-goat-chunk-MR7MNSDR.mjs} +155 -517
- package/dist/{token-goat-chunk-ZQ3PUOP3.mjs → token-goat-chunk-RRNRPCLX.mjs} +167 -116
- package/dist/{token-goat-chunk-U4UI5F3S.mjs → token-goat-chunk-SQSB5P5P.mjs} +842 -368
- package/dist/{token-goat-chunk-RE7S7H26.mjs → token-goat-chunk-SXSWQMNP.mjs} +512 -206
- package/dist/{token-goat-chunk-HNODKNWO.mjs → token-goat-chunk-V5T3YNYR.mjs} +5 -5
- package/dist/token-goat-hook.mjs +5 -5
- package/dist/token-goat.core.mjs +5 -5
- package/package.json +1 -1
- package/dist/token-goat-chunk-E76UNTVK.mjs +0 -7133
|
@@ -23,10 +23,13 @@ import {
|
|
|
23
23
|
extractPdfMeta,
|
|
24
24
|
extractPdfOutline,
|
|
25
25
|
extractPdfText,
|
|
26
|
+
fenceUntrusted,
|
|
26
27
|
fenceUntrustedContent,
|
|
27
28
|
formatCsvProfile,
|
|
28
29
|
formatCsvTable,
|
|
30
|
+
getEmbeddingCoverage,
|
|
29
31
|
getFileEntry,
|
|
32
|
+
getTrackedFiles,
|
|
30
33
|
indexFileSync,
|
|
31
34
|
isAvailable,
|
|
32
35
|
isBlobStale,
|
|
@@ -49,7 +52,7 @@ import {
|
|
|
49
52
|
queryRefs,
|
|
50
53
|
queryRefsByContext,
|
|
51
54
|
querySymbols,
|
|
52
|
-
|
|
55
|
+
scanAndRecord,
|
|
53
56
|
searchEvidenceSemantically,
|
|
54
57
|
searchSemantic,
|
|
55
58
|
searchSymbolsFts,
|
|
@@ -64,7 +67,7 @@ import {
|
|
|
64
67
|
walkProject,
|
|
65
68
|
yamlLineClosesQuote,
|
|
66
69
|
yamlOpenQuoteAfter
|
|
67
|
-
} from "./token-goat-chunk-
|
|
70
|
+
} from "./token-goat-chunk-FDXINYK4.mjs";
|
|
68
71
|
import {
|
|
69
72
|
Database,
|
|
70
73
|
PER_FILE_COUNTERFACTUAL_CEILING,
|
|
@@ -118,36 +121,11 @@ import {
|
|
|
118
121
|
unsupportedLanguageName,
|
|
119
122
|
windowsCmdQuoteArg,
|
|
120
123
|
withExtension
|
|
121
|
-
} from "./token-goat-chunk-
|
|
124
|
+
} from "./token-goat-chunk-4ZDRTNGV.mjs";
|
|
122
125
|
import {
|
|
123
126
|
registerReset
|
|
124
127
|
} from "./token-goat-chunk-AO2QD2AG.mjs";
|
|
125
128
|
|
|
126
|
-
// src/repomap.ts
|
|
127
|
-
import * as fs from "fs";
|
|
128
|
-
import * as path from "path";
|
|
129
|
-
function getTrackedFiles(cwd = process.cwd()) {
|
|
130
|
-
try {
|
|
131
|
-
let dir = cwd;
|
|
132
|
-
let onlyFile = "";
|
|
133
|
-
try {
|
|
134
|
-
if (fs.statSync(cwd).isFile()) {
|
|
135
|
-
dir = path.dirname(cwd);
|
|
136
|
-
onlyFile = path.basename(cwd);
|
|
137
|
-
}
|
|
138
|
-
} catch {
|
|
139
|
-
}
|
|
140
|
-
const args = onlyFile === "" ? ["ls-files"] : ["ls-files", "--error-unmatch", "--", onlyFile];
|
|
141
|
-
const result = runGit(args, { cwd: dir });
|
|
142
|
-
if (result.exitCode !== 0 || !result.stdout) {
|
|
143
|
-
return [];
|
|
144
|
-
}
|
|
145
|
-
return result.stdout.split("\n").filter((line) => line.trim().length > 0).map((rel) => path.join(dir, rel));
|
|
146
|
-
} catch {
|
|
147
|
-
return [];
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
129
|
// src/section_reader.ts
|
|
152
130
|
import { readFileSync } from "node:fs";
|
|
153
131
|
function parseHeadingSpec(spec, headers) {
|
|
@@ -475,8 +453,8 @@ import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
|
475
453
|
import { randomUUID } from "node:crypto";
|
|
476
454
|
|
|
477
455
|
// src/read_commands.ts
|
|
478
|
-
import * as
|
|
479
|
-
import * as
|
|
456
|
+
import * as fs4 from "node:fs";
|
|
457
|
+
import * as path4 from "node:path";
|
|
480
458
|
|
|
481
459
|
// src/json_query.ts
|
|
482
460
|
function jsonType(value) {
|
|
@@ -3442,11 +3420,11 @@ var CHOMPING_STRIP = CHOMPING_MODE.STRIP;
|
|
|
3442
3420
|
var CHOMPING_KEEP = CHOMPING_MODE.KEEP;
|
|
3443
3421
|
|
|
3444
3422
|
// src/openapi_query.ts
|
|
3445
|
-
import * as
|
|
3423
|
+
import * as path from "node:path";
|
|
3446
3424
|
var HTTP_METHODS = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
|
|
3447
3425
|
function parseOpenApiSpec(text, filePath) {
|
|
3448
3426
|
text = stripBom(text);
|
|
3449
|
-
const ext =
|
|
3427
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
3450
3428
|
if (ext === ".yaml" || ext === ".yml") return load(text);
|
|
3451
3429
|
if (ext === ".json") return JSON.parse(text);
|
|
3452
3430
|
try {
|
|
@@ -3800,24 +3778,24 @@ ${c.body}`).join("\n\n");
|
|
|
3800
3778
|
}
|
|
3801
3779
|
|
|
3802
3780
|
// src/sqlite_query.ts
|
|
3803
|
-
import * as
|
|
3781
|
+
import * as fs from "node:fs";
|
|
3804
3782
|
var SQLITE_QUERY_ROW_CAP = 5e3;
|
|
3805
3783
|
var SQLITE_MAGIC = Buffer.from([83, 81, 76, 105, 116, 101, 32, 102, 111, 114, 109, 97, 116, 32, 51, 0]);
|
|
3806
3784
|
function readMagicBytes(filePath) {
|
|
3807
3785
|
let fd;
|
|
3808
3786
|
try {
|
|
3809
|
-
fd =
|
|
3787
|
+
fd = fs.openSync(filePath, "r");
|
|
3810
3788
|
} catch {
|
|
3811
3789
|
return null;
|
|
3812
3790
|
}
|
|
3813
3791
|
try {
|
|
3814
3792
|
const buf = Buffer.alloc(SQLITE_MAGIC.length);
|
|
3815
|
-
const bytesRead =
|
|
3793
|
+
const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);
|
|
3816
3794
|
return bytesRead === buf.length ? buf : null;
|
|
3817
3795
|
} catch {
|
|
3818
3796
|
return null;
|
|
3819
3797
|
} finally {
|
|
3820
|
-
|
|
3798
|
+
fs.closeSync(fd);
|
|
3821
3799
|
}
|
|
3822
3800
|
}
|
|
3823
3801
|
function isSqliteFile(filePath) {
|
|
@@ -3825,7 +3803,7 @@ function isSqliteFile(filePath) {
|
|
|
3825
3803
|
return magic !== null && magic.equals(SQLITE_MAGIC);
|
|
3826
3804
|
}
|
|
3827
3805
|
function openReadonlySqlite(filePath) {
|
|
3828
|
-
if (!
|
|
3806
|
+
if (!fs.existsSync(filePath)) {
|
|
3829
3807
|
throw new Error(`file not found: ${filePath}`);
|
|
3830
3808
|
}
|
|
3831
3809
|
if (!isSqliteFile(filePath)) {
|
|
@@ -4528,8 +4506,8 @@ function formatConflictSummaries(summaries) {
|
|
|
4528
4506
|
|
|
4529
4507
|
// src/screenshot.ts
|
|
4530
4508
|
import dns from "node:dns/promises";
|
|
4531
|
-
import
|
|
4532
|
-
import
|
|
4509
|
+
import fs2 from "node:fs";
|
|
4510
|
+
import path2 from "node:path";
|
|
4533
4511
|
var loadPuppeteer = createLazyModuleLoader(
|
|
4534
4512
|
async () => await import("puppeteer-core"),
|
|
4535
4513
|
"screenshot disabled (puppeteer-core unavailable)"
|
|
@@ -4538,7 +4516,7 @@ var PLAYWRIGHT_CHROME_SUBDIRS = ["chrome-win64", "chrome-win"];
|
|
|
4538
4516
|
function findPlaywrightChromium(msPlaywrightDir) {
|
|
4539
4517
|
let entries;
|
|
4540
4518
|
try {
|
|
4541
|
-
entries =
|
|
4519
|
+
entries = fs2.readdirSync(msPlaywrightDir);
|
|
4542
4520
|
} catch {
|
|
4543
4521
|
return [];
|
|
4544
4522
|
}
|
|
@@ -4546,7 +4524,7 @@ function findPlaywrightChromium(msPlaywrightDir) {
|
|
|
4546
4524
|
const candidates = [];
|
|
4547
4525
|
for (const m of versioned) {
|
|
4548
4526
|
for (const sub of PLAYWRIGHT_CHROME_SUBDIRS) {
|
|
4549
|
-
candidates.push(
|
|
4527
|
+
candidates.push(path2.join(msPlaywrightDir, m[0], sub, "chrome.exe"));
|
|
4550
4528
|
}
|
|
4551
4529
|
}
|
|
4552
4530
|
return candidates;
|
|
@@ -4557,33 +4535,33 @@ function platformCandidatePaths() {
|
|
|
4557
4535
|
const programFiles = process.env["PROGRAMFILES"];
|
|
4558
4536
|
const programFilesX86 = process.env["PROGRAMFILES(X86)"];
|
|
4559
4537
|
const localAppData = process.env["LOCALAPPDATA"];
|
|
4560
|
-
if (programFiles) candidates2.push(
|
|
4561
|
-
if (programFilesX86) candidates2.push(
|
|
4538
|
+
if (programFiles) candidates2.push(path2.join(programFiles, "Google", "Chrome", "Application", "chrome.exe"));
|
|
4539
|
+
if (programFilesX86) candidates2.push(path2.join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe"));
|
|
4562
4540
|
if (localAppData) {
|
|
4563
|
-
candidates2.push(
|
|
4564
|
-
candidates2.push(...findPlaywrightChromium(
|
|
4541
|
+
candidates2.push(path2.join(localAppData, "Google", "Chrome", "Application", "chrome.exe"));
|
|
4542
|
+
candidates2.push(...findPlaywrightChromium(path2.join(localAppData, "ms-playwright")));
|
|
4565
4543
|
}
|
|
4566
4544
|
return candidates2;
|
|
4567
4545
|
}
|
|
4568
4546
|
if (process.platform === "darwin") {
|
|
4569
4547
|
const home2 = process.env["HOME"];
|
|
4570
4548
|
const candidates2 = ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"];
|
|
4571
|
-
if (home2) candidates2.push(...findPlaywrightChromium(
|
|
4549
|
+
if (home2) candidates2.push(...findPlaywrightChromium(path2.join(home2, "Library", "Caches", "ms-playwright")));
|
|
4572
4550
|
return candidates2;
|
|
4573
4551
|
}
|
|
4574
4552
|
const home = process.env["HOME"];
|
|
4575
4553
|
const candidates = ["/usr/bin/google-chrome-stable", "/usr/bin/google-chrome", "/usr/bin/chromium-browser", "/usr/bin/chromium"];
|
|
4576
|
-
if (home) candidates.push(...findPlaywrightChromium(
|
|
4554
|
+
if (home) candidates.push(...findPlaywrightChromium(path2.join(home, ".cache", "ms-playwright")));
|
|
4577
4555
|
return candidates;
|
|
4578
4556
|
}
|
|
4579
4557
|
function resolveBrowserExecutablePath(explicit) {
|
|
4580
|
-
if (explicit &&
|
|
4558
|
+
if (explicit && fs2.existsSync(explicit)) return explicit;
|
|
4581
4559
|
const cfgPath = loadConfig().screenshot.chrome_path;
|
|
4582
|
-
if (cfgPath &&
|
|
4560
|
+
if (cfgPath && fs2.existsSync(cfgPath)) return cfgPath;
|
|
4583
4561
|
const envPath = process.env["TOKEN_GOAT_CHROME_PATH"];
|
|
4584
|
-
if (envPath &&
|
|
4562
|
+
if (envPath && fs2.existsSync(envPath)) return envPath;
|
|
4585
4563
|
for (const candidate of platformCandidatePaths()) {
|
|
4586
|
-
if (
|
|
4564
|
+
if (fs2.existsSync(candidate)) return candidate;
|
|
4587
4565
|
}
|
|
4588
4566
|
return null;
|
|
4589
4567
|
}
|
|
@@ -4890,7 +4868,7 @@ async function takeScreenshot(url, destPath, opts) {
|
|
|
4890
4868
|
}
|
|
4891
4869
|
|
|
4892
4870
|
// src/notes.ts
|
|
4893
|
-
import * as
|
|
4871
|
+
import * as fs3 from "node:fs";
|
|
4894
4872
|
var WHOLE_FILE_NOTE_SYMBOL = "";
|
|
4895
4873
|
function toNoteRow(row) {
|
|
4896
4874
|
return {
|
|
@@ -4915,7 +4893,7 @@ function resolveSymbolMatch(filePath, symbolName, dbPath = globalDbPath()) {
|
|
|
4915
4893
|
}
|
|
4916
4894
|
function bodyFromSource(entry) {
|
|
4917
4895
|
try {
|
|
4918
|
-
return
|
|
4896
|
+
return fs3.readFileSync(entry.filePath, "utf8").split(/\r?\n/).slice(Math.max(0, entry.lineStart - 1), entry.lineEnd).join("\n");
|
|
4919
4897
|
} catch {
|
|
4920
4898
|
return "";
|
|
4921
4899
|
}
|
|
@@ -4966,7 +4944,7 @@ function isNoteStale(note, dbPath = globalDbPath()) {
|
|
|
4966
4944
|
|
|
4967
4945
|
// src/ts_refs.ts
|
|
4968
4946
|
import { createRequire } from "node:module";
|
|
4969
|
-
import * as
|
|
4947
|
+
import * as path3 from "node:path";
|
|
4970
4948
|
var _require = createRequire(import.meta.url);
|
|
4971
4949
|
var MAX_CANDIDATE_FILES = 50;
|
|
4972
4950
|
var _ts = null;
|
|
@@ -4997,7 +4975,7 @@ registerReset(() => {
|
|
|
4997
4975
|
var TS_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts"]);
|
|
4998
4976
|
var TS_JS_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
4999
4977
|
function isTsPath(filePath) {
|
|
5000
|
-
return TS_EXTENSIONS.has(
|
|
4978
|
+
return TS_EXTENSIONS.has(path3.extname(filePath).toLowerCase());
|
|
5001
4979
|
}
|
|
5002
4980
|
function resolveTypedRefs(input) {
|
|
5003
4981
|
const ts = loadTs();
|
|
@@ -5027,7 +5005,7 @@ function resolveTypedRefs(input) {
|
|
|
5027
5005
|
if (defSymbol === null) return null;
|
|
5028
5006
|
const out = [];
|
|
5029
5007
|
for (const ref of input.candidates) {
|
|
5030
|
-
if (!TS_JS_EXTENSIONS.has(
|
|
5008
|
+
if (!TS_JS_EXTENSIONS.has(path3.extname(ref.filePath).toLowerCase())) {
|
|
5031
5009
|
out.push(ref);
|
|
5032
5010
|
continue;
|
|
5033
5011
|
}
|
|
@@ -5053,12 +5031,12 @@ function buildScopedProgram(ts, rootNames, searchFrom) {
|
|
|
5053
5031
|
resolveJsonModule: true,
|
|
5054
5032
|
esModuleInterop: true
|
|
5055
5033
|
};
|
|
5056
|
-
const configPath = ts.findConfigFile(
|
|
5034
|
+
const configPath = ts.findConfigFile(path3.dirname(searchFrom), ts.sys.fileExists, "tsconfig.json");
|
|
5057
5035
|
if (configPath !== void 0) {
|
|
5058
5036
|
try {
|
|
5059
5037
|
const raw = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
5060
5038
|
if (raw.error === void 0) {
|
|
5061
|
-
const parsed = ts.parseJsonConfigFileContent(raw.config, ts.sys,
|
|
5039
|
+
const parsed = ts.parseJsonConfigFileContent(raw.config, ts.sys, path3.dirname(configPath));
|
|
5062
5040
|
Object.assign(options, parsed.options);
|
|
5063
5041
|
}
|
|
5064
5042
|
} catch {
|
|
@@ -5162,7 +5140,7 @@ var STRUCTURED_MISS_MAX_NODES = 2e4;
|
|
|
5162
5140
|
var REFS_TOP_SCAN_LIMIT = 2e4;
|
|
5163
5141
|
function fileExists(p) {
|
|
5164
5142
|
try {
|
|
5165
|
-
|
|
5143
|
+
fs4.statSync(p);
|
|
5166
5144
|
return true;
|
|
5167
5145
|
} catch {
|
|
5168
5146
|
return false;
|
|
@@ -5193,30 +5171,30 @@ function withPinnedReads(pins, fn) {
|
|
|
5193
5171
|
}
|
|
5194
5172
|
}
|
|
5195
5173
|
function readPinnedBytes(p, pinned) {
|
|
5196
|
-
const fd =
|
|
5174
|
+
const fd = fs4.openSync(p, fs4.constants.O_RDONLY);
|
|
5197
5175
|
try {
|
|
5198
|
-
const actual = fileIdentity(
|
|
5176
|
+
const actual = fileIdentity(fs4.fstatSync(fd, { bigint: true }));
|
|
5199
5177
|
if (actual !== pinned) {
|
|
5200
5178
|
throw new ConfinementIdentityError(
|
|
5201
5179
|
`refused: "${p}" changed identity between validation and read (validated ${pinned}, opened ${actual}). The file was replaced or redirected after the confinement check, so the read was not performed.`
|
|
5202
5180
|
);
|
|
5203
5181
|
}
|
|
5204
|
-
return
|
|
5182
|
+
return fs4.readFileSync(fd);
|
|
5205
5183
|
} finally {
|
|
5206
|
-
|
|
5184
|
+
fs4.closeSync(fd);
|
|
5207
5185
|
}
|
|
5208
5186
|
}
|
|
5209
5187
|
function verifyPinnedIdentity(p, pinned) {
|
|
5210
|
-
const fd =
|
|
5188
|
+
const fd = fs4.openSync(p, fs4.constants.O_RDONLY);
|
|
5211
5189
|
try {
|
|
5212
|
-
const actual = fileIdentity(
|
|
5190
|
+
const actual = fileIdentity(fs4.fstatSync(fd, { bigint: true }));
|
|
5213
5191
|
if (actual !== pinned) {
|
|
5214
5192
|
throw new ConfinementIdentityError(
|
|
5215
5193
|
`refused: "${p}" changed identity between validation and read (validated ${pinned}, opened ${actual}). The file was replaced or redirected after the confinement check, so the read was not performed.`
|
|
5216
5194
|
);
|
|
5217
5195
|
}
|
|
5218
5196
|
} finally {
|
|
5219
|
-
|
|
5197
|
+
fs4.closeSync(fd);
|
|
5220
5198
|
}
|
|
5221
5199
|
}
|
|
5222
5200
|
function verifyStillAbsent(p) {
|
|
@@ -5234,7 +5212,7 @@ function verifyPin(p, pinned) {
|
|
|
5234
5212
|
verifyPinnedIdentity(p, pinned);
|
|
5235
5213
|
}
|
|
5236
5214
|
function indexFileSyncPinned(resolvedPath, dbPath) {
|
|
5237
|
-
const pinned = activePins?.get(pinKey(
|
|
5215
|
+
const pinned = activePins?.get(pinKey(path4.resolve(resolvedPath)));
|
|
5238
5216
|
if (pinned === void 0) {
|
|
5239
5217
|
indexFileSync(resolvedPath, dbPath);
|
|
5240
5218
|
return;
|
|
@@ -5256,21 +5234,21 @@ function indexFileSyncPinned(resolvedPath, dbPath) {
|
|
|
5256
5234
|
indexFileSync(resolvedPath, dbPath, bytes);
|
|
5257
5235
|
}
|
|
5258
5236
|
function readFileText(p) {
|
|
5259
|
-
const pinned = activePins?.get(pinKey(
|
|
5237
|
+
const pinned = activePins?.get(pinKey(path4.resolve(p)));
|
|
5260
5238
|
try {
|
|
5261
5239
|
if (pinned === ABSENT_PIN) {
|
|
5262
5240
|
verifyStillAbsent(p);
|
|
5263
5241
|
return null;
|
|
5264
5242
|
}
|
|
5265
5243
|
if (pinned !== void 0) return redactIfDotenv(p, decodeSource(readPinnedBytes(p, pinned)));
|
|
5266
|
-
return redactIfDotenv(p, decodeSource(
|
|
5244
|
+
return redactIfDotenv(p, decodeSource(fs4.readFileSync(p)));
|
|
5267
5245
|
} catch (err) {
|
|
5268
5246
|
if (err instanceof ConfinementIdentityError) throw err;
|
|
5269
5247
|
return null;
|
|
5270
5248
|
}
|
|
5271
5249
|
}
|
|
5272
5250
|
function readFileBytes(p) {
|
|
5273
|
-
const pinned = activePins?.get(pinKey(
|
|
5251
|
+
const pinned = activePins?.get(pinKey(path4.resolve(p)));
|
|
5274
5252
|
try {
|
|
5275
5253
|
if (pinned === ABSENT_PIN) {
|
|
5276
5254
|
verifyStillAbsent(p);
|
|
@@ -5281,9 +5259,9 @@ function readFileBytes(p) {
|
|
|
5281
5259
|
if (bytes.length > MAX_ZIP_INPUT_BYTES) throw new ZipInputTooLargeError(p, bytes.length, MAX_ZIP_INPUT_BYTES);
|
|
5282
5260
|
return bytes;
|
|
5283
5261
|
}
|
|
5284
|
-
const stat =
|
|
5262
|
+
const stat = fs4.statSync(p);
|
|
5285
5263
|
if (stat.size > MAX_ZIP_INPUT_BYTES) throw new ZipInputTooLargeError(p, stat.size, MAX_ZIP_INPUT_BYTES);
|
|
5286
|
-
return
|
|
5264
|
+
return fs4.readFileSync(p);
|
|
5287
5265
|
} catch (err) {
|
|
5288
5266
|
if (err instanceof ConfinementIdentityError || err instanceof ZipInputTooLargeError) throw err;
|
|
5289
5267
|
return null;
|
|
@@ -5302,7 +5280,7 @@ var STALE_WARNING = "\u26A0 STALE: index is older than the file on disk (worker
|
|
|
5302
5280
|
var DELETED_WARNING = "\u26A0 DELETED: this file is no longer on disk \u2014 what follows is what the index last saw of it";
|
|
5303
5281
|
var DELETED_TAG = "\u26A0 DELETED: file no longer on disk";
|
|
5304
5282
|
function fileIsGone(absPath) {
|
|
5305
|
-
if (!
|
|
5283
|
+
if (!path4.isAbsolute(absPath)) return false;
|
|
5306
5284
|
return fileIsAbsent(absPath);
|
|
5307
5285
|
}
|
|
5308
5286
|
function staleWarning(resolvedPath) {
|
|
@@ -5353,15 +5331,12 @@ function guardText(text, command) {
|
|
|
5353
5331
|
const cfg = loadConfig();
|
|
5354
5332
|
return cfg.overflow_guard.enabled ? trimToBudget(text, cfg.overflow_guard.max_tokens, command) : text;
|
|
5355
5333
|
}
|
|
5356
|
-
function
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
matches = [];
|
|
5362
|
-
}
|
|
5334
|
+
function fenceGithubText(text) {
|
|
5335
|
+
return fenceUntrusted(text, UNTRUSTED_GITHUB_TAG);
|
|
5336
|
+
}
|
|
5337
|
+
function fenceGithubFieldIfMatched(text) {
|
|
5338
|
+
const matches = scanAndRecord(text);
|
|
5363
5339
|
if (matches.length === 0) return text;
|
|
5364
|
-
recordStat("injection_detected", 0, 0, void 0, matches.join(","));
|
|
5365
5340
|
return fenceUntrustedContent(text, matches, UNTRUSTED_GITHUB_TAG);
|
|
5366
5341
|
}
|
|
5367
5342
|
function guardJsonRows(items) {
|
|
@@ -5373,12 +5348,18 @@ function sumFileSizes(filePaths) {
|
|
|
5373
5348
|
let total = 0;
|
|
5374
5349
|
for (const fp of new Set(filePaths)) {
|
|
5375
5350
|
try {
|
|
5376
|
-
total += Math.min(
|
|
5351
|
+
total += Math.min(fs4.statSync(fp).size, PER_FILE_COUNTERFACTUAL_CEILING);
|
|
5377
5352
|
} catch {
|
|
5378
5353
|
}
|
|
5379
5354
|
}
|
|
5380
5355
|
return total;
|
|
5381
5356
|
}
|
|
5357
|
+
function refsSearchBaselineBytes(rows) {
|
|
5358
|
+
let total = 0;
|
|
5359
|
+
for (const ref of rows) total += Buffer.byteLength(`${refsDisplayPath(ref.filePath)}:${ref.line}: ${ref.context}
|
|
5360
|
+
`, "utf8");
|
|
5361
|
+
return total;
|
|
5362
|
+
}
|
|
5382
5363
|
function recordReadStat(kind, fullSourceBytes, emittedText, detail) {
|
|
5383
5364
|
const emittedBytes = Buffer.byteLength(emittedText, "utf8");
|
|
5384
5365
|
const bytesSaved = Math.max(1, fullSourceBytes - emittedBytes);
|
|
@@ -5551,7 +5532,7 @@ function findStructuredKeyPath(name, filePaths) {
|
|
|
5551
5532
|
if (!isYaml && !lower.endsWith(".json")) continue;
|
|
5552
5533
|
let size;
|
|
5553
5534
|
try {
|
|
5554
|
-
size =
|
|
5535
|
+
size = fs4.statSync(filePath).size;
|
|
5555
5536
|
} catch {
|
|
5556
5537
|
continue;
|
|
5557
5538
|
}
|
|
@@ -6089,7 +6070,7 @@ ${sub.text}`);
|
|
|
6089
6070
|
return { text, code: 1 };
|
|
6090
6071
|
}
|
|
6091
6072
|
function resolveAgainstProjectRoot(file, projectRoot) {
|
|
6092
|
-
return projectRoot !== void 0 && !
|
|
6073
|
+
return projectRoot !== void 0 && !path4.isAbsolute(file) ? path4.resolve(projectRoot, file) : file;
|
|
6093
6074
|
}
|
|
6094
6075
|
function literalHeadingExists(filePath, heading) {
|
|
6095
6076
|
const ordinalMatch = /^([^#\r\n]+)#(\d+)$/.exec(heading);
|
|
@@ -6113,7 +6094,7 @@ function runSection(opts) {
|
|
|
6113
6094
|
}
|
|
6114
6095
|
const result = readSection(filePath, heading, readFileText);
|
|
6115
6096
|
if (result === null) {
|
|
6116
|
-
if (!
|
|
6097
|
+
if (!fs4.existsSync(filePath)) {
|
|
6117
6098
|
return { text: `File not found: '${filePath}'`, code: 1 };
|
|
6118
6099
|
}
|
|
6119
6100
|
const ordSpec = /^(.*?)#(\d+)$/.exec(heading);
|
|
@@ -6200,7 +6181,7 @@ function runSectionCrossFile(pairs, opts) {
|
|
|
6200
6181
|
textBlocks.push(`${key}:
|
|
6201
6182
|
${sub.text}`);
|
|
6202
6183
|
}
|
|
6203
|
-
const resolvePath = (f) => opts.projectRoot !== void 0 && !
|
|
6184
|
+
const resolvePath = (f) => opts.projectRoot !== void 0 && !path4.isAbsolute(f) ? path4.resolve(opts.projectRoot, f) : f;
|
|
6204
6185
|
const text = opts.json === true ? JSON.stringify(jsonOut, null, 2) : textBlocks.join("\n\n");
|
|
6205
6186
|
if (anyFound) {
|
|
6206
6187
|
const fullSourceBytes = sumFileSizes(Array.from(distinctFiles, resolvePath));
|
|
@@ -6273,7 +6254,7 @@ function renderRefsTargets(targets, opts, {
|
|
|
6273
6254
|
const jsonOut = {};
|
|
6274
6255
|
let anyFound = false;
|
|
6275
6256
|
const lines = [];
|
|
6276
|
-
const
|
|
6257
|
+
const refRows = [];
|
|
6277
6258
|
for (const { file, symbol, key } of targets) {
|
|
6278
6259
|
const queryOpts = { name: symbol };
|
|
6279
6260
|
if (opts.excludeTests === true || opts.grep !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
|
|
@@ -6299,7 +6280,7 @@ function renderRefsTargets(targets, opts, {
|
|
|
6299
6280
|
results = results.slice(0, opts.limit ?? 100);
|
|
6300
6281
|
}
|
|
6301
6282
|
if (results.length > 0) anyFound = true;
|
|
6302
|
-
|
|
6283
|
+
refRows.push(...results);
|
|
6303
6284
|
if (opts.json === true) {
|
|
6304
6285
|
const hiddenByGrep = matchesGrep !== void 0 ? preGrepCount - (filteredTotal ?? results.length) : 0;
|
|
6305
6286
|
const withHidden = (payload) => ({ ...payload, ...annotateHiddenByGrep && hiddenByGrep > 0 ? { hiddenByGrep } : {} });
|
|
@@ -6341,7 +6322,7 @@ function renderRefsTargets(targets, opts, {
|
|
|
6341
6322
|
if (notice !== null) lines.push(` token-goat: ${notice}`);
|
|
6342
6323
|
}
|
|
6343
6324
|
}
|
|
6344
|
-
const fullSourceBytes =
|
|
6325
|
+
const fullSourceBytes = refsSearchBaselineBytes(refRows);
|
|
6345
6326
|
if (opts.json === true) {
|
|
6346
6327
|
const text2 = JSON.stringify(jsonOut, null, 2);
|
|
6347
6328
|
emit(text2);
|
|
@@ -6450,7 +6431,7 @@ function runRefsSingle(opts) {
|
|
|
6450
6431
|
}
|
|
6451
6432
|
return 1;
|
|
6452
6433
|
}
|
|
6453
|
-
const fullSourceBytes =
|
|
6434
|
+
const fullSourceBytes = refsSearchBaselineBytes(results);
|
|
6454
6435
|
if (opts.json === true) {
|
|
6455
6436
|
let payload;
|
|
6456
6437
|
if (opts.top !== void 0) {
|
|
@@ -6523,7 +6504,7 @@ function renderCallerGroups(refs, contextLines = 0) {
|
|
|
6523
6504
|
return lines;
|
|
6524
6505
|
}
|
|
6525
6506
|
function noSymbolsMessage(displayPath, resolvedPath) {
|
|
6526
|
-
if (!
|
|
6507
|
+
if (!fs4.existsSync(resolvedPath)) {
|
|
6527
6508
|
return `Could not read: ${displayPath}`;
|
|
6528
6509
|
}
|
|
6529
6510
|
const lang = unsupportedLanguageName(resolvedPath);
|
|
@@ -7217,11 +7198,11 @@ function runPrSlice(opts) {
|
|
|
7217
7198
|
}
|
|
7218
7199
|
const fullSourceBytes = Buffer.byteLength(diffText, "utf8");
|
|
7219
7200
|
if (opts.json === true) {
|
|
7220
|
-
const jsonText = JSON.stringify({ path: parsed.path, diff:
|
|
7201
|
+
const jsonText = JSON.stringify({ path: parsed.path, diff: fenceGithubFieldIfMatched(fileDiff) });
|
|
7221
7202
|
emit(jsonText);
|
|
7222
7203
|
recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} diff:${parsed.path}`);
|
|
7223
7204
|
} else {
|
|
7224
|
-
emitGuarded(
|
|
7205
|
+
emitGuarded(fenceGithubText(fileDiff), "pr-slice");
|
|
7225
7206
|
recordReadStat("pr_slice", fullSourceBytes, fileDiff, `${repo}#${opts.pr} diff:${parsed.path}`);
|
|
7226
7207
|
}
|
|
7227
7208
|
return 0;
|
|
@@ -7230,14 +7211,14 @@ function runPrSlice(opts) {
|
|
|
7230
7211
|
const comments = fetchPrComments(opts.pr, repo);
|
|
7231
7212
|
const fullSourceBytes = Buffer.byteLength(JSON.stringify(comments), "utf8");
|
|
7232
7213
|
if (opts.json === true) {
|
|
7233
|
-
const fencedComments = comments.map((c) => ({ ...c, body:
|
|
7214
|
+
const fencedComments = comments.map((c) => ({ ...c, body: fenceGithubFieldIfMatched(c.body) }));
|
|
7234
7215
|
const capped = guardJsonRows(fencedComments);
|
|
7235
7216
|
const jsonText = JSON.stringify({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
|
|
7236
7217
|
emit(jsonText);
|
|
7237
7218
|
recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} comments`);
|
|
7238
7219
|
} else {
|
|
7239
7220
|
const text = formatCommentsSlice(comments);
|
|
7240
|
-
emitGuarded(
|
|
7221
|
+
emitGuarded(fenceGithubText(text), "pr-slice");
|
|
7241
7222
|
recordReadStat("pr_slice", fullSourceBytes, text, `${repo}#${opts.pr} comments`);
|
|
7242
7223
|
}
|
|
7243
7224
|
return 0;
|
|
@@ -7248,15 +7229,15 @@ function runPrSlice(opts) {
|
|
|
7248
7229
|
if (opts.json === true) {
|
|
7249
7230
|
const fencedDesc = {
|
|
7250
7231
|
...desc,
|
|
7251
|
-
title:
|
|
7252
|
-
body: desc.body !== null ?
|
|
7232
|
+
title: fenceGithubFieldIfMatched(desc.title),
|
|
7233
|
+
body: desc.body !== null ? fenceGithubFieldIfMatched(desc.body) : null
|
|
7253
7234
|
};
|
|
7254
7235
|
const jsonText = JSON.stringify(fencedDesc);
|
|
7255
7236
|
emit(jsonText);
|
|
7256
7237
|
recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} description`);
|
|
7257
7238
|
} else {
|
|
7258
7239
|
const text = formatDescriptionSlice(desc);
|
|
7259
|
-
emitGuarded(
|
|
7240
|
+
emitGuarded(fenceGithubText(text), "pr-slice");
|
|
7260
7241
|
recordReadStat("pr_slice", fullSourceBytes, text, `${repo}#${opts.pr} description`);
|
|
7261
7242
|
}
|
|
7262
7243
|
return 0;
|
|
@@ -7362,10 +7343,10 @@ function runConflicts(opts) {
|
|
|
7362
7343
|
if (opts.path === void 0) {
|
|
7363
7344
|
files = walkProject(process.cwd()).files;
|
|
7364
7345
|
} else {
|
|
7365
|
-
const abs =
|
|
7346
|
+
const abs = path4.resolve(opts.path);
|
|
7366
7347
|
let stat;
|
|
7367
7348
|
try {
|
|
7368
|
-
stat =
|
|
7349
|
+
stat = fs4.statSync(abs);
|
|
7369
7350
|
} catch {
|
|
7370
7351
|
emitErr(`Could not read: ${opts.path}`);
|
|
7371
7352
|
return 1;
|
|
@@ -7400,7 +7381,7 @@ async function runPdfExtractText(file, pagesSpec, layout = false) {
|
|
|
7400
7381
|
if (!fileExists(file)) {
|
|
7401
7382
|
throw new Error(`Could not read: ${file}`);
|
|
7402
7383
|
}
|
|
7403
|
-
const data =
|
|
7384
|
+
const data = fs4.readFileSync(file);
|
|
7404
7385
|
const result = await extractPdfText(new Uint8Array(data), pagesSpec, layout);
|
|
7405
7386
|
return result.text;
|
|
7406
7387
|
}
|
|
@@ -7408,21 +7389,21 @@ async function runPdfOutline(file) {
|
|
|
7408
7389
|
if (!fileExists(file)) {
|
|
7409
7390
|
throw new Error(`Could not read: ${file}`);
|
|
7410
7391
|
}
|
|
7411
|
-
const data =
|
|
7392
|
+
const data = fs4.readFileSync(file);
|
|
7412
7393
|
return extractPdfOutline(new Uint8Array(data));
|
|
7413
7394
|
}
|
|
7414
7395
|
async function runPdfMeta(file) {
|
|
7415
7396
|
if (!fileExists(file)) {
|
|
7416
7397
|
throw new Error(`Could not read: ${file}`);
|
|
7417
7398
|
}
|
|
7418
|
-
const data =
|
|
7399
|
+
const data = fs4.readFileSync(file);
|
|
7419
7400
|
return extractPdfMeta(new Uint8Array(data));
|
|
7420
7401
|
}
|
|
7421
7402
|
async function runPdfLocate(file, pattern, opts) {
|
|
7422
7403
|
if (!fileExists(file)) {
|
|
7423
7404
|
throw new Error(`Could not read: ${file}`);
|
|
7424
7405
|
}
|
|
7425
|
-
const data =
|
|
7406
|
+
const data = fs4.readFileSync(file);
|
|
7426
7407
|
return locatePdfPages(new Uint8Array(data), pattern, opts);
|
|
7427
7408
|
}
|
|
7428
7409
|
async function runImageMeta(file) {
|
|
@@ -7432,7 +7413,7 @@ async function runImageMeta(file) {
|
|
|
7432
7413
|
if (!isImagePath(file)) {
|
|
7433
7414
|
throw new Error(`Not an image file: ${file}`);
|
|
7434
7415
|
}
|
|
7435
|
-
const data =
|
|
7416
|
+
const data = fs4.readFileSync(file);
|
|
7436
7417
|
const bytes = data.length;
|
|
7437
7418
|
let probe;
|
|
7438
7419
|
try {
|
|
@@ -7464,7 +7445,7 @@ async function runImageText(file) {
|
|
|
7464
7445
|
if (!isImagePath(file)) {
|
|
7465
7446
|
throw new Error(`Not an image file: ${file}`);
|
|
7466
7447
|
}
|
|
7467
|
-
const data =
|
|
7448
|
+
const data = fs4.readFileSync(file);
|
|
7468
7449
|
const ocr = await ocrImage(data);
|
|
7469
7450
|
if (ocr === null) {
|
|
7470
7451
|
if (ocrIntegrityFailed()) {
|
|
@@ -7673,7 +7654,7 @@ function runFind(opts) {
|
|
|
7673
7654
|
}
|
|
7674
7655
|
if (opts.json === true) {
|
|
7675
7656
|
const fuzzyPayload = fuzzyNames.length > 0 ? { fuzzy: true, matchedNames: fuzzyNames } : {};
|
|
7676
|
-
emit(JSON.stringify({ files, truncated, ...fuzzyPayload }, null, 2));
|
|
7657
|
+
emit(JSON.stringify({ files, truncated, totalCount: allFiles.length, ...fuzzyPayload }, null, 2));
|
|
7677
7658
|
return 0;
|
|
7678
7659
|
}
|
|
7679
7660
|
if (fuzzyNames.length > 0) {
|
|
@@ -8168,7 +8149,7 @@ function runGrep(opts) {
|
|
|
8168
8149
|
if (activePins !== null) {
|
|
8169
8150
|
let realDir;
|
|
8170
8151
|
try {
|
|
8171
|
-
realDir = foldRealpath(
|
|
8152
|
+
realDir = foldRealpath(fs4.realpathSync(dir));
|
|
8172
8153
|
} catch {
|
|
8173
8154
|
return;
|
|
8174
8155
|
}
|
|
@@ -8177,12 +8158,12 @@ function runGrep(opts) {
|
|
|
8177
8158
|
visitedRealDirs.add(realDir);
|
|
8178
8159
|
}
|
|
8179
8160
|
try {
|
|
8180
|
-
for (const entry of
|
|
8161
|
+
for (const entry of fs4.readdirSync(dir)) {
|
|
8181
8162
|
if (entry.startsWith(".")) continue;
|
|
8182
|
-
const full =
|
|
8163
|
+
const full = path4.join(dir, entry);
|
|
8183
8164
|
let lst;
|
|
8184
8165
|
try {
|
|
8185
|
-
lst =
|
|
8166
|
+
lst = fs4.lstatSync(full);
|
|
8186
8167
|
} catch {
|
|
8187
8168
|
continue;
|
|
8188
8169
|
}
|
|
@@ -8190,7 +8171,7 @@ function runGrep(opts) {
|
|
|
8190
8171
|
if (lst.isSymbolicLink()) {
|
|
8191
8172
|
let real;
|
|
8192
8173
|
try {
|
|
8193
|
-
real =
|
|
8174
|
+
real = fs4.realpathSync(full);
|
|
8194
8175
|
} catch {
|
|
8195
8176
|
continue;
|
|
8196
8177
|
}
|
|
@@ -8199,7 +8180,7 @@ function runGrep(opts) {
|
|
|
8199
8180
|
}
|
|
8200
8181
|
let stat;
|
|
8201
8182
|
try {
|
|
8202
|
-
stat =
|
|
8183
|
+
stat = fs4.statSync(target);
|
|
8203
8184
|
} catch {
|
|
8204
8185
|
continue;
|
|
8205
8186
|
}
|
|
@@ -8219,16 +8200,16 @@ function runGrep(opts) {
|
|
|
8219
8200
|
emitErr(`Path not found: ${searchPath}`);
|
|
8220
8201
|
return 1;
|
|
8221
8202
|
}
|
|
8222
|
-
const stat =
|
|
8203
|
+
const stat = fs4.statSync(searchPath);
|
|
8223
8204
|
if (stat.isDirectory()) {
|
|
8224
|
-
const pinned = activePins?.get(pinKey(
|
|
8205
|
+
const pinned = activePins?.get(pinKey(path4.resolve(searchPath)));
|
|
8225
8206
|
if (pinned !== void 0) verifyPin(searchPath, pinned);
|
|
8226
8207
|
let boundaryReal;
|
|
8227
8208
|
try {
|
|
8228
|
-
boundaryReal =
|
|
8209
|
+
boundaryReal = fs4.realpathSync(searchPath);
|
|
8229
8210
|
} catch (err) {
|
|
8230
8211
|
if (pinned === void 0) {
|
|
8231
|
-
boundaryReal =
|
|
8212
|
+
boundaryReal = path4.resolve(searchPath);
|
|
8232
8213
|
} else {
|
|
8233
8214
|
throw new ConfinementIdentityError(
|
|
8234
8215
|
`refused: "${searchPath}" could not be resolved after validation (${String(err)}). The path may have been replaced or redirected after the confinement check, so the search was not performed.`
|
|
@@ -8359,7 +8340,7 @@ function runConfigGet(opts) {
|
|
|
8359
8340
|
emit(value);
|
|
8360
8341
|
return 0;
|
|
8361
8342
|
}
|
|
8362
|
-
const ext =
|
|
8343
|
+
const ext = path4.extname(opts.file).toLowerCase();
|
|
8363
8344
|
if (ext === ".json") {
|
|
8364
8345
|
try {
|
|
8365
8346
|
let obj = JSON.parse(text);
|
|
@@ -8482,7 +8463,7 @@ function runExports(opts) {
|
|
|
8482
8463
|
names.push(s.name);
|
|
8483
8464
|
}
|
|
8484
8465
|
}
|
|
8485
|
-
const ext =
|
|
8466
|
+
const ext = path4.extname(opts.file).toLowerCase();
|
|
8486
8467
|
const text = readFileText(diskPath);
|
|
8487
8468
|
if (text === null && symbols.length === 0) {
|
|
8488
8469
|
emitErr(`Could not read: ${opts.file}`);
|
|
@@ -8819,9 +8800,9 @@ function extractImports(text, ext) {
|
|
|
8819
8800
|
return found;
|
|
8820
8801
|
}
|
|
8821
8802
|
function importsExtensionFor(filePath) {
|
|
8822
|
-
const base =
|
|
8803
|
+
const base = path4.basename(filePath).toLowerCase();
|
|
8823
8804
|
if (base === "makefile" || base === "gnumakefile" || base === "bsdmakefile") return ".mk";
|
|
8824
|
-
return
|
|
8805
|
+
return path4.extname(filePath);
|
|
8825
8806
|
}
|
|
8826
8807
|
function runImports(opts) {
|
|
8827
8808
|
const multiFiles = parseMultiFileSpec(opts.file);
|
|
@@ -8913,7 +8894,7 @@ async function runSemantic(query, opts) {
|
|
|
8913
8894
|
}
|
|
8914
8895
|
const n = opts.limit !== void 0 && Number.isFinite(opts.limit) ? opts.limit : 20;
|
|
8915
8896
|
if (opts.projectRoot !== void 0) {
|
|
8916
|
-
if (!
|
|
8897
|
+
if (!path4.isAbsolute(opts.projectRoot) || !fs4.existsSync(opts.projectRoot) || !fs4.statSync(opts.projectRoot).isDirectory()) {
|
|
8917
8898
|
const message = `token-goat: projectRoot must be an absolute, existing directory, got '${opts.projectRoot}'`;
|
|
8918
8899
|
if (opts.json === true) {
|
|
8919
8900
|
return { text: JSON.stringify({ error: message }, null, 2), code: 1 };
|
|
@@ -8943,6 +8924,18 @@ async function runSemantic(query, opts) {
|
|
|
8943
8924
|
`Matching on meaning is off (${extractErrorMessage(e)}); these results come from keyword search alone.`
|
|
8944
8925
|
);
|
|
8945
8926
|
}
|
|
8927
|
+
if (rawHits.length === 0 && isAvailable()) {
|
|
8928
|
+
try {
|
|
8929
|
+
const enabled = loadConfig().indexing.embeddings_enabled;
|
|
8930
|
+
const { indexedFiles, embeddedFiles } = enabled ? getEmbeddingCoverage(globalDbPath(), rootDir) : { indexedFiles: 0, embeddedFiles: 0 };
|
|
8931
|
+
if (indexedFiles > 0 && embeddedFiles < indexedFiles) {
|
|
8932
|
+
console.warn(
|
|
8933
|
+
`Matching on meaning found nothing, and only ${embeddedFiles} of ${indexedFiles} indexed file(s) in this project have embeddings \u2014 these results come from keyword search alone. Run 'token-goat doctor' for why.`
|
|
8934
|
+
);
|
|
8935
|
+
}
|
|
8936
|
+
} catch {
|
|
8937
|
+
}
|
|
8938
|
+
}
|
|
8946
8939
|
const mergedHits = mergeNearbyHits(rawHits);
|
|
8947
8940
|
const overFetchFts = Math.min(MAX_OVER_FETCH, n * OVER_FETCH_FACTOR);
|
|
8948
8941
|
const ftsRows = searchSymbolsFts(query, overFetchFts, void 0, rootDir);
|
|
@@ -8989,7 +8982,9 @@ async function runSemantic(query, opts) {
|
|
|
8989
8982
|
const anyFilter = matchesGrep !== void 0 || opts.excludeTests === true;
|
|
8990
8983
|
const filteredHits = anyFilter ? fusedHits.filter(keepHit) : fusedHits;
|
|
8991
8984
|
const suppressedTotal = opts.excludeTests === true ? fusedHits.filter((h) => (matchesGrep === void 0 || matchesGrep(toDisplayPath(rootDir, h.filePath))) && isTestFile(h.filePath)).length : 0;
|
|
8985
|
+
const eligibleCount = filteredHits.length;
|
|
8992
8986
|
const hits = filteredHits.slice(0, n);
|
|
8987
|
+
const candidatesClipped = rawHits.length >= overFetchForMerge || ftsRows.length >= overFetchFts;
|
|
8993
8988
|
const hadDense = mergedHits.length > 0;
|
|
8994
8989
|
const hadFts = ftsRows.length > 0;
|
|
8995
8990
|
const source = hadDense && hadFts ? "hybrid" : hadDense ? "embeddings" : "fts";
|
|
@@ -9005,7 +9000,8 @@ async function runSemantic(query, opts) {
|
|
|
9005
9000
|
preview: previewLines(h.previewText, 3)
|
|
9006
9001
|
}));
|
|
9007
9002
|
const capped = guardJsonRows(items);
|
|
9008
|
-
const
|
|
9003
|
+
const limitTruncated = hits.length < eligibleCount;
|
|
9004
|
+
const text3 = JSON.stringify({ source, ...capped, truncated: capped.truncated || limitTruncated, totalCount: eligibleCount, ...candidatesClipped ? { totalCountIsFloor: true } : {} }, null, 2);
|
|
9009
9005
|
recordReadStat("semantic_search", sumFileSizes(hits.map((h) => h.filePath)), text3, query);
|
|
9010
9006
|
return { text: text3, code: 0 };
|
|
9011
9007
|
}
|
|
@@ -9019,6 +9015,9 @@ ${previewLines(h.previewText, 3)}`;
|
|
|
9019
9015
|
${previewLines(h.previewText, 3)}`;
|
|
9020
9016
|
});
|
|
9021
9017
|
const text2 = guardText(blocks.join("\n\n"), "semantic");
|
|
9018
|
+
if (hits.length < eligibleCount) {
|
|
9019
|
+
emitErr(`Showing ${hits.length} of ${candidatesClipped ? "at least " : ""}${countNoun(eligibleCount, "match", "matches")} (raise --limit to see the rest).`);
|
|
9020
|
+
}
|
|
9022
9021
|
recordReadStat("semantic_search", sumFileSizes(hits.map((h) => h.filePath)), text2, query);
|
|
9023
9022
|
return { text: text2, code: 0 };
|
|
9024
9023
|
}
|
|
@@ -9133,6 +9132,318 @@ function runNoteList(opts = {}) {
|
|
|
9133
9132
|
return { text: lines.join("\n"), code: 0 };
|
|
9134
9133
|
}
|
|
9135
9134
|
|
|
9135
|
+
// src/import_graph.ts
|
|
9136
|
+
import * as fs5 from "node:fs";
|
|
9137
|
+
import * as path5 from "node:path";
|
|
9138
|
+
var DIRECT_PROBE_EXTENSIONS = ["", ".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cjs", ".cts", ".py"];
|
|
9139
|
+
var INDEX_PROBE_EXTENSIONS = [".ts", ".js", ".tsx", ".jsx", ".mts", ".cts"];
|
|
9140
|
+
function buildImportGraph(cwd) {
|
|
9141
|
+
const files = getTrackedFiles(cwd);
|
|
9142
|
+
const filesByFoldedPath = /* @__PURE__ */ new Map();
|
|
9143
|
+
for (const f of files) filesByFoldedPath.set(foldPath(f), f);
|
|
9144
|
+
const resolve5 = (fromFile, spec) => {
|
|
9145
|
+
if (!spec.startsWith(".")) return null;
|
|
9146
|
+
const dir = path5.dirname(fromFile);
|
|
9147
|
+
const strippedSpec = spec.replace(/\.(m?js|cjs)$/, "");
|
|
9148
|
+
const base = path5.resolve(dir, strippedSpec);
|
|
9149
|
+
for (const ext of DIRECT_PROBE_EXTENSIONS) {
|
|
9150
|
+
const match = filesByFoldedPath.get(foldPath(base + ext));
|
|
9151
|
+
if (match !== void 0) return match;
|
|
9152
|
+
}
|
|
9153
|
+
const idx = path5.join(base, "index");
|
|
9154
|
+
for (const ext of INDEX_PROBE_EXTENSIONS) {
|
|
9155
|
+
const match = filesByFoldedPath.get(foldPath(idx + ext));
|
|
9156
|
+
if (match !== void 0) return match;
|
|
9157
|
+
}
|
|
9158
|
+
return null;
|
|
9159
|
+
};
|
|
9160
|
+
const graph = /* @__PURE__ */ new Map();
|
|
9161
|
+
const importedBy = /* @__PURE__ */ new Map();
|
|
9162
|
+
for (const file of files) {
|
|
9163
|
+
let text;
|
|
9164
|
+
try {
|
|
9165
|
+
text = fs5.readFileSync(file, "utf8");
|
|
9166
|
+
} catch {
|
|
9167
|
+
continue;
|
|
9168
|
+
}
|
|
9169
|
+
const internal = [];
|
|
9170
|
+
for (const spec of extractImports(text, importsExtensionFor(file))) {
|
|
9171
|
+
const resolved = resolve5(file, spec);
|
|
9172
|
+
if (resolved === null) continue;
|
|
9173
|
+
internal.push(resolved);
|
|
9174
|
+
let importers = importedBy.get(resolved);
|
|
9175
|
+
if (importers === void 0) {
|
|
9176
|
+
importers = /* @__PURE__ */ new Set();
|
|
9177
|
+
importedBy.set(resolved, importers);
|
|
9178
|
+
}
|
|
9179
|
+
importers.add(file);
|
|
9180
|
+
}
|
|
9181
|
+
graph.set(file, internal);
|
|
9182
|
+
}
|
|
9183
|
+
return { files, graph, importedBy, resolve: resolve5 };
|
|
9184
|
+
}
|
|
9185
|
+
|
|
9186
|
+
// src/modules.ts
|
|
9187
|
+
var WEAK_MODULARITY = 0.3;
|
|
9188
|
+
var MAX_PASSES = 32;
|
|
9189
|
+
var GAIN_EPSILON = 1e-12;
|
|
9190
|
+
function emptyGraph(n) {
|
|
9191
|
+
return { n, adj: Array.from({ length: n }, () => /* @__PURE__ */ new Map()), degree: new Array(n).fill(0), m: 0 };
|
|
9192
|
+
}
|
|
9193
|
+
function addEdge(g, a, b, w) {
|
|
9194
|
+
if (a === b) {
|
|
9195
|
+
g.adj[a].set(a, (g.adj[a].get(a) ?? 0) + w);
|
|
9196
|
+
g.degree[a] += 2 * w;
|
|
9197
|
+
} else {
|
|
9198
|
+
g.adj[a].set(b, (g.adj[a].get(b) ?? 0) + w);
|
|
9199
|
+
g.adj[b].set(a, (g.adj[b].get(a) ?? 0) + w);
|
|
9200
|
+
g.degree[a] += w;
|
|
9201
|
+
g.degree[b] += w;
|
|
9202
|
+
}
|
|
9203
|
+
g.m += w;
|
|
9204
|
+
}
|
|
9205
|
+
function localMoving(g) {
|
|
9206
|
+
const community = Array.from({ length: g.n }, (_, i) => i);
|
|
9207
|
+
const tot = g.degree.slice();
|
|
9208
|
+
const twoM = 2 * g.m;
|
|
9209
|
+
let movedEver = false;
|
|
9210
|
+
if (twoM === 0) return { community, moved: false };
|
|
9211
|
+
for (let pass = 0; pass < MAX_PASSES; pass++) {
|
|
9212
|
+
let improved = false;
|
|
9213
|
+
for (let i = 0; i < g.n; i++) {
|
|
9214
|
+
const ki = g.degree[i];
|
|
9215
|
+
const ci = community[i];
|
|
9216
|
+
const links = /* @__PURE__ */ new Map();
|
|
9217
|
+
for (const [j, w] of g.adj[i]) {
|
|
9218
|
+
if (j === i) continue;
|
|
9219
|
+
const cj = community[j];
|
|
9220
|
+
links.set(cj, (links.get(cj) ?? 0) + w);
|
|
9221
|
+
}
|
|
9222
|
+
tot[ci] = tot[ci] - ki;
|
|
9223
|
+
let bestC = ci;
|
|
9224
|
+
let bestGain = (links.get(ci) ?? 0) - tot[ci] * ki / twoM;
|
|
9225
|
+
for (const c of [...links.keys()].sort((a, b) => a - b)) {
|
|
9226
|
+
if (c === ci) continue;
|
|
9227
|
+
const gain = links.get(c) - tot[c] * ki / twoM;
|
|
9228
|
+
if (gain > bestGain + GAIN_EPSILON) {
|
|
9229
|
+
bestGain = gain;
|
|
9230
|
+
bestC = c;
|
|
9231
|
+
}
|
|
9232
|
+
}
|
|
9233
|
+
tot[bestC] = tot[bestC] + ki;
|
|
9234
|
+
community[i] = bestC;
|
|
9235
|
+
if (bestC !== ci) {
|
|
9236
|
+
improved = true;
|
|
9237
|
+
movedEver = true;
|
|
9238
|
+
}
|
|
9239
|
+
}
|
|
9240
|
+
if (!improved) break;
|
|
9241
|
+
}
|
|
9242
|
+
return { community, moved: movedEver };
|
|
9243
|
+
}
|
|
9244
|
+
function densify(community) {
|
|
9245
|
+
const firstMember = /* @__PURE__ */ new Map();
|
|
9246
|
+
for (let i = 0; i < community.length; i++) {
|
|
9247
|
+
const c = community[i];
|
|
9248
|
+
if (!firstMember.has(c)) firstMember.set(c, i);
|
|
9249
|
+
}
|
|
9250
|
+
const ordered = [...firstMember.entries()].sort((a, b) => a[1] - b[1]).map(([c]) => c);
|
|
9251
|
+
const remap = /* @__PURE__ */ new Map();
|
|
9252
|
+
ordered.forEach((c, idx) => remap.set(c, idx));
|
|
9253
|
+
return { dense: community.map((c) => remap.get(c)), count: ordered.length };
|
|
9254
|
+
}
|
|
9255
|
+
function modularityOf(g, partition) {
|
|
9256
|
+
const twoM = 2 * g.m;
|
|
9257
|
+
if (twoM === 0) return null;
|
|
9258
|
+
const internal = /* @__PURE__ */ new Map();
|
|
9259
|
+
const tot = /* @__PURE__ */ new Map();
|
|
9260
|
+
for (let i = 0; i < g.n; i++) {
|
|
9261
|
+
const ci = partition[i];
|
|
9262
|
+
tot.set(ci, (tot.get(ci) ?? 0) + g.degree[i]);
|
|
9263
|
+
for (const [j, w] of g.adj[i]) {
|
|
9264
|
+
if (j < i) continue;
|
|
9265
|
+
if (partition[j] === ci) internal.set(ci, (internal.get(ci) ?? 0) + w);
|
|
9266
|
+
}
|
|
9267
|
+
}
|
|
9268
|
+
let q = 0;
|
|
9269
|
+
for (const [c, t] of tot) {
|
|
9270
|
+
q += 2 * (internal.get(c) ?? 0) / twoM - (t / twoM) ** 2;
|
|
9271
|
+
}
|
|
9272
|
+
return q;
|
|
9273
|
+
}
|
|
9274
|
+
function louvain(g) {
|
|
9275
|
+
let current = g;
|
|
9276
|
+
let mapping = Array.from({ length: g.n }, (_, i) => i);
|
|
9277
|
+
for (let level = 0; level < MAX_PASSES; level++) {
|
|
9278
|
+
const { community, moved } = localMoving(current);
|
|
9279
|
+
const { dense, count } = densify(community);
|
|
9280
|
+
mapping = mapping.map((c) => dense[c]);
|
|
9281
|
+
if (!moved || count === current.n) break;
|
|
9282
|
+
const next = emptyGraph(count);
|
|
9283
|
+
for (let i = 0; i < current.n; i++) {
|
|
9284
|
+
for (const [j, w] of current.adj[i]) {
|
|
9285
|
+
if (j < i) continue;
|
|
9286
|
+
addEdge(next, dense[i], dense[j], w);
|
|
9287
|
+
}
|
|
9288
|
+
}
|
|
9289
|
+
current = next;
|
|
9290
|
+
}
|
|
9291
|
+
return mapping;
|
|
9292
|
+
}
|
|
9293
|
+
function commonDirLabel(files) {
|
|
9294
|
+
const dirs = new Set(files.map(dirOf));
|
|
9295
|
+
if (dirs.size === 1) {
|
|
9296
|
+
const only = [...dirs][0];
|
|
9297
|
+
return only === "." ? "." : `${only}/`;
|
|
9298
|
+
}
|
|
9299
|
+
const segmentLists = files.map((f) => {
|
|
9300
|
+
const parts = f.split("/");
|
|
9301
|
+
parts.pop();
|
|
9302
|
+
return parts;
|
|
9303
|
+
});
|
|
9304
|
+
const first = segmentLists[0];
|
|
9305
|
+
if (first === void 0) return null;
|
|
9306
|
+
const prefix = [];
|
|
9307
|
+
for (let i = 0; i < first.length; i++) {
|
|
9308
|
+
const seg = first[i];
|
|
9309
|
+
if (!segmentLists.every((s) => s[i] === seg)) break;
|
|
9310
|
+
prefix.push(seg);
|
|
9311
|
+
}
|
|
9312
|
+
return prefix.length === 0 ? null : `${prefix.join("/")}/`;
|
|
9313
|
+
}
|
|
9314
|
+
function dirOf(file) {
|
|
9315
|
+
const idx = file.lastIndexOf("/");
|
|
9316
|
+
return idx === -1 ? "." : file.slice(0, idx);
|
|
9317
|
+
}
|
|
9318
|
+
function detectModules(imports, cwd, top) {
|
|
9319
|
+
const { files, graph } = imports;
|
|
9320
|
+
const root = getDisplayRoot(cwd);
|
|
9321
|
+
const degreeOf = /* @__PURE__ */ new Map();
|
|
9322
|
+
const bump = (f) => {
|
|
9323
|
+
degreeOf.set(f, (degreeOf.get(f) ?? 0) + 1);
|
|
9324
|
+
};
|
|
9325
|
+
for (const [from, targets] of graph) {
|
|
9326
|
+
for (const to of targets) {
|
|
9327
|
+
if (from === to) continue;
|
|
9328
|
+
bump(from);
|
|
9329
|
+
bump(to);
|
|
9330
|
+
}
|
|
9331
|
+
}
|
|
9332
|
+
const connected = files.filter((f) => (degreeOf.get(f) ?? 0) > 0);
|
|
9333
|
+
const isolatedCount = files.length - connected.length;
|
|
9334
|
+
if (connected.length === 0) {
|
|
9335
|
+
return { modules: [], modulesTotal: 0, modularity: null, isolatedCount, crossImports: [], crossImportsTotal: 0, noEdges: true };
|
|
9336
|
+
}
|
|
9337
|
+
const ordered = [...connected].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
9338
|
+
const idOf = /* @__PURE__ */ new Map();
|
|
9339
|
+
ordered.forEach((f, i) => idOf.set(f, i));
|
|
9340
|
+
const g = emptyGraph(ordered.length);
|
|
9341
|
+
const pairWeight = /* @__PURE__ */ new Map();
|
|
9342
|
+
for (const [from, targets] of graph) {
|
|
9343
|
+
const a = idOf.get(from);
|
|
9344
|
+
if (a === void 0) continue;
|
|
9345
|
+
for (const to of targets) {
|
|
9346
|
+
const b = idOf.get(to);
|
|
9347
|
+
if (b === void 0 || a === b) continue;
|
|
9348
|
+
const key = a < b ? `${a}:${b}` : `${b}:${a}`;
|
|
9349
|
+
pairWeight.set(key, (pairWeight.get(key) ?? 0) + 1);
|
|
9350
|
+
}
|
|
9351
|
+
}
|
|
9352
|
+
for (const key of [...pairWeight.keys()].sort()) {
|
|
9353
|
+
const [a, b] = key.split(":").map(Number);
|
|
9354
|
+
addEdge(g, a, b, pairWeight.get(key));
|
|
9355
|
+
}
|
|
9356
|
+
const partition = louvain(g);
|
|
9357
|
+
const modularity = modularityOf(g, partition);
|
|
9358
|
+
const membersOf = /* @__PURE__ */ new Map();
|
|
9359
|
+
for (let i = 0; i < ordered.length; i++) {
|
|
9360
|
+
const c = partition[i];
|
|
9361
|
+
const list = membersOf.get(c);
|
|
9362
|
+
if (list === void 0) membersOf.set(c, [ordered[i]]);
|
|
9363
|
+
else list.push(ordered[i]);
|
|
9364
|
+
}
|
|
9365
|
+
const inModuleDegree = /* @__PURE__ */ new Map();
|
|
9366
|
+
for (const [from, targets] of graph) {
|
|
9367
|
+
const a = idOf.get(from);
|
|
9368
|
+
if (a === void 0) continue;
|
|
9369
|
+
for (const to of targets) {
|
|
9370
|
+
const b = idOf.get(to);
|
|
9371
|
+
if (b === void 0 || a === b || partition[a] !== partition[b]) continue;
|
|
9372
|
+
inModuleDegree.set(from, (inModuleDegree.get(from) ?? 0) + 1);
|
|
9373
|
+
inModuleDegree.set(to, (inModuleDegree.get(to) ?? 0) + 1);
|
|
9374
|
+
}
|
|
9375
|
+
}
|
|
9376
|
+
const built = [...membersOf.entries()].map(([c, absFiles]) => {
|
|
9377
|
+
const display = absFiles.map((f) => toDisplayPath(root, f)).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
9378
|
+
const coreAbs = [...absFiles].sort((a, b) => (inModuleDegree.get(b) ?? 0) - (inModuleDegree.get(a) ?? 0) || (a < b ? -1 : a > b ? 1 : 0))[0];
|
|
9379
|
+
return { community: c, core: toDisplayPath(root, coreAbs), commonDir: commonDirLabel(display), files: display, directories: new Set(display.map(dirOf)).size };
|
|
9380
|
+
}).sort((a, b) => b.files.length - a.files.length || (a.core < b.core ? -1 : a.core > b.core ? 1 : 0) || (a.files[0] < b.files[0] ? -1 : 1));
|
|
9381
|
+
const indexOfCommunity = /* @__PURE__ */ new Map();
|
|
9382
|
+
built.forEach((m, i) => indexOfCommunity.set(m.community, i + 1));
|
|
9383
|
+
const coreOfIndex = /* @__PURE__ */ new Map();
|
|
9384
|
+
built.forEach((m, i) => coreOfIndex.set(i + 1, m.core));
|
|
9385
|
+
const crossCount = /* @__PURE__ */ new Map();
|
|
9386
|
+
for (const [from, targets] of graph) {
|
|
9387
|
+
const a = idOf.get(from);
|
|
9388
|
+
if (a === void 0) continue;
|
|
9389
|
+
const ca = indexOfCommunity.get(partition[a]);
|
|
9390
|
+
if (ca === void 0) continue;
|
|
9391
|
+
for (const to of targets) {
|
|
9392
|
+
const b = idOf.get(to);
|
|
9393
|
+
if (b === void 0) continue;
|
|
9394
|
+
const cb = indexOfCommunity.get(partition[b]);
|
|
9395
|
+
if (cb === void 0 || ca === cb) continue;
|
|
9396
|
+
const key = `${ca}:${cb}`;
|
|
9397
|
+
crossCount.set(key, (crossCount.get(key) ?? 0) + 1);
|
|
9398
|
+
}
|
|
9399
|
+
}
|
|
9400
|
+
const allCross = [...crossCount.entries()].map(([key, imports2]) => {
|
|
9401
|
+
const [fromIndex, toIndex] = key.split(":").map(Number);
|
|
9402
|
+
return { fromIndex, toIndex, fromCore: coreOfIndex.get(fromIndex), toCore: coreOfIndex.get(toIndex), imports: imports2 };
|
|
9403
|
+
}).sort((a, b) => b.imports - a.imports || a.fromIndex - b.fromIndex || a.toIndex - b.toIndex);
|
|
9404
|
+
const modules = built.slice(0, top).map((m, i) => ({ index: i + 1, core: m.core, commonDir: m.commonDir, files: m.files, size: m.files.length, directories: m.directories }));
|
|
9405
|
+
return {
|
|
9406
|
+
modules,
|
|
9407
|
+
modulesTotal: built.length,
|
|
9408
|
+
modularity,
|
|
9409
|
+
isolatedCount,
|
|
9410
|
+
crossImports: allCross.slice(0, top),
|
|
9411
|
+
crossImportsTotal: allCross.length,
|
|
9412
|
+
noEdges: false
|
|
9413
|
+
};
|
|
9414
|
+
}
|
|
9415
|
+
function renderModules(result, top) {
|
|
9416
|
+
const lines = [];
|
|
9417
|
+
if (result.noEdges) {
|
|
9418
|
+
lines.push(`modules: none. No file in this project imports another by a relative path, so there is nothing to group (${countNoun(result.isolatedCount, "file")} checked).`);
|
|
9419
|
+
return lines;
|
|
9420
|
+
}
|
|
9421
|
+
const q = result.modularity;
|
|
9422
|
+
const strength = q === null ? "" : q < WEAK_MODULARITY ? `, modularity ${q.toFixed(2)} -- weak, so treat this grouping as a hint rather than a finding` : `, modularity ${q.toFixed(2)}`;
|
|
9423
|
+
lines.push(result.modules.length < result.modulesTotal ? `modules (top ${result.modules.length} of ${result.modulesTotal}${strength}):` : `modules (${result.modulesTotal} found${strength}):`);
|
|
9424
|
+
for (const m of result.modules) {
|
|
9425
|
+
const where = m.commonDir === null ? `across ${m.directories} directories` : m.commonDir === "." ? "all in the repository root" : `all in ${m.commonDir}`;
|
|
9426
|
+
lines.push(` #${m.index} ${m.size} files ${m.core} (${where})`);
|
|
9427
|
+
}
|
|
9428
|
+
if (result.isolatedCount > 0) {
|
|
9429
|
+
lines.push(` ${result.isolatedCount} files are in no module (they neither import nor are imported within the project).`);
|
|
9430
|
+
}
|
|
9431
|
+
if (result.crossImportsTotal === 0) {
|
|
9432
|
+
lines.push("cross-module imports: none. Every import stays inside its own module.");
|
|
9433
|
+
} else {
|
|
9434
|
+
lines.push(
|
|
9435
|
+
result.crossImports.length < result.crossImportsTotal ? `cross-module imports (top ${result.crossImports.length} of ${result.crossImportsTotal} pairs):` : `cross-module imports (${result.crossImportsTotal} pairs):`
|
|
9436
|
+
);
|
|
9437
|
+
for (const c of result.crossImports) {
|
|
9438
|
+
lines.push(` ${c.imports} imports #${c.fromIndex} ${c.fromCore} -> #${c.toIndex} ${c.toCore}`);
|
|
9439
|
+
}
|
|
9440
|
+
}
|
|
9441
|
+
if (result.modules.length < result.modulesTotal && result.crossImports.some((c) => c.fromIndex > top || c.toIndex > top)) {
|
|
9442
|
+
lines.push(` (a #N above ${top} refers to a module the --top cap left out; raise --top to see it.)`);
|
|
9443
|
+
}
|
|
9444
|
+
return lines;
|
|
9445
|
+
}
|
|
9446
|
+
|
|
9136
9447
|
// src/graph_commands.ts
|
|
9137
9448
|
var DEFAULT_REF_QUERY_LIMIT = 500;
|
|
9138
9449
|
var ALL_SYMBOLS_IN_FILE_LIMIT = 1e4;
|
|
@@ -9819,7 +10130,7 @@ var TYPE_KINDS = [
|
|
|
9819
10130
|
var CORE_SYMBOL_KINDS = [
|
|
9820
10131
|
.../* @__PURE__ */ new Set([...GENERIC_SYMBOL_KINDS, ...TYPE_KINDS, ...OTHER_ADAPTER_SYMBOL_KINDS])
|
|
9821
10132
|
];
|
|
9822
|
-
var
|
|
10133
|
+
var TYPES_SCAN_LIMIT = 5e3;
|
|
9823
10134
|
function runTypes(opts) {
|
|
9824
10135
|
if (opts.limit !== void 0 && opts.limit <= 0) {
|
|
9825
10136
|
emitErr2(`--limit must be a positive number, got: ${opts.limit}`);
|
|
@@ -9832,34 +10143,25 @@ function runTypes(opts) {
|
|
|
9832
10143
|
const rootDir = resolveProjectRoot({ project: process.cwd() });
|
|
9833
10144
|
const results = [];
|
|
9834
10145
|
let suppressed = 0;
|
|
9835
|
-
const queryLimit = excludeTests ? TYPES_EXCLUDE_TESTS_SCAN_LIMIT : limit;
|
|
9836
10146
|
for (const k of TYPE_KINDS) {
|
|
9837
|
-
const syms = querySymbols({ kind: k, ...fpOpt, limit:
|
|
9838
|
-
if (!excludeTests) {
|
|
9839
|
-
results.push(...syms);
|
|
9840
|
-
continue;
|
|
9841
|
-
}
|
|
9842
|
-
const kept = [];
|
|
10147
|
+
const syms = querySymbols({ kind: k, ...fpOpt, limit: TYPES_SCAN_LIMIT, rootDir });
|
|
9843
10148
|
for (const sym of syms) {
|
|
9844
|
-
if (isTestFile(sym.filePath)) {
|
|
10149
|
+
if (excludeTests && isTestFile(sym.filePath)) {
|
|
9845
10150
|
suppressed += 1;
|
|
9846
10151
|
continue;
|
|
9847
10152
|
}
|
|
9848
|
-
|
|
10153
|
+
results.push(sym);
|
|
9849
10154
|
}
|
|
9850
|
-
results.push(...kept.slice(0, limit));
|
|
9851
10155
|
}
|
|
9852
|
-
const classes = querySymbols({ kind: "class", ...fpOpt, limit:
|
|
9853
|
-
const typeClasses = [];
|
|
10156
|
+
const classes = querySymbols({ kind: "class", ...fpOpt, limit: TYPES_SCAN_LIMIT, rootDir });
|
|
9854
10157
|
for (const cls of classes) {
|
|
9855
10158
|
if (!looksLikeTypeClass(cls.body)) continue;
|
|
9856
10159
|
if (excludeTests && isTestFile(cls.filePath)) {
|
|
9857
10160
|
suppressed += 1;
|
|
9858
10161
|
continue;
|
|
9859
10162
|
}
|
|
9860
|
-
|
|
10163
|
+
results.push(cls);
|
|
9861
10164
|
}
|
|
9862
|
-
results.push(...excludeTests ? typeClasses.slice(0, limit) : typeClasses);
|
|
9863
10165
|
results.sort(
|
|
9864
10166
|
// Pin the locale: an unlocaled localeCompare() sorts differently across
|
|
9865
10167
|
// Node's small-icu vs full-icu builds and different system default
|
|
@@ -9886,7 +10188,16 @@ function runTypes(opts) {
|
|
|
9886
10188
|
}
|
|
9887
10189
|
const preFilterCount = results.length;
|
|
9888
10190
|
const matchesGrep = opts.grep !== void 0 ? compileGrepMatcher(opts.grep) : void 0;
|
|
9889
|
-
const
|
|
10191
|
+
const matched = matchesGrep !== void 0 ? results.filter((r) => matchesGrep(r.name)) : results;
|
|
10192
|
+
const eligibleCount = matched.length;
|
|
10193
|
+
const perKindShown = /* @__PURE__ */ new Map();
|
|
10194
|
+
const filtered = matched.filter((r) => {
|
|
10195
|
+
const seen = perKindShown.get(r.kind) ?? 0;
|
|
10196
|
+
if (seen >= limit) return false;
|
|
10197
|
+
perKindShown.set(r.kind, seen + 1);
|
|
10198
|
+
return true;
|
|
10199
|
+
});
|
|
10200
|
+
const cappedOut = eligibleCount - filtered.length;
|
|
9890
10201
|
if (filtered.length === 0) {
|
|
9891
10202
|
if (opts.json === true) {
|
|
9892
10203
|
emit2(JSON.stringify({ items: [], truncated: false, totalCount: 0, hiddenByGrep: preFilterCount }, null, 2));
|
|
@@ -9897,8 +10208,8 @@ function runTypes(opts) {
|
|
|
9897
10208
|
}
|
|
9898
10209
|
if (opts.json === true) {
|
|
9899
10210
|
const capped = guardJsonRows(filtered.map((r) => ({ ...r, filePath: toDisplayPath(rootDir, r.filePath) })));
|
|
9900
|
-
const hiddenByGrep = preFilterCount -
|
|
9901
|
-
emit2(JSON.stringify({ items: capped.items, truncated: capped.truncated, totalCount:
|
|
10211
|
+
const hiddenByGrep = preFilterCount - eligibleCount;
|
|
10212
|
+
emit2(JSON.stringify({ items: capped.items, truncated: capped.truncated || cappedOut > 0, totalCount: eligibleCount, ...hiddenByGrep > 0 ? { hiddenByGrep } : {}, ...excludeTests && suppressed > 0 ? { hiddenByExcludeTests: suppressed } : {} }, null, 2));
|
|
9902
10213
|
return 0;
|
|
9903
10214
|
}
|
|
9904
10215
|
if (excludeTests && suppressed > 0) {
|
|
@@ -9907,6 +10218,9 @@ function runTypes(opts) {
|
|
|
9907
10218
|
for (const r of filtered) {
|
|
9908
10219
|
emit2(`${r.name} ${r.kind} ${toDisplayPath(rootDir, r.filePath)}:${r.lineStart}`);
|
|
9909
10220
|
}
|
|
10221
|
+
if (cappedOut > 0) {
|
|
10222
|
+
emitErr2(`Showing ${filtered.length} of ${eligibleCount} type declarations (--limit is per kind; raise it to see the rest).`);
|
|
10223
|
+
}
|
|
9910
10224
|
return 0;
|
|
9911
10225
|
}
|
|
9912
10226
|
function runScope(opts) {
|
|
@@ -9922,7 +10236,7 @@ function runScope(opts) {
|
|
|
9922
10236
|
return 1;
|
|
9923
10237
|
}
|
|
9924
10238
|
const line = Number.parseInt(lineStr, 10);
|
|
9925
|
-
if (!Number.
|
|
10239
|
+
if (!Number.isSafeInteger(line) || line < 1) {
|
|
9926
10240
|
emitErr2(`Invalid line number: ${lineStr}`);
|
|
9927
10241
|
return 1;
|
|
9928
10242
|
}
|
|
@@ -9932,25 +10246,32 @@ function runScope(opts) {
|
|
|
9932
10246
|
return 1;
|
|
9933
10247
|
}
|
|
9934
10248
|
const filePath = resolveIndexPath(file);
|
|
9935
|
-
const
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
10249
|
+
const enclosing = querySymbols({ filePath, enclosingLine: line, limit: ALL_SYMBOLS_IN_FILE_LIMIT }).sort((a, b) => b.lineStart - a.lineStart || a.lineEnd - b.lineEnd || a.name.localeCompare(b.name, "en"));
|
|
10250
|
+
if (enclosing.length === 0) {
|
|
10251
|
+
if (querySymbols({ filePath, limit: 1 }).length === 0) {
|
|
10252
|
+
if (!fs6.existsSync(filePath)) {
|
|
10253
|
+
emitErr2(`Could not read: ${file}`);
|
|
10254
|
+
return 1;
|
|
10255
|
+
}
|
|
10256
|
+
emitErr2(
|
|
10257
|
+
`No indexed symbols in '${file}' \u2014 the file exists but nothing is indexed for it, so every line looks empty`
|
|
10258
|
+
);
|
|
9940
10259
|
return 1;
|
|
9941
10260
|
}
|
|
9942
|
-
emitErr2(`No indexed symbols in '${file}' \u2014 the file exists but nothing is indexed for it, so every line looks empty`);
|
|
9943
|
-
return 1;
|
|
9944
|
-
}
|
|
9945
|
-
if (enclosing.length === 0) {
|
|
9946
10261
|
emitErr2(`No symbols enclosing line ${line} in '${file}'`);
|
|
9947
10262
|
return 1;
|
|
9948
10263
|
}
|
|
10264
|
+
const scopeDisplayRoot = getDisplayRoot();
|
|
9949
10265
|
if (opts.json === true) {
|
|
9950
|
-
emit2(
|
|
10266
|
+
emit2(
|
|
10267
|
+
JSON.stringify(
|
|
10268
|
+
enclosing.map((s) => ({ ...s, filePath: toDisplayPath(scopeDisplayRoot, s.filePath) })),
|
|
10269
|
+
null,
|
|
10270
|
+
2
|
|
10271
|
+
)
|
|
10272
|
+
);
|
|
9951
10273
|
return 0;
|
|
9952
10274
|
}
|
|
9953
|
-
const scopeDisplayRoot = getDisplayRoot();
|
|
9954
10275
|
for (const s of enclosing) {
|
|
9955
10276
|
emit2(`${s.name} ${s.kind} ${toDisplayPath(scopeDisplayRoot, s.filePath)}:${s.lineStart}-${s.lineEnd}`);
|
|
9956
10277
|
}
|
|
@@ -10075,8 +10396,12 @@ function runSimilar(opts) {
|
|
|
10075
10396
|
const words = [anchor.name, ...(anchor.docstring ?? "").split(/\s+/).filter((w) => w.length > 4)];
|
|
10076
10397
|
const query = words.slice(0, 8).join(" ");
|
|
10077
10398
|
const rootDir = resolveProjectRoot({ project: process.cwd() });
|
|
10078
|
-
const hits = searchSymbolsFts(query,
|
|
10079
|
-
const
|
|
10399
|
+
const hits = searchSymbolsFts(query, UNBOUNDED_REF_LIMIT, void 0, rootDir);
|
|
10400
|
+
const matches = hits.filter((h) => !(h.filePath === anchor.filePath && h.name === anchor.name));
|
|
10401
|
+
const results = matches.slice(0, top);
|
|
10402
|
+
if (matches.length > results.length) {
|
|
10403
|
+
emitErr2(`Showing top ${results.length} of ${matches.length} similar symbols (raise --top to see the rest).`);
|
|
10404
|
+
}
|
|
10080
10405
|
if (opts.json === true) {
|
|
10081
10406
|
emit2(JSON.stringify(results.map((h) => ({ name: h.name, kind: h.kind, file: h.filePath, line: h.lineStart })), null, 2));
|
|
10082
10407
|
return 0;
|
|
@@ -10092,7 +10417,9 @@ function runContextFor(opts) {
|
|
|
10092
10417
|
const top = opts.top ?? 12;
|
|
10093
10418
|
const budget = opts.budget;
|
|
10094
10419
|
const rootDir = resolveProjectRoot({ project: process.cwd() });
|
|
10095
|
-
const
|
|
10420
|
+
const fetched = searchSymbolsFts(opts.task, top + 1, void 0, rootDir);
|
|
10421
|
+
const moreBeyondTop = fetched.length > top;
|
|
10422
|
+
const hits = fetched.slice(0, top);
|
|
10096
10423
|
if (hits.length === 0) {
|
|
10097
10424
|
emitErr2(`No matches found for '${opts.task}'`);
|
|
10098
10425
|
return 1;
|
|
@@ -10105,6 +10432,15 @@ function runContextFor(opts) {
|
|
|
10105
10432
|
tokensSoFar += bodyTokens;
|
|
10106
10433
|
entries.push({ file: h.filePath, symbol: h.name, kind: h.kind, line: h.lineStart, readCmd: `token-goat read "${h.filePath}::${h.name}@${h.lineStart}"` });
|
|
10107
10434
|
}
|
|
10435
|
+
const skippedByBudget = hits.length - entries.length;
|
|
10436
|
+
const notices = [];
|
|
10437
|
+
if (skippedByBudget > 0) {
|
|
10438
|
+
notices.push(
|
|
10439
|
+
entries.length === 0 ? `All ${countNoun(skippedByBudget, "matching symbol")} were larger than --budget ${String(opts.budget)} tokens, so none are shown. Raise --budget.` : `Showing ${entries.length} of ${countNoun(hits.length, "matching symbol")}; ${skippedByBudget} did not fit --budget ${String(opts.budget)} tokens.`
|
|
10440
|
+
);
|
|
10441
|
+
}
|
|
10442
|
+
if (moreBeyondTop) notices.push(`More matches exist beyond --top ${top} (raise it to see them).`);
|
|
10443
|
+
for (const n of notices) emitErr2(n);
|
|
10108
10444
|
if (opts.json === true) {
|
|
10109
10445
|
emit2(JSON.stringify(entries, null, 2));
|
|
10110
10446
|
return 0;
|
|
@@ -10195,66 +10531,31 @@ function runArch(opts) {
|
|
|
10195
10531
|
}
|
|
10196
10532
|
const cwd = opts.cwd ?? process.cwd();
|
|
10197
10533
|
const top = opts.top ?? 10;
|
|
10198
|
-
const files =
|
|
10534
|
+
const { files, graph, importedBy, resolve: resolve5 } = buildImportGraph(cwd);
|
|
10199
10535
|
if (files.length === 0 && opts.json !== true) {
|
|
10200
10536
|
emit2(`no tracked files found under '${toDisplayPath(getDisplayRoot(cwd), cwd)}' (is it a git repo?). Nothing to analyse.`);
|
|
10201
10537
|
return 0;
|
|
10202
10538
|
}
|
|
10203
|
-
const
|
|
10204
|
-
|
|
10205
|
-
const
|
|
10206
|
-
const
|
|
10207
|
-
const
|
|
10208
|
-
|
|
10209
|
-
const dir = path6.dirname(fromFile);
|
|
10210
|
-
const strippedSpec = spec.replace(/\.(m?js|cjs)$/, "");
|
|
10211
|
-
const base = path6.resolve(dir, strippedSpec);
|
|
10212
|
-
for (const ext of ["", ".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cjs", ".cts", ".py"]) {
|
|
10213
|
-
const candidate = base + ext;
|
|
10214
|
-
const match = filesByFoldedPath.get(foldPath(candidate));
|
|
10215
|
-
if (match !== void 0) return match;
|
|
10216
|
-
}
|
|
10217
|
-
const idx = path6.join(base, "index");
|
|
10218
|
-
for (const ext of [".ts", ".js", ".tsx", ".jsx", ".mts", ".cts"]) {
|
|
10219
|
-
const candidate = idx + ext;
|
|
10220
|
-
const match = filesByFoldedPath.get(foldPath(candidate));
|
|
10221
|
-
if (match !== void 0) return match;
|
|
10222
|
-
}
|
|
10223
|
-
return null;
|
|
10224
|
-
};
|
|
10225
|
-
for (const file of files) {
|
|
10226
|
-
let text;
|
|
10227
|
-
try {
|
|
10228
|
-
text = fs6.readFileSync(file, "utf8");
|
|
10229
|
-
} catch {
|
|
10230
|
-
continue;
|
|
10231
|
-
}
|
|
10232
|
-
const ext = importsExtensionFor(file);
|
|
10233
|
-
const rawImports = extractImports(text, ext);
|
|
10234
|
-
const internal = [];
|
|
10235
|
-
for (const spec of rawImports) {
|
|
10236
|
-
const resolved = resolveRelImport(file, spec);
|
|
10237
|
-
if (resolved !== null) {
|
|
10238
|
-
internal.push(resolved);
|
|
10239
|
-
if (!importedBy.has(resolved)) importedBy.set(resolved, /* @__PURE__ */ new Set());
|
|
10240
|
-
importedBy.get(resolved).add(file);
|
|
10241
|
-
}
|
|
10242
|
-
}
|
|
10243
|
-
graph.set(file, internal);
|
|
10244
|
-
}
|
|
10245
|
-
const hubs = [...importedBy.entries()].sort((a, b) => b[1].size - a[1].size).slice(0, top).map(([f, importers]) => ({ file: f, importedBy: importers.size }));
|
|
10246
|
-
const entryPoints = files.filter((f) => !importedBy.has(f) && (graph.get(f) ?? []).length > 0).slice(0, top).map((f) => ({ file: f }));
|
|
10539
|
+
const allHubs = [...importedBy.entries()].sort((a, b) => b[1].size - a[1].size).map(([f, importers]) => ({ file: f, importedBy: importers.size }));
|
|
10540
|
+
const hubsTotal = allHubs.length;
|
|
10541
|
+
const hubs = allHubs.slice(0, top);
|
|
10542
|
+
const allEntryPoints = files.filter((f) => !importedBy.has(f) && (graph.get(f) ?? []).length > 0).map((f) => ({ file: f }));
|
|
10543
|
+
const entryPointsTotal = allEntryPoints.length;
|
|
10544
|
+
const entryPoints = allEntryPoints.slice(0, top);
|
|
10247
10545
|
const { cycles, truncated: cyclesTruncated } = findCyclesCapped(graph);
|
|
10546
|
+
const moduleResult = opts.modules === true ? detectModules({ files, graph, importedBy, resolve: resolve5 }, cwd, top) : null;
|
|
10248
10547
|
if (opts.json === true) {
|
|
10249
|
-
|
|
10548
|
+
const modulePayload = moduleResult === null ? {} : { modules: moduleResult.modules, modulesTotal: moduleResult.modulesTotal, modulesTruncated: moduleResult.modules.length < moduleResult.modulesTotal, modularity: moduleResult.modularity, isolatedCount: moduleResult.isolatedCount, crossImports: moduleResult.crossImports, crossImportsTotal: moduleResult.crossImportsTotal, crossImportsTruncated: moduleResult.crossImports.length < moduleResult.crossImportsTotal, noImportEdges: moduleResult.noEdges };
|
|
10549
|
+
emit2(JSON.stringify({ hubs, hubsTotal, hubsTruncated: hubs.length < hubsTotal, entryPoints, entryPointsTotal, entryPointsTruncated: entryPoints.length < entryPointsTotal, cycles, ...cyclesTruncated ? { cyclesTruncated: true } : {}, ...modulePayload }, null, 2));
|
|
10250
10550
|
return 0;
|
|
10251
10551
|
}
|
|
10252
|
-
emit2(`hubs (top ${
|
|
10552
|
+
emit2(hubs.length < hubsTotal ? `hubs (top ${hubs.length} of ${hubsTotal} most-imported):` : `hubs (${hubsTotal} most-imported):`);
|
|
10253
10553
|
for (const h of hubs) emit2(` ${h.importedBy} importers ${toDisplayPath(getDisplayRoot(opts.cwd), h.file)}`);
|
|
10254
|
-
emit2(`entry points (imported by nobody, top ${
|
|
10554
|
+
emit2(entryPoints.length < entryPointsTotal ? `entry points (imported by nobody, top ${entryPoints.length} of ${entryPointsTotal}):` : `entry points (imported by nobody, ${entryPointsTotal} found):`);
|
|
10255
10555
|
for (const e of entryPoints) emit2(` ${toDisplayPath(getDisplayRoot(opts.cwd), e.file)}`);
|
|
10256
10556
|
emit2(cyclesTruncated ? `cycles (first ${cycles.length}, truncated at the ${MAX_CYCLES}-cycle enumeration limit: more cycles exist):` : `cycles (${cycles.length} found):`);
|
|
10257
10557
|
for (const c of cycles) emit2(` ${c.map((f) => toDisplayPath(getDisplayRoot(opts.cwd), f)).join(" -> ")}`);
|
|
10558
|
+
if (moduleResult !== null) for (const line of renderModules(moduleResult, top)) emit2(line);
|
|
10258
10559
|
return 0;
|
|
10259
10560
|
}
|
|
10260
10561
|
function runBlame(opts) {
|
|
@@ -10301,7 +10602,12 @@ function runAsk(opts) {
|
|
|
10301
10602
|
}
|
|
10302
10603
|
const top = opts.top ?? 8;
|
|
10303
10604
|
const rootDir = resolveProjectRoot({ project: process.cwd() });
|
|
10304
|
-
const
|
|
10605
|
+
const fetched = searchSymbolsFts(opts.question, top + 1, void 0, rootDir);
|
|
10606
|
+
const moreBeyondTop = fetched.length > top;
|
|
10607
|
+
const hits = fetched.slice(0, top);
|
|
10608
|
+
if (moreBeyondTop) {
|
|
10609
|
+
emitErr2(`Answer is grounded in the top ${countNoun(top, "match", "matches")}; more matched (raise --top to widen the evidence).`);
|
|
10610
|
+
}
|
|
10305
10611
|
const BACKEND_ENV = "TOKEN_GOAT_ASK_BACKEND";
|
|
10306
10612
|
const backendLabel = process.env[BACKEND_ENV] ?? "";
|
|
10307
10613
|
const entries = hits.map((h) => ({ file: h.filePath, symbol: h.name, kind: h.kind, line: h.lineStart, readCmd: `token-goat read "${h.filePath}::${h.name}@${h.lineStart}"` }));
|
|
@@ -10505,10 +10811,10 @@ function resolveHandoff(name, opts = {}) {
|
|
|
10505
10811
|
}
|
|
10506
10812
|
|
|
10507
10813
|
export {
|
|
10508
|
-
getTrackedFiles,
|
|
10509
10814
|
extractSection,
|
|
10510
10815
|
readSection,
|
|
10511
10816
|
listSections,
|
|
10817
|
+
buildImportGraph,
|
|
10512
10818
|
ALL_SYMBOLS_IN_FILE_LIMIT,
|
|
10513
10819
|
enclosingSymbol,
|
|
10514
10820
|
runCallers,
|