token-goat 2.9.4 → 2.9.5
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 +7 -4
- package/dist/{token-goat-chunk-GEXHIIKM.mjs → token-goat-chunk-2FVSKFZU.mjs} +5 -5
- package/dist/{token-goat-chunk-US57I7GN.mjs → token-goat-chunk-4P6GTCMM.mjs} +220 -23
- package/dist/{token-goat-chunk-6MU6FHE3.mjs → token-goat-chunk-5T2K7DEE.mjs} +62 -44
- package/dist/{token-goat-chunk-OZAEJQ7L.mjs → token-goat-chunk-DRL5USXI.mjs} +3 -3
- package/dist/{token-goat-chunk-EQKNR7CN.mjs → token-goat-chunk-GFBXHGFY.mjs} +5 -5
- package/dist/{token-goat-chunk-EPX5DWGM.mjs → token-goat-chunk-HTJP6FHK.mjs} +2 -1
- package/dist/{token-goat-chunk-FSC44QOH.mjs → token-goat-chunk-JO5JX72D.mjs} +2 -2
- package/dist/{token-goat-chunk-5BHXZEOI.mjs → token-goat-chunk-KFFAZ5DJ.mjs} +2 -2
- package/dist/{token-goat-chunk-CBO45DYZ.mjs → token-goat-chunk-U4FTM2SB.mjs} +9797 -9400
- package/dist/{token-goat-chunk-63XEQMNU.mjs → token-goat-chunk-ZLP6TCGN.mjs} +215 -27
- package/dist/{token-goat-chunk-3ZR4NLB3.mjs → token-goat-chunk-ZOKNDG6V.mjs} +220 -99
- package/dist/token-goat-hook.mjs +5 -5
- package/dist/token-goat.core.mjs +5 -5
- package/docs/security.md +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ permalink: /
|
|
|
11
11
|
|
|
12
12
|
***Give the model what it needs, not everything you have.***
|
|
13
13
|
|
|
14
|
-
**85%** smaller reads · **97.4%** image compression · **180+** filter & interception rules · **94–99%** skill overhead cut · compaction memory · **prompt injection** guard · **3.7 GB** never reached the model · **1.1 Gt** tokens saved
|
|
14
|
+
**85%** smaller reads · **49%** of first-read bytes withheld · **97.4%** image compression · **180+** filter & interception rules · **94–99%** skill overhead cut · compaction memory · **prompt injection** guard · **3.7 GB** never reached the model · **1.1 Gt** tokens saved
|
|
15
15
|
|
|
16
16
|
**Reduces AI token use/costs by 40–90%, and improves its focus. Fully automated, always online.**
|
|
17
17
|
|
|
@@ -70,7 +70,8 @@ The fastest way to reduce AI token costs is fixing these five, not writing short
|
|
|
70
70
|
| 3.3 MB screenshot lands in model context | 84 KB compressed copy, 97.4% smaller |
|
|
71
71
|
| Agent re-reads files from earlier in the session | "Already read this" reminder with narrow slice suggestion |
|
|
72
72
|
| Read tool asks for lines the session was already given | Answered with a pointer at the copy already delivered instead of the file, when the text this read would return matches the text already served for it whole line for whole line. Proof rather than a read count, so it also covers a file inside the recent-read protection window; a changed file, a wider range, and `reread_deny = false` all pass through |
|
|
73
|
-
| Same unchanged file read again through the shell (`cat`, `head`, `tail`, `sed -n '1,40p'`) | Byte-identical repeat replaced with a one-line pointer instead of the whole body
|
|
73
|
+
| Same unchanged file read again through the shell (`cat`, `head`, `tail`, `sed -n '1,40p'`) | Byte-identical repeat replaced with a one-line pointer instead of the whole body: 4,031 bytes to 189 on this project. A later read wholly inside an earlier one collapses the same way |
|
|
74
|
+
| A shell read of a file overlaps an earlier one without sitting inside it (`sed -n '100,140p'` after `sed -n '120,160p'`) | Only the already-shown stretch is withheld, replaced in place by one line naming its line numbers and the command that returns it; every line not shown before arrives untouched. 56% of the second read on a real pair over this project's README. Line numbers come from the command's own ranges, so a `tail`, whose start the command does not state, is left alone. Full text stays available via `token-goat bash-output <id>` |
|
|
74
75
|
| Part of a file re-read under a different command (`head -40 F` then `sed -n '1,30p' F`) | Repeat replaced with a pointer when every line coming back was already served for that same file this session. Matched on the text, on whole-line boundaries, so a read that adds any new lines is left whole; the record is dropped when the file is edited or the conversation is compacted. A file read with the Read tool counts as served too, limited to the lines that read actually handed over, and a read that came back truncated counts for nothing |
|
|
75
76
|
| Read tool asks for a range that overlaps one already delivered | Only the overlapping stretch is withheld, replaced by one line naming the line numbers and the recall command; the new lines come through with their own numbers and spacing, byte for byte. A stretch is kept whenever dropping it would save less than the line replacing it costs, and a result carrying anything the redactor would strip, a truncated result, or a file changed on disk all pass through whole. Set `elide_served_lines = false` to disable |
|
|
76
77
|
| Shell command run with colour on (`git`, `npm`, `npx`, `token-goat`) | Terminal escape sequences removed, leaving byte-for-byte the same output with colour off: 13.2% smaller on a real `git diff` here, and about a quarter of the bytes on the calls it fires for. Nothing is summarized or withheld, so there is no recall pointer; it runs on failed commands too, and only when the escapes are worth a rewrite |
|
|
@@ -114,7 +115,7 @@ The fastest way to reduce AI token costs is fixing these five, not writing short
|
|
|
114
115
|
| Index-only files (lockfiles, source maps, bundles) read on every session | Pre-Read suppression for read-only files (package-lock.json, *.map, dist/), skipped unless explicitly edited |
|
|
115
116
|
| Large markdown file read in full (README.md, CHANGELOG.md, CLAUDE.md ≥8 KB) | Heading tree intercepted instead — H1–H3 with `#2`/`#3` disambiguation; `token-goat section` shortcuts listed for well-known files; post-edit injects a re-read suggestion rather than the full file |
|
|
116
117
|
| Subagent reads a ≥30 KB markdown file whole, on its first look at it | Off by default. Set `subagent_markdown_first_read_deny = true` under `[hints]` to block that read and answer with the heading tree instead. Only fires in a subagent, only on a first, un-ranged read of a `.md`/`.mdx`/`.markdown` file with at least three headings; a read that already asks for a line range, and every main-session read, pass through untouched |
|
|
117
|
-
| A source file is read whole for the first time, with no earlier copy to compare it against |
|
|
118
|
+
| A source file is read whole for the first time, with no earlier copy to compare it against | Keeps each function's declaration and its first eight lines, replacing the rest with one line naming the symbol, the exact range removed, and the command that returns it. Set `fold_code_bodies = false` under `[hints]` to turn it off. Comment blocks of twelve lines or more fold to their first two on the same terms. Imports, signatures, type declarations, classes and interfaces are never folded, and a file whose index no longer matches what is on disk keeps its bodies. Measured on this repository's own source: 229 of 256 files fold, and 43% of what a read of them delivers is removed. A read that already names an offset or a limit, and any file holding something that looks like a secret, pass through untouched |
|
|
118
119
|
| PDF opened via Read | Full read denied; PDF shows page count and outline (`token-goat pdf-extract` pulls the actual text, optionally paged/sliced, when the outline isn't enough) |
|
|
119
120
|
| Excel/PowerPoint/Word file (.xlsx/.pptx/.docx) opened via Read | Full read denied; redirects to the matching narrow-slice command family (`xlsx-sheets`/`xlsx-head`/`xlsx-range`/`xlsx-query`, `pptx-outline`/`pptx-slide`/`pptx-notes`/`pptx-text`, `docx-outline`/`docx-text`) instead of extracting the whole document as text |
|
|
120
121
|
| Other Office binary (.odt, .ods, .ott, .odp) opened via Read | Full read denied; redirects to `pandoc` for text extraction (no dedicated reader for these formats yet) |
|
|
@@ -185,10 +186,12 @@ Returns relevance-ranked, distance-scored hits straight from the notes, the same
|
|
|
185
186
|
|
|
186
187
|
## Token savings, measured
|
|
187
188
|
|
|
188
|
-
Numbers below come from synthetic-fixture benchmarks in the test suite. Each row points at the source file where the measurement is reproduced.
|
|
189
|
+
Numbers below come from synthetic-fixture benchmarks in the test suite, except the first two rows, which are measured on a corpus of real sessions and say so. Each row points at the source file where the measurement is reproduced.
|
|
189
190
|
|
|
190
191
|
| Source | Improvement | Measured impact | Where |
|
|
191
192
|
|--------|-------------|-----------------|-------|
|
|
193
|
+
| Large-document outline | A read naming no `offset` or `limit` on a markdown document over 8 KB with six or more headings returns the lead-in and heading tree, plus the `token-goat section` command that reads any section verbatim | Measured on 13,870 real reads across 5,104 sessions: withholds 40.4% of all bytes the Read tool delivers. A 104,890 B document returns 1,541 B with its opening paragraph intact. Sections sum to the document, so a reader who pulls every one back pays about 3% over reading it whole | `src/hooks_read.ts` (`foldMarkdownOutline`) |
|
|
194
|
+
| Large-source skeleton | A read naming no `offset` or `limit` on a source file over 12 KB with eight or more declarations returns the preamble and one line per declaration, each withheld run naming the `token-goat read "file::Symbol"` or ranged `Read` that returns it | Measured on the same corpus: withholds up to 8.6% of all bytes the Read tool delivers, a ceiling rather than a booked total, since the shipping gates are narrower than the measurement's. The skeleton is 10.5% of a `.ts` file. Median symbol body is 4.1% of its file, so a reader breaks even at roughly 22 bodies pulled back out of an average 30.8 | `src/hooks_read.ts` (`foldSourceSkeleton`) |
|
|
192
195
|
| Image shrink | Every still is encoded both ways and the smaller file wins, rather than one codec being assumed | 2560x1440 screenshot-shaped PNG: 2,782,963 -> 259,475 bytes (91% smaller) | `src/image_shrink.ts` (codec selection) |
|
|
193
196
|
| Repomap output | `--compact` trims the top-symbols list to 10 (vs 30) and drops the recent-files section and per-symbol locations | Denser overview for the same byte budget | `src/baseline.ts` (`buildProjectMap`, `token-goat map --compact`) |
|
|
194
197
|
| DB reindex | Batched single transaction + composite indexes on `(file_id, kind)` | 100 files / 10K rows: 84 s → 1 s (~80× faster) | `src/parser.ts`, `src/db.ts` (index migration) |
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
expandGlobs,
|
|
8
8
|
leftoverIntegrations,
|
|
9
9
|
run
|
|
10
|
-
} from "./token-goat-chunk-
|
|
11
|
-
import "./token-goat-chunk-
|
|
12
|
-
import "./token-goat-chunk-
|
|
13
|
-
import "./token-goat-chunk-
|
|
14
|
-
import "./token-goat-chunk-
|
|
10
|
+
} from "./token-goat-chunk-5T2K7DEE.mjs";
|
|
11
|
+
import "./token-goat-chunk-4P6GTCMM.mjs";
|
|
12
|
+
import "./token-goat-chunk-JO5JX72D.mjs";
|
|
13
|
+
import "./token-goat-chunk-U4FTM2SB.mjs";
|
|
14
|
+
import "./token-goat-chunk-ZOKNDG6V.mjs";
|
|
15
15
|
import "./token-goat-chunk-EEIDFMEM.mjs";
|
|
16
16
|
import "./token-goat-chunk-A37V4PBF.mjs";
|
|
17
17
|
export {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
+
DEFAULT_QUERY_LIMIT,
|
|
4
5
|
IMPORT_RE,
|
|
5
6
|
ImageDecodeError,
|
|
6
7
|
MAX_OVER_FETCH,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
extractPdfText,
|
|
26
27
|
fenceUntrusted,
|
|
27
28
|
fenceUntrustedContent,
|
|
29
|
+
fenceUntrustedFileContent,
|
|
28
30
|
formatCsvProfile,
|
|
29
31
|
formatCsvTable,
|
|
30
32
|
getEmbeddingCoverage,
|
|
@@ -68,7 +70,7 @@ import {
|
|
|
68
70
|
walkProject,
|
|
69
71
|
yamlLineClosesQuote,
|
|
70
72
|
yamlOpenQuoteAfter
|
|
71
|
-
} from "./token-goat-chunk-
|
|
73
|
+
} from "./token-goat-chunk-U4FTM2SB.mjs";
|
|
72
74
|
import {
|
|
73
75
|
Database,
|
|
74
76
|
PER_FILE_COUNTERFACTUAL_CEILING,
|
|
@@ -122,7 +124,7 @@ import {
|
|
|
122
124
|
unsupportedLanguageName,
|
|
123
125
|
windowsCmdQuoteArg,
|
|
124
126
|
withExtension
|
|
125
|
-
} from "./token-goat-chunk-
|
|
127
|
+
} from "./token-goat-chunk-ZOKNDG6V.mjs";
|
|
126
128
|
import {
|
|
127
129
|
registerReset
|
|
128
130
|
} from "./token-goat-chunk-EEIDFMEM.mjs";
|
|
@@ -458,6 +460,69 @@ import * as path6 from "node:path";
|
|
|
458
460
|
import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
459
461
|
import { randomUUID } from "node:crypto";
|
|
460
462
|
|
|
463
|
+
// src/ref_blindness.ts
|
|
464
|
+
init_define_import_meta_env();
|
|
465
|
+
var REF_INDEXED_LANGUAGES = /* @__PURE__ */ new Set([
|
|
466
|
+
"typescript",
|
|
467
|
+
"javascript",
|
|
468
|
+
"python",
|
|
469
|
+
"go",
|
|
470
|
+
"rust",
|
|
471
|
+
"java",
|
|
472
|
+
"c",
|
|
473
|
+
"cpp",
|
|
474
|
+
"ruby"
|
|
475
|
+
]);
|
|
476
|
+
function isRefIndexedLanguage(language) {
|
|
477
|
+
return REF_INDEXED_LANGUAGES.has(language);
|
|
478
|
+
}
|
|
479
|
+
function isRefIndexedFile(filePath) {
|
|
480
|
+
return isRefIndexedLanguage(detectLanguage(filePath));
|
|
481
|
+
}
|
|
482
|
+
var LANGUAGE_LABELS = /* @__PURE__ */ new Map([
|
|
483
|
+
["csharp", "C#"],
|
|
484
|
+
["cpp", "C++"],
|
|
485
|
+
["c", "C"],
|
|
486
|
+
["php", "PHP"],
|
|
487
|
+
["powershell", "PowerShell"],
|
|
488
|
+
["sql", "SQL"],
|
|
489
|
+
["graphql", "GraphQL"],
|
|
490
|
+
["proto", "Protocol Buffers"],
|
|
491
|
+
["html", "HTML"],
|
|
492
|
+
["css", "CSS"],
|
|
493
|
+
["toml", "TOML"],
|
|
494
|
+
["json", "JSON"],
|
|
495
|
+
["yaml", "YAML"],
|
|
496
|
+
["ini", "INI"],
|
|
497
|
+
["env_file", "env file"],
|
|
498
|
+
["ipynb", "Jupyter notebook"],
|
|
499
|
+
["salesforce_metadata", "Salesforce metadata"],
|
|
500
|
+
["salesforce_markup", "Salesforce markup"],
|
|
501
|
+
["unknown", "this file type"]
|
|
502
|
+
]);
|
|
503
|
+
function languageLabel(language) {
|
|
504
|
+
return LANGUAGE_LABELS.get(language) ?? language;
|
|
505
|
+
}
|
|
506
|
+
function refBlindLanguageNotice(symbolName, language, displayPath) {
|
|
507
|
+
return `Cannot determine references for '${symbolName}': ${languageLabel(language)} call sites are not indexed (${displayPath}). This is a gap in token-goat's index, not evidence the symbol is unreferenced. Search the source directly instead, e.g. \`rg -n -w ${symbolName}\`.`;
|
|
508
|
+
}
|
|
509
|
+
var REF_BLIND_KIND_REASON = "the index records value-position references only (calls, `new`, macro invocations), never type annotations, so a type declaration has no ref rows however widely it is used";
|
|
510
|
+
var REF_BLIND_DEF_PROBE_LIMIT = 50;
|
|
511
|
+
function kindWithArticle(kind) {
|
|
512
|
+
return `${/^[aeiou]/.test(kind) ? "an" : "a"} ${kind}`;
|
|
513
|
+
}
|
|
514
|
+
function refBlindKindClause(symbolName, kinds) {
|
|
515
|
+
const first = kinds[0];
|
|
516
|
+
if (kinds.length === 1 && first !== void 0) return `'${symbolName}' is ${kindWithArticle(first)}`;
|
|
517
|
+
return `every definition of '${symbolName}' is a type declaration (${kinds.map((k) => `'${k}'`).join(", ")})`;
|
|
518
|
+
}
|
|
519
|
+
function refBlindKindNotice(symbolName, kinds) {
|
|
520
|
+
return `Cannot determine references for '${symbolName}': ${refBlindKindClause(symbolName, kinds)}, and ${REF_BLIND_KIND_REASON}. This is a gap in token-goat's index, not evidence the symbol is unreferenced. Search the source directly instead, e.g. \`rg -n -w ${symbolName}\`.`;
|
|
521
|
+
}
|
|
522
|
+
function refBlindKindPartialNote(symbolName, kinds, blindCount, totalCount) {
|
|
523
|
+
return `Note: ${blindCount} of ${totalCount} definitions of '${symbolName}' (${kinds.map((k) => `'${k}'`).join(", ")}) are not covered by this result -- ${REF_BLIND_KIND_REASON}. The empty result above speaks only for the other ${totalCount - blindCount}; for the rest, search the source directly, e.g. \`rg -n -w ${symbolName}\`.`;
|
|
524
|
+
}
|
|
525
|
+
|
|
461
526
|
// src/read_commands.ts
|
|
462
527
|
init_define_import_meta_env();
|
|
463
528
|
import * as fs4 from "node:fs";
|
|
@@ -5435,6 +5500,15 @@ function guardJsonRows(items) {
|
|
|
5435
5500
|
if (!cfg.overflow_guard.enabled) return { items: [...items], truncated: false, totalCount: items.length };
|
|
5436
5501
|
return capJsonRows(items, cfg.overflow_guard.max_tokens);
|
|
5437
5502
|
}
|
|
5503
|
+
function changedDiffBaselineBytes(cwd, ref, files) {
|
|
5504
|
+
if (files.length === 0) return 0;
|
|
5505
|
+
try {
|
|
5506
|
+
const result = runGit(["diff", ref, "--unified=0", "--", ...files], { cwd });
|
|
5507
|
+
if (result.exitCode === 0) return Buffer.byteLength(result.stdout, "utf8");
|
|
5508
|
+
} catch {
|
|
5509
|
+
}
|
|
5510
|
+
return 0;
|
|
5511
|
+
}
|
|
5438
5512
|
function sumFileSizes(filePaths) {
|
|
5439
5513
|
let total = 0;
|
|
5440
5514
|
for (const fp of new Set(filePaths)) {
|
|
@@ -5822,9 +5896,9 @@ function truncationFooter(shown, limit, total, plural, flag) {
|
|
|
5822
5896
|
|
|
5823
5897
|
token-goat: ${notice}`;
|
|
5824
5898
|
}
|
|
5825
|
-
function refsTotal(clientFiltered, filteredTotal, shown, countExact, preScanCount) {
|
|
5899
|
+
function refsTotal(clientFiltered, filteredTotal, shown, countExact, preScanCount, scanLimit) {
|
|
5826
5900
|
if (!clientFiltered) return { count: countExact(), exact: true };
|
|
5827
|
-
return { count: filteredTotal ?? shown, exact: preScanCount <
|
|
5901
|
+
return { count: filteredTotal ?? shown, exact: preScanCount < scanLimit };
|
|
5828
5902
|
}
|
|
5829
5903
|
function truncationNotice(shown, limit, total, plural, flag) {
|
|
5830
5904
|
if (shown < limit) return null;
|
|
@@ -6037,9 +6111,11 @@ function resolveSymbolSpec(spec, forceRefresh, projectRoot) {
|
|
|
6037
6111
|
});
|
|
6038
6112
|
}
|
|
6039
6113
|
if (methodName !== void 0 && candidates.length > 1) {
|
|
6114
|
+
const containerBaseName = file.slice(Math.max(file.lastIndexOf("/"), file.lastIndexOf("\\")) + 1);
|
|
6040
6115
|
const containers = querySymbols({
|
|
6041
6116
|
name: symBase,
|
|
6042
6117
|
limit: 50,
|
|
6118
|
+
...containerBaseName !== "" ? { fileBaseName: containerBaseName } : {},
|
|
6043
6119
|
...projectRoot !== void 0 ? { rootDir: projectRoot } : {}
|
|
6044
6120
|
});
|
|
6045
6121
|
const symBaseLower = symBase.toLowerCase();
|
|
@@ -6355,7 +6431,9 @@ function renderRefsTargets(targets, opts, {
|
|
|
6355
6431
|
if (rootDir !== void 0) queryOpts.rootDir = rootDir;
|
|
6356
6432
|
const scanned = queryRefs(queryOpts);
|
|
6357
6433
|
const preScanCount = scanned.length;
|
|
6434
|
+
const scanLimit = queryOpts.limit ?? DEFAULT_QUERY_LIMIT;
|
|
6358
6435
|
let results = applyTypedRefsTier(symbol, file, scanned);
|
|
6436
|
+
const typedFilterDropped = results.length < scanned.length;
|
|
6359
6437
|
let suppressed = 0;
|
|
6360
6438
|
if (opts.excludeTests === true) {
|
|
6361
6439
|
const f = applyExcludeTestsFilter(results);
|
|
@@ -6365,9 +6443,10 @@ function renderRefsTargets(targets, opts, {
|
|
|
6365
6443
|
const preGrepCount = results.length;
|
|
6366
6444
|
const matchesGrep = refGrepFilter(opts.grep);
|
|
6367
6445
|
if (matchesGrep !== void 0) results = results.filter(matchesGrep);
|
|
6446
|
+
const clientFiltered = opts.excludeTests === true || matchesGrep !== void 0 || typedFilterDropped;
|
|
6368
6447
|
let filteredTotal;
|
|
6369
|
-
if (
|
|
6370
|
-
if (
|
|
6448
|
+
if (clientFiltered) filteredTotal = results.length;
|
|
6449
|
+
if (clientFiltered && opts.top === void 0) {
|
|
6371
6450
|
results = results.slice(0, opts.limit ?? 100);
|
|
6372
6451
|
}
|
|
6373
6452
|
if (results.length > 0) anyFound = true;
|
|
@@ -6379,7 +6458,7 @@ function renderRefsTargets(targets, opts, {
|
|
|
6379
6458
|
jsonOut[key] = withHidden(topFilesJsonPayload(results, opts.top));
|
|
6380
6459
|
} else {
|
|
6381
6460
|
const capped = guardJsonRows(results);
|
|
6382
|
-
const trueTotal =
|
|
6461
|
+
const trueTotal = clientFiltered ? filteredTotal ?? results.length : countRefs(queryOpts);
|
|
6383
6462
|
jsonOut[key] = withHidden({ items: refsJsonItems(capped.items, opts.context ?? 0), truncated: capped.truncated || trueTotal > results.length, totalCount: trueTotal });
|
|
6384
6463
|
}
|
|
6385
6464
|
continue;
|
|
@@ -6406,7 +6485,7 @@ function renderRefsTargets(targets, opts, {
|
|
|
6406
6485
|
const notice = truncationNotice(
|
|
6407
6486
|
results.length,
|
|
6408
6487
|
opts.limit ?? 100,
|
|
6409
|
-
() => refsTotal(
|
|
6488
|
+
() => refsTotal(clientFiltered, filteredTotal, results.length, () => countRefs(queryOpts), preScanCount, scanLimit),
|
|
6410
6489
|
"references",
|
|
6411
6490
|
"--limit"
|
|
6412
6491
|
);
|
|
@@ -6482,7 +6561,9 @@ function runRefsSingle(opts) {
|
|
|
6482
6561
|
if (rootDir !== void 0) queryOpts.rootDir = rootDir;
|
|
6483
6562
|
const scanned = queryRefs(queryOpts);
|
|
6484
6563
|
const preScanCount = scanned.length;
|
|
6564
|
+
const scanLimit = queryOpts.limit ?? DEFAULT_QUERY_LIMIT;
|
|
6485
6565
|
let results = applyTypedRefsTier(symName, defFileHint, scanned);
|
|
6566
|
+
const typedFilterDropped = results.length < scanned.length;
|
|
6486
6567
|
let suppressed = 0;
|
|
6487
6568
|
if (opts.excludeTests === true) {
|
|
6488
6569
|
const f = applyExcludeTestsFilter(results);
|
|
@@ -6492,9 +6573,10 @@ function runRefsSingle(opts) {
|
|
|
6492
6573
|
const preGrepCount = results.length;
|
|
6493
6574
|
const matchesGrep = refGrepFilter(opts.grep);
|
|
6494
6575
|
if (matchesGrep !== void 0) results = results.filter(matchesGrep);
|
|
6576
|
+
const clientFiltered = opts.excludeTests === true || matchesGrep !== void 0 || typedFilterDropped;
|
|
6495
6577
|
let filteredTotal;
|
|
6496
|
-
if (
|
|
6497
|
-
if (
|
|
6578
|
+
if (clientFiltered) filteredTotal = results.length;
|
|
6579
|
+
if (clientFiltered && opts.top === void 0) {
|
|
6498
6580
|
results = results.slice(0, opts.limit ?? 100);
|
|
6499
6581
|
}
|
|
6500
6582
|
if (results.length === 0) {
|
|
@@ -6511,12 +6593,26 @@ function runRefsSingle(opts) {
|
|
|
6511
6593
|
return 1;
|
|
6512
6594
|
}
|
|
6513
6595
|
const rootDir2 = opts.projectRoot ?? resolveProjectRoot({ project: process.cwd() });
|
|
6514
|
-
|
|
6596
|
+
const defRows = querySymbols({ name: symName, rootDir: rootDir2, limit: REF_BLIND_DEF_PROBE_LIMIT });
|
|
6597
|
+
if (defRows.length === 0) {
|
|
6515
6598
|
emitErr(`Symbol not found: ${symName}${unknownSymbolSuggestion(symName, rootDir2)}`);
|
|
6516
6599
|
if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir2)) emitErr(emptyIndexMessage(rootDir2));
|
|
6517
6600
|
return 1;
|
|
6518
6601
|
}
|
|
6602
|
+
const defPaths = defFileHint !== void 0 ? [defFileHint] : defRows.map((r) => r.filePath);
|
|
6603
|
+
const firstDefPath = defPaths[0];
|
|
6604
|
+
if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
|
|
6605
|
+
emitErr(refBlindLanguageNotice(symName, detectLanguage(firstDefPath), refsDisplayPath(firstDefPath)));
|
|
6606
|
+
return 1;
|
|
6607
|
+
}
|
|
6608
|
+
const kindRows = defFileHint !== void 0 ? querySymbols({ name: symName, filePath: defFileHint, rootDir: rootDir2, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
|
|
6609
|
+
const kindVerdict = refBlindKindVerdict(kindRows);
|
|
6610
|
+
if (kindVerdict.allBlind) {
|
|
6611
|
+
emitErr(refBlindKindNotice(symName, kindVerdict.blindKinds));
|
|
6612
|
+
return 1;
|
|
6613
|
+
}
|
|
6519
6614
|
emitErr(`No references found for '${symName}'`);
|
|
6615
|
+
if (kindVerdict.blindCount > 0) emitErr(refBlindKindPartialNote(symName, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
|
|
6520
6616
|
if (opts.json !== true) {
|
|
6521
6617
|
if (isIndexEmptyForProject(globalDbPath(), rootDir2)) emitErr(emptyIndexMessage(rootDir2));
|
|
6522
6618
|
}
|
|
@@ -6529,7 +6625,7 @@ function runRefsSingle(opts) {
|
|
|
6529
6625
|
payload = topFilesJsonPayload(results, opts.top);
|
|
6530
6626
|
} else {
|
|
6531
6627
|
const capped = guardJsonRows(results);
|
|
6532
|
-
const trueTotal =
|
|
6628
|
+
const trueTotal = clientFiltered ? filteredTotal ?? results.length : countRefs(queryOpts);
|
|
6533
6629
|
payload = { items: refsJsonItems(capped.items, opts.context ?? 0), truncated: capped.truncated || trueTotal > results.length, totalCount: trueTotal };
|
|
6534
6630
|
}
|
|
6535
6631
|
const hiddenByGrep = matchesGrep !== void 0 ? preGrepCount - (filteredTotal ?? results.length) : 0;
|
|
@@ -6539,7 +6635,7 @@ function runRefsSingle(opts) {
|
|
|
6539
6635
|
return 0;
|
|
6540
6636
|
}
|
|
6541
6637
|
const lines = opts.top !== void 0 ? renderTopFilesSummary(results, opts.top, suppressed) : opts.callers === true ? [...opts.excludeTests === true && suppressed > 0 ? [`${countNoun(results.length, "reference")} (${excludeTestsHiddenNote(suppressed)})`] : [], ...renderCallerGroups(results, opts.context ?? 0)] : [...opts.excludeTests === true && suppressed > 0 ? [`${countNoun(results.length, "reference")} (${excludeTestsHiddenNote(suppressed)})`] : [], ...results.flatMap((ref) => renderRefLines(ref, opts.context ?? 0, ""))];
|
|
6542
|
-
const refsFooter = opts.top !== void 0 ? "" : truncationFooter(results.length, opts.limit ?? 100, () => refsTotal(
|
|
6638
|
+
const refsFooter = opts.top !== void 0 ? "" : truncationFooter(results.length, opts.limit ?? 100, () => refsTotal(clientFiltered, filteredTotal, results.length, () => countRefs(queryOpts), preScanCount, scanLimit), "references", "--limit");
|
|
6543
6639
|
const text = lines.join("\n");
|
|
6544
6640
|
emit(guardText(text, "symbol") + refsFooter);
|
|
6545
6641
|
recordReadStat("symbol_read", fullSourceBytes, text + refsFooter, symName);
|
|
@@ -6726,7 +6822,23 @@ function runSkeleton(opts) {
|
|
|
6726
6822
|
return { text, code: 0 };
|
|
6727
6823
|
}
|
|
6728
6824
|
var DOC_SUMMARY_MAX_CHARS = 140;
|
|
6825
|
+
function firstSentenceEnd(line) {
|
|
6826
|
+
const MIN_SENTENCE_CHARS = 30;
|
|
6827
|
+
const ABBREV = new RegExp("(?:\\b(?:e\\.g|i\\.e|vs|cf|etc|approx|al|Dr|Mr|Ms|St|Fig|No)\\.|\\b\\p{L}\\.)$", "u");
|
|
6828
|
+
for (const m of line.matchAll(/[.!?](?=\s|$)/gu)) {
|
|
6829
|
+
const end = m.index + 1;
|
|
6830
|
+
if (end < MIN_SENTENCE_CHARS) continue;
|
|
6831
|
+
const head = line.slice(0, end);
|
|
6832
|
+
if (ABBREV.test(head)) continue;
|
|
6833
|
+
return end;
|
|
6834
|
+
}
|
|
6835
|
+
return null;
|
|
6836
|
+
}
|
|
6729
6837
|
function clipDocSummary(firstLine) {
|
|
6838
|
+
const sentence = firstSentenceEnd(firstLine);
|
|
6839
|
+
if (sentence !== null && sentence <= DOC_SUMMARY_MAX_CHARS) {
|
|
6840
|
+
return sentence === firstLine.length ? firstLine : `${firstLine.slice(0, sentence)}\u2026`;
|
|
6841
|
+
}
|
|
6730
6842
|
if (firstLine.length <= DOC_SUMMARY_MAX_CHARS) return firstLine;
|
|
6731
6843
|
const cut = firstLine.lastIndexOf(" ", DOC_SUMMARY_MAX_CHARS);
|
|
6732
6844
|
return `${firstLine.slice(0, cut > 40 ? cut : DOC_SUMMARY_MAX_CHARS).trimEnd()}\u2026`;
|
|
@@ -7930,10 +8042,12 @@ function runChanged(opts = {}) {
|
|
|
7930
8042
|
}
|
|
7931
8043
|
if (opts.symbolMode === true) {
|
|
7932
8044
|
let hunksByFile = /* @__PURE__ */ new Map();
|
|
8045
|
+
let symbolDiffBaselineBytes = 0;
|
|
7933
8046
|
try {
|
|
7934
|
-
const diffResult = runGit(["diff", ref, "--unified=0"], { cwd });
|
|
8047
|
+
const diffResult = runGit(["diff", ref, "--unified=0", "--", ...changedFiles], { cwd });
|
|
7935
8048
|
if (diffResult.exitCode === 0) {
|
|
7936
8049
|
hunksByFile = parseDiffHunks(diffResult.stdout);
|
|
8050
|
+
symbolDiffBaselineBytes = Buffer.byteLength(diffResult.stdout, "utf8");
|
|
7937
8051
|
}
|
|
7938
8052
|
} catch {
|
|
7939
8053
|
}
|
|
@@ -7949,7 +8063,7 @@ function runChanged(opts = {}) {
|
|
|
7949
8063
|
emit("No symbols changed.");
|
|
7950
8064
|
return 0;
|
|
7951
8065
|
}
|
|
7952
|
-
const symbolFullBytes =
|
|
8066
|
+
const symbolFullBytes = symbolDiffBaselineBytes;
|
|
7953
8067
|
if (opts.json === true) {
|
|
7954
8068
|
const capped = guardJsonRows(allSymbols);
|
|
7955
8069
|
const text = JSON.stringify({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }, null, 2);
|
|
@@ -7964,7 +8078,7 @@ function runChanged(opts = {}) {
|
|
|
7964
8078
|
recordReadStat("changed_lookup", symbolFullBytes, symbolText, ref);
|
|
7965
8079
|
return 0;
|
|
7966
8080
|
}
|
|
7967
|
-
const fullBytes =
|
|
8081
|
+
const fullBytes = changedDiffBaselineBytes(cwd, ref, changedFiles);
|
|
7968
8082
|
if (opts.json === true) {
|
|
7969
8083
|
const capped = guardJsonRows(changedFiles);
|
|
7970
8084
|
const text = JSON.stringify({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }, null, 2);
|
|
@@ -9701,12 +9815,26 @@ function runCallers(opts) {
|
|
|
9701
9815
|
emitErr2(`No non-test references found for '${opts.symbol}' (${excludeTestsHiddenNote(suppressed)})`);
|
|
9702
9816
|
return 1;
|
|
9703
9817
|
}
|
|
9704
|
-
|
|
9818
|
+
const defRows = querySymbols({ name, rootDir, limit: REF_BLIND_DEF_PROBE_LIMIT });
|
|
9819
|
+
if (defRows.length === 0) {
|
|
9705
9820
|
emitErr2(`Symbol not found: ${opts.symbol}${unknownSymbolSuggestion(name, rootDir)}`);
|
|
9706
9821
|
if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr2(emptyIndexMessage(rootDir));
|
|
9707
9822
|
return 1;
|
|
9708
9823
|
}
|
|
9824
|
+
const defPaths = fileHint !== void 0 ? [fileHint] : defRows.map((r) => r.filePath);
|
|
9825
|
+
const firstDefPath = defPaths[0];
|
|
9826
|
+
if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
|
|
9827
|
+
emitErr2(refBlindLanguageNotice(name, detectLanguage(firstDefPath), toDisplayPath(rootDir, firstDefPath)));
|
|
9828
|
+
return 1;
|
|
9829
|
+
}
|
|
9830
|
+
const kindRows = fileHint !== void 0 ? querySymbols({ name, filePath: fileHint, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
|
|
9831
|
+
const kindVerdict = refBlindKindVerdict(kindRows);
|
|
9832
|
+
if (kindVerdict.allBlind) {
|
|
9833
|
+
emitErr2(refBlindKindNotice(name, kindVerdict.blindKinds));
|
|
9834
|
+
return 1;
|
|
9835
|
+
}
|
|
9709
9836
|
emitErr2(`No references found for '${opts.symbol}'`);
|
|
9837
|
+
if (kindVerdict.blindCount > 0) emitErr2(refBlindKindPartialNote(name, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
|
|
9710
9838
|
if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr2(emptyIndexMessage(rootDir));
|
|
9711
9839
|
return 1;
|
|
9712
9840
|
}
|
|
@@ -9754,6 +9882,14 @@ function runCallChain(opts) {
|
|
|
9754
9882
|
if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr2(emptyIndexMessage(rootDir));
|
|
9755
9883
|
return 1;
|
|
9756
9884
|
}
|
|
9885
|
+
const refBlindRootPath = () => {
|
|
9886
|
+
const paths = fileHint !== void 0 ? [fileHint] : querySymbols({ name, rootDir, limit: REF_BLIND_DEF_PROBE_LIMIT }).map((r) => r.filePath);
|
|
9887
|
+
return paths.length > 0 && paths.every((fp) => !isRefIndexedFile(fp)) ? paths[0] : void 0;
|
|
9888
|
+
};
|
|
9889
|
+
const refBlindRootKinds = () => {
|
|
9890
|
+
const rows = fileHint !== void 0 ? querySymbols({ name, filePath: fileHint, limit: REF_BLIND_DEF_PROBE_LIMIT }) : querySymbols({ name, rootDir, limit: REF_BLIND_DEF_PROBE_LIMIT });
|
|
9891
|
+
return { ...refBlindKindVerdict(rows), total: rows.length };
|
|
9892
|
+
};
|
|
9757
9893
|
const getSyms = buildFileSymCache();
|
|
9758
9894
|
let suppressedCount = 0;
|
|
9759
9895
|
const callersOf = (n) => {
|
|
@@ -9778,7 +9914,10 @@ function runCallChain(opts) {
|
|
|
9778
9914
|
if (opts.json === true) {
|
|
9779
9915
|
const hiddenByGrep = chains.length - filteredChains.length;
|
|
9780
9916
|
const hiddenByExcludeTests = noCallers && opts.excludeTests === true ? suppressedCount : 0;
|
|
9781
|
-
|
|
9917
|
+
const refBlindKinds = noCallers ? refBlindRootKinds().blindKinds : [];
|
|
9918
|
+
const blindRootPath = noCallers ? refBlindRootPath() : void 0;
|
|
9919
|
+
const refBlindLanguage = blindRootPath !== void 0 ? { language: detectLanguage(blindRootPath), definedIn: toDisplayPath(rootDir, blindRootPath) } : void 0;
|
|
9920
|
+
emit2(JSON.stringify({ chains: filteredChains, ...hiddenByGrep > 0 ? { hiddenByGrep } : {}, ...hiddenByExcludeTests > 0 ? { hiddenByExcludeTests } : {}, ...refBlindKinds.length > 0 ? { refBlindKinds } : {}, ...refBlindLanguage !== void 0 ? { refBlindLanguage } : {} }, null, 2));
|
|
9782
9921
|
return 0;
|
|
9783
9922
|
}
|
|
9784
9923
|
if (noCallers) {
|
|
@@ -9786,7 +9925,20 @@ function runCallChain(opts) {
|
|
|
9786
9925
|
emit2(`${name} (no non-test callers; ${excludeTestsHiddenNote(suppressedCount)})`);
|
|
9787
9926
|
return 0;
|
|
9788
9927
|
}
|
|
9928
|
+
const blindRoot = refBlindRootPath();
|
|
9929
|
+
if (blindRoot !== void 0) {
|
|
9930
|
+
emitErr2(refBlindLanguageNotice(name, detectLanguage(blindRoot), toDisplayPath(rootDir, blindRoot)));
|
|
9931
|
+
emit2(`${name} (no callers recorded)`);
|
|
9932
|
+
return 0;
|
|
9933
|
+
}
|
|
9934
|
+
const rootKinds = refBlindRootKinds();
|
|
9935
|
+
if (rootKinds.allBlind) {
|
|
9936
|
+
emitErr2(refBlindKindNotice(name, rootKinds.blindKinds));
|
|
9937
|
+
emit2(`${name} (no callers recorded)`);
|
|
9938
|
+
return 0;
|
|
9939
|
+
}
|
|
9789
9940
|
emit2(`${name} (no callers)`);
|
|
9941
|
+
if (rootKinds.blindCount > 0) emitErr2(refBlindKindPartialNote(name, rootKinds.blindKinds, rootKinds.blindCount, rootKinds.total));
|
|
9790
9942
|
return 0;
|
|
9791
9943
|
}
|
|
9792
9944
|
if (matchesGrep !== void 0 && filteredChains.length === 0) {
|
|
@@ -9881,11 +10033,25 @@ function runImpact(opts) {
|
|
|
9881
10033
|
emitErr2(`No non-test impact found for '${opts.symbol}' (${excludeTestsHiddenNote(suppressedCount)})`);
|
|
9882
10034
|
return 1;
|
|
9883
10035
|
}
|
|
9884
|
-
|
|
10036
|
+
const defRows = querySymbols({ name: rootName, rootDir, limit: REF_BLIND_DEF_PROBE_LIMIT });
|
|
10037
|
+
if (defRows.length === 0) {
|
|
9885
10038
|
emitErr2(`Symbol not found: ${opts.symbol}${unknownSymbolSuggestion(rootName, rootDir)}`);
|
|
9886
10039
|
return 1;
|
|
9887
10040
|
}
|
|
10041
|
+
const defPaths = fileHint !== void 0 ? [fileHint] : defRows.map((r) => r.filePath);
|
|
10042
|
+
const firstDefPath = defPaths[0];
|
|
10043
|
+
if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
|
|
10044
|
+
emitErr2(refBlindLanguageNotice(rootName, detectLanguage(firstDefPath), toDisplayPath(rootDir, firstDefPath)));
|
|
10045
|
+
return 1;
|
|
10046
|
+
}
|
|
10047
|
+
const kindRows = fileHint !== void 0 ? querySymbols({ name: rootName, filePath: fileHint, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
|
|
10048
|
+
const kindVerdict = refBlindKindVerdict(kindRows);
|
|
10049
|
+
if (kindVerdict.allBlind) {
|
|
10050
|
+
emitErr2(refBlindKindNotice(rootName, kindVerdict.blindKinds));
|
|
10051
|
+
return 1;
|
|
10052
|
+
}
|
|
9888
10053
|
emitErr2(`No callers found for '${opts.symbol}'`);
|
|
10054
|
+
if (kindVerdict.blindCount > 0) emitErr2(refBlindKindPartialNote(rootName, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
|
|
9889
10055
|
return 1;
|
|
9890
10056
|
}
|
|
9891
10057
|
if (opts.json === true) {
|
|
@@ -9918,7 +10084,10 @@ function hasAncestorDispatchRef(methodName, scopeName, classFile, rootDir) {
|
|
|
9918
10084
|
const baseSyms = querySymbols({ name: baseName, kind: "class", limit: 1, rootDir });
|
|
9919
10085
|
const baseSym = baseSyms[0];
|
|
9920
10086
|
if (baseSym === void 0) return false;
|
|
9921
|
-
|
|
10087
|
+
let baseRefs = queryRefs({ name: methodName, filePath: baseSym.filePath, limit: DEFAULT_REF_QUERY_LIMIT, rootDir });
|
|
10088
|
+
if (baseRefs.length >= DEFAULT_REF_QUERY_LIMIT && !baseRefs.some((ref) => ref.line >= baseSym.lineStart && ref.line <= baseSym.lineEnd)) {
|
|
10089
|
+
baseRefs = queryRefs({ name: methodName, filePath: baseSym.filePath, limit: UNBOUNDED_REF_LIMIT, rootDir });
|
|
10090
|
+
}
|
|
9922
10091
|
if (baseRefs.some((ref) => ref.line >= baseSym.lineStart && ref.line <= baseSym.lineEnd)) return true;
|
|
9923
10092
|
currentName = baseName;
|
|
9924
10093
|
currentFile = baseSym.filePath;
|
|
@@ -9992,11 +10161,26 @@ function runDead(opts) {
|
|
|
9992
10161
|
}
|
|
9993
10162
|
return 1;
|
|
9994
10163
|
}
|
|
9995
|
-
const
|
|
10164
|
+
const blindKinds = kinds.filter((k) => REF_BLIND_KINDS.includes(k));
|
|
10165
|
+
const assessableKinds = kinds.filter((k) => !REF_BLIND_KINDS.includes(k));
|
|
10166
|
+
if (blindKinds.length > 0 && assessableKinds.length === 0) {
|
|
10167
|
+
const blindLabel = blindKinds.length === 1 ? "kind" : "kinds";
|
|
10168
|
+
emitErr2(`Cannot assess deadness for ${blindLabel}: ${blindKinds.map((k) => `'${k}'`).join(", ")} -- ${REF_BLIND_KIND_REASON}.`);
|
|
10169
|
+
emitErr2(`Every symbol of ${blindKinds.length === 1 ? "this kind" : "these kinds"} would be reported dead, so no result is emitted rather than a wrong one. To hunt unused type declarations, list them with 'token-goat types --json' and search the source for each name directly.`);
|
|
10170
|
+
return 1;
|
|
10171
|
+
}
|
|
10172
|
+
const blindKindNote = blindKinds.length > 0 ? `Note: ${blindKinds.map((k) => `'${k}'`).join(", ")} excluded -- ${REF_BLIND_KIND_REASON}.` : void 0;
|
|
10173
|
+
if (blindKindNote !== void 0 && opts.json !== true) emitErr2(blindKindNote);
|
|
10174
|
+
const syms = assessableKinds.flatMap((k) => querySymbols({ kind: k, limit: UNBOUNDED_REF_LIMIT, rootDir }));
|
|
9996
10175
|
const getSyms = buildFileSymCache();
|
|
9997
10176
|
const results = [];
|
|
9998
10177
|
let suppressed = 0;
|
|
10178
|
+
let refBlindByLanguage = 0;
|
|
9999
10179
|
for (const sym of syms) {
|
|
10180
|
+
if (!isRefIndexedFile(sym.filePath)) {
|
|
10181
|
+
refBlindByLanguage += 1;
|
|
10182
|
+
continue;
|
|
10183
|
+
}
|
|
10000
10184
|
if (opts.includePrivate !== true && sym.name.startsWith("_")) continue;
|
|
10001
10185
|
const refs = queryRefs({ name: sym.name, limit: DEFAULT_REF_QUERY_LIMIT, rootDir });
|
|
10002
10186
|
let scoped = filterRefsForSymbol(refs, sym.name, sym.filePath, getSyms);
|
|
@@ -10014,6 +10198,9 @@ function runDead(opts) {
|
|
|
10014
10198
|
}
|
|
10015
10199
|
results.push({ name: sym.name, kind: sym.kind, file: sym.filePath, line: sym.lineStart });
|
|
10016
10200
|
}
|
|
10201
|
+
if (refBlindByLanguage > 0 && opts.json !== true) {
|
|
10202
|
+
emitErr2(`Note: ${countNoun(refBlindByLanguage, "symbol")} skipped -- defined in a language whose call sites token-goat does not index, so deadness cannot be determined for them.`);
|
|
10203
|
+
}
|
|
10017
10204
|
const preGrepCount = results.length;
|
|
10018
10205
|
const matchesGrep = opts.grep !== void 0 ? compileGrepMatcher(opts.grep) : void 0;
|
|
10019
10206
|
const grepped = matchesGrep !== void 0 ? results.filter((r) => matchesGrep(r.name)) : results;
|
|
@@ -10025,7 +10212,7 @@ function runDead(opts) {
|
|
|
10025
10212
|
}));
|
|
10026
10213
|
const topTruncated = sliced.length < grepped.length;
|
|
10027
10214
|
const hiddenByGrep = preGrepCount - grepped.length;
|
|
10028
|
-
emit2(JSON.stringify({ items: capped.items, truncated: capped.truncated || topTruncated, totalCount: grepped.length, ...hiddenByGrep > 0 ? { hiddenByGrep } : {}, ...opts.excludeTests === true && suppressed > 0 ? { hiddenByExcludeTests: suppressed } : {} }, null, 2));
|
|
10215
|
+
emit2(JSON.stringify({ items: capped.items, truncated: capped.truncated || topTruncated, totalCount: grepped.length, ...hiddenByGrep > 0 ? { hiddenByGrep } : {}, ...opts.excludeTests === true && suppressed > 0 ? { hiddenByExcludeTests: suppressed } : {}, ...blindKinds.length > 0 ? { excludedKinds: blindKinds, excludedKindsReason: REF_BLIND_KIND_REASON } : {}, ...refBlindByLanguage > 0 ? { unassessableByLanguage: refBlindByLanguage } : {} }, null, 2));
|
|
10029
10216
|
return 0;
|
|
10030
10217
|
}
|
|
10031
10218
|
if (sliced.length === 0) {
|
|
@@ -10220,6 +10407,15 @@ var TYPE_KINDS = [
|
|
|
10220
10407
|
// Kotlin/Scala object.
|
|
10221
10408
|
"graphql_extend"
|
|
10222
10409
|
];
|
|
10410
|
+
var REF_BLIND_KINDS = [.../* @__PURE__ */ new Set([...TYPE_KINDS, "impl"])];
|
|
10411
|
+
function refBlindKindVerdict(rows) {
|
|
10412
|
+
const blind = rows.filter((r) => REF_BLIND_KINDS.includes(r.kind));
|
|
10413
|
+
return {
|
|
10414
|
+
blindKinds: [...new Set(blind.map((r) => r.kind))],
|
|
10415
|
+
blindCount: blind.length,
|
|
10416
|
+
allBlind: rows.length > 0 && blind.length === rows.length
|
|
10417
|
+
};
|
|
10418
|
+
}
|
|
10223
10419
|
var CORE_SYMBOL_KINDS = [
|
|
10224
10420
|
.../* @__PURE__ */ new Set([...GENERIC_SYMBOL_KINDS, ...TYPE_KINDS, ...OTHER_ADAPTER_SYMBOL_KINDS])
|
|
10225
10421
|
];
|
|
@@ -10728,8 +10924,9 @@ function runAsk(opts) {
|
|
|
10728
10924
|
} catch {
|
|
10729
10925
|
}
|
|
10730
10926
|
if (!backendPath) return degrade(`${BACKEND_ENV}=${backendLabel} is set, but '${backendLabel}' was not found on PATH`);
|
|
10731
|
-
const
|
|
10927
|
+
const rawContext = hits.map((h, i) => `[${i + 1}] ${h.filePath}
|
|
10732
10928
|
${h.body ?? ""}`).join("\n\n");
|
|
10929
|
+
const context = fenceUntrustedFileContent(redactSecrets(rawContext).text);
|
|
10733
10930
|
const prompt = `Answer the QUESTION using only the CODE SNIPPETS below.
|
|
10734
10931
|
QUESTION: ${opts.question}
|
|
10735
10932
|
|