dsh-gitnexus-plus 0.0.0-stage → 0.1.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/LICENSE +38 -0
- package/README.md +483 -2
- package/cordis.patch.yml +18 -0
- package/lib/bin/gitnexus-coverage.d.ts +14 -0
- package/lib/bin/gitnexus-coverage.d.ts.map +1 -0
- package/lib/bin/gitnexus-coverage.js +171 -0
- package/lib/bin/gitnexus-coverage.js.map +1 -0
- package/lib/client.js +1642 -0
- package/lib/gitnexus/analyze.d.ts +148 -0
- package/lib/gitnexus/analyze.d.ts.map +1 -0
- package/lib/gitnexus/analyze.js +283 -0
- package/lib/gitnexus/analyze.js.map +1 -0
- package/lib/gitnexus/commands.d.ts +96 -0
- package/lib/gitnexus/commands.d.ts.map +1 -0
- package/lib/gitnexus/commands.js +132 -0
- package/lib/gitnexus/commands.js.map +1 -0
- package/lib/gitnexus/coverage.d.ts +340 -0
- package/lib/gitnexus/coverage.d.ts.map +1 -0
- package/lib/gitnexus/coverage.js +552 -0
- package/lib/gitnexus/coverage.js.map +1 -0
- package/lib/gitnexus/format.d.ts +16 -0
- package/lib/gitnexus/format.d.ts.map +1 -0
- package/lib/gitnexus/format.js +178 -0
- package/lib/gitnexus/format.js.map +1 -0
- package/lib/gitnexus/git-activity.d.ts +136 -0
- package/lib/gitnexus/git-activity.d.ts.map +1 -0
- package/lib/gitnexus/git-activity.js +345 -0
- package/lib/gitnexus/git-activity.js.map +1 -0
- package/lib/gitnexus/git.d.ts +70 -0
- package/lib/gitnexus/git.d.ts.map +1 -0
- package/lib/gitnexus/git.js +121 -0
- package/lib/gitnexus/git.js.map +1 -0
- package/lib/gitnexus/index-meta.d.ts +150 -0
- package/lib/gitnexus/index-meta.d.ts.map +1 -0
- package/lib/gitnexus/index-meta.js +156 -0
- package/lib/gitnexus/index-meta.js.map +1 -0
- package/lib/gitnexus/install.d.ts +97 -0
- package/lib/gitnexus/install.d.ts.map +1 -0
- package/lib/gitnexus/install.js +228 -0
- package/lib/gitnexus/install.js.map +1 -0
- package/lib/gitnexus/languages.d.ts +73 -0
- package/lib/gitnexus/languages.d.ts.map +1 -0
- package/lib/gitnexus/languages.js +217 -0
- package/lib/gitnexus/languages.js.map +1 -0
- package/lib/gitnexus/root.d.ts +68 -0
- package/lib/gitnexus/root.d.ts.map +1 -0
- package/lib/gitnexus/root.js +162 -0
- package/lib/gitnexus/root.js.map +1 -0
- package/lib/gitnexus/scan.d.ts +67 -0
- package/lib/gitnexus/scan.d.ts.map +1 -0
- package/lib/gitnexus/scan.js +247 -0
- package/lib/gitnexus/scan.js.map +1 -0
- package/lib/gitnexus/toolchain.d.ts +136 -0
- package/lib/gitnexus/toolchain.d.ts.map +1 -0
- package/lib/gitnexus/toolchain.js +251 -0
- package/lib/gitnexus/toolchain.js.map +1 -0
- package/lib/index.d.ts +79 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +211 -0
- package/lib/index.js.map +1 -0
- package/lib/routes/analyze.d.ts +35 -0
- package/lib/routes/analyze.d.ts.map +1 -0
- package/lib/routes/analyze.js +71 -0
- package/lib/routes/analyze.js.map +1 -0
- package/lib/routes/coverage.d.ts +44 -0
- package/lib/routes/coverage.d.ts.map +1 -0
- package/lib/routes/coverage.js +68 -0
- package/lib/routes/coverage.js.map +1 -0
- package/lib/routes/guard.d.ts +92 -0
- package/lib/routes/guard.d.ts.map +1 -0
- package/lib/routes/guard.js +187 -0
- package/lib/routes/guard.js.map +1 -0
- package/lib/routes/install.d.ts +27 -0
- package/lib/routes/install.d.ts.map +1 -0
- package/lib/routes/install.js +46 -0
- package/lib/routes/install.js.map +1 -0
- package/package.json +87 -4
- package/scripts/link-runtime.mjs +146 -0
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index-coverage and large-file monitoring for one repository.
|
|
3
|
+
*
|
|
4
|
+
* The question this answers is not "how big is this repo" but "what did
|
|
5
|
+
* `analyze` silently leave out, and does that change how much I should trust the
|
|
6
|
+
* index?". GitNexus tells the operator, on stderr, once:
|
|
7
|
+
*
|
|
8
|
+
* Skipped 3 large files (>512KB, likely generated/vendored)
|
|
9
|
+
* - dist/app.min.js
|
|
10
|
+
* ...and 2 more (set GITNEXUS_VERBOSE=1 to list them all)
|
|
11
|
+
*
|
|
12
|
+
* That is the whole surface. It is not returned, not persisted, not queryable,
|
|
13
|
+
* and gone once the terminal scrolls. `scanRepository` turns it into data; this
|
|
14
|
+
* module turns it into a judgement — including the case that matters most, where
|
|
15
|
+
* one minified bundle dominates a language's byte share and makes the index look
|
|
16
|
+
* far more complete than it is.
|
|
17
|
+
*/
|
|
18
|
+
import fs from 'node:fs/promises';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { readIndexMeta, findRegistryEntry, normalizePathKey } from './index-meta.js';
|
|
21
|
+
import { scanRepository } from './scan.js';
|
|
22
|
+
import { classifyFile, aggregateLanguages, loadLanguageDetector, } from './languages.js';
|
|
23
|
+
import { readGitState, classifyStaleness } from './git.js';
|
|
24
|
+
import { readGitActivity } from './git-activity.js';
|
|
25
|
+
import { readToolchainStatus } from './toolchain.js';
|
|
26
|
+
/** Bytes sampled from a file's head when judging its shape. */
|
|
27
|
+
const MINIFIED_SAMPLE_BYTES = 64 * 1024;
|
|
28
|
+
/** Average characters per line above which a file is treated as minified. */
|
|
29
|
+
const MINIFIED_AVG_LINE_THRESHOLD = 500;
|
|
30
|
+
/** Control-byte share above which a sample is treated as binary. */
|
|
31
|
+
const BINARY_CONTROL_RATIO = 0.3;
|
|
32
|
+
/**
|
|
33
|
+
* Narrow the manifest's `capabilities` block.
|
|
34
|
+
*
|
|
35
|
+
* The manifest is JSON written by another tool, so at the boundary it is
|
|
36
|
+
* `Record<string, unknown>` and has to be **checked** rather than asserted. A cast
|
|
37
|
+
* here would move the failure from "a missing field renders as undefined" to "a
|
|
38
|
+
* malformed manifest crashes the panel", which is the wrong trade for data this
|
|
39
|
+
* plugin does not control.
|
|
40
|
+
*
|
|
41
|
+
* WHAT THE NARROWING IS AND IS NOT FOR
|
|
42
|
+
* ------------------------------------
|
|
43
|
+
* Its job is to make the JSON safe to *read*, not to decide which fields exist. A
|
|
44
|
+
* first version listed the two fields it expected and rebuilt each entry from just
|
|
45
|
+
* those, which silently dropped `provider` — a field the panel renders, and the
|
|
46
|
+
* reason it showed `unknown` for two surfaces that were available. So the original
|
|
47
|
+
* entry is spread first and only the validated fields are overwritten: something
|
|
48
|
+
* this plugin has not heard of yet survives, instead of being deleted by a checklist.
|
|
49
|
+
*/
|
|
50
|
+
export function readCapabilities(raw) {
|
|
51
|
+
const out = {};
|
|
52
|
+
if (raw === null || raw === undefined)
|
|
53
|
+
return out;
|
|
54
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
55
|
+
if (value === null || typeof value !== 'object')
|
|
56
|
+
continue;
|
|
57
|
+
const entry = value;
|
|
58
|
+
out[key] = {
|
|
59
|
+
...entry,
|
|
60
|
+
status: typeof entry.status === 'string' ? entry.status : undefined,
|
|
61
|
+
skipReason: typeof entry.skipReason === 'string' ? entry.skipReason : undefined,
|
|
62
|
+
provider: typeof entry.provider === 'string' ? entry.provider : undefined,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Narrow the manifest's `unresolvedReceiverMembers` block.
|
|
69
|
+
*
|
|
70
|
+
* Returns null rather than a zero-filled object when the field is absent: an index
|
|
71
|
+
* written before this was recorded must render as "not recorded", not as "no untyped
|
|
72
|
+
* receivers", because those are opposite claims about how much to trust the graph.
|
|
73
|
+
*/
|
|
74
|
+
export function readGraphQuality(raw) {
|
|
75
|
+
if (raw === null || raw === undefined || typeof raw !== 'object')
|
|
76
|
+
return null;
|
|
77
|
+
const value = raw;
|
|
78
|
+
const counts = {};
|
|
79
|
+
if (value.counts !== null && typeof value.counts === 'object') {
|
|
80
|
+
for (const [key, count] of Object.entries(value.counts)) {
|
|
81
|
+
if (typeof count === 'number')
|
|
82
|
+
counts[key] = count;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const totalSites = typeof value.totalSites === 'number' ? value.totalSites : 0;
|
|
86
|
+
return { totalSites, counts };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Judge what kind of file this is from the head of its bytes.
|
|
90
|
+
*
|
|
91
|
+
* Reads only the head: a bundle megabytes wide on one line is identifiable from
|
|
92
|
+
* any prefix, and reading it whole to decide would cost exactly what the size cap
|
|
93
|
+
* exists to avoid.
|
|
94
|
+
*
|
|
95
|
+
* BINARY IS CHECKED FIRST, AND THAT ORDER IS THE WHOLE POINT
|
|
96
|
+
* ---------------------------------------------------------
|
|
97
|
+
* A first revision tested only "no newlines ⇒ one enormous line", which flagged
|
|
98
|
+
* every binary asset as minified. Measured on a real repository: a 380 MB `.glb`
|
|
99
|
+
* model and a 30 MB `.glb` reported "single-line ≈ 399 230 584 chars" — absurd on
|
|
100
|
+
* its face, and worse than absurd in effect, because it told the reader that 97 %
|
|
101
|
+
* of the repository's skipped bytes were compressed *source*. They were 3D assets
|
|
102
|
+
* that could never have held a symbol.
|
|
103
|
+
*
|
|
104
|
+
* A binary file has few newlines for a reason that has nothing to do with
|
|
105
|
+
* minification, so no line-length statistic over it means anything. The test is
|
|
106
|
+
* git's own: a NUL byte in the head means binary. A control-byte ratio backs it up
|
|
107
|
+
* for machine formats that happen to avoid NUL.
|
|
108
|
+
*
|
|
109
|
+
* The extrapolation is deliberately crude — newline density in the head is assumed
|
|
110
|
+
* to hold for the rest — and only ever produces a *warning*, never an exclusion.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} absolutePath
|
|
113
|
+
* @param {number} size
|
|
114
|
+
* @returns {Promise<FileShape>}
|
|
115
|
+
*/
|
|
116
|
+
export async function judgeMinified(absolutePath, size) {
|
|
117
|
+
const want = Math.max(1, Math.min(size, MINIFIED_SAMPLE_BYTES));
|
|
118
|
+
let handle;
|
|
119
|
+
try {
|
|
120
|
+
handle = await fs.open(absolutePath, 'r');
|
|
121
|
+
const buffer = Buffer.allocUnsafe(want);
|
|
122
|
+
const { bytesRead } = await handle.read(buffer, 0, want, 0);
|
|
123
|
+
const sample = buffer.subarray(0, bytesRead);
|
|
124
|
+
const sampled = sample.length;
|
|
125
|
+
if (sampled === 0) {
|
|
126
|
+
return { binary: false, suspect: false, avgLineLength: 0, estimatedLines: 0, sampledBytes: 0 };
|
|
127
|
+
}
|
|
128
|
+
let newlines = 0;
|
|
129
|
+
let control = 0;
|
|
130
|
+
for (let i = 0; i < sampled; i += 1) {
|
|
131
|
+
const byte = sample[i];
|
|
132
|
+
if (byte === 0x0a)
|
|
133
|
+
newlines += 1;
|
|
134
|
+
// NUL is decisive on its own (git's rule); other C0 controls accumulate as
|
|
135
|
+
// corroboration. Tab, LF and CR are ordinary text bytes and excluded.
|
|
136
|
+
if (byte === 0x00) {
|
|
137
|
+
return { binary: true, suspect: false, avgLineLength: 0, estimatedLines: null, sampledBytes: sampled };
|
|
138
|
+
}
|
|
139
|
+
if (byte < 0x20 && byte !== 0x09 && byte !== 0x0a && byte !== 0x0d)
|
|
140
|
+
control += 1;
|
|
141
|
+
}
|
|
142
|
+
if (control / sampled > BINARY_CONTROL_RATIO) {
|
|
143
|
+
return { binary: true, suspect: false, avgLineLength: 0, estimatedLines: null, sampledBytes: sampled };
|
|
144
|
+
}
|
|
145
|
+
// Whole file sampled: the line count is exact.
|
|
146
|
+
if (size <= sampled) {
|
|
147
|
+
const lines = newlines + 1;
|
|
148
|
+
const avg = size / lines;
|
|
149
|
+
return {
|
|
150
|
+
binary: false,
|
|
151
|
+
suspect: avg > MINIFIED_AVG_LINE_THRESHOLD,
|
|
152
|
+
avgLineLength: avg,
|
|
153
|
+
estimatedLines: lines,
|
|
154
|
+
sampledBytes: sampled,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// Extrapolated: newlines/byte in the head is assumed to hold throughout, so
|
|
158
|
+
// average line length is simply sample length over newlines in the sample.
|
|
159
|
+
if (newlines === 0) {
|
|
160
|
+
return { binary: false, suspect: true, avgLineLength: size, estimatedLines: 1, sampledBytes: sampled };
|
|
161
|
+
}
|
|
162
|
+
const avg = sampled / newlines;
|
|
163
|
+
return {
|
|
164
|
+
binary: false,
|
|
165
|
+
suspect: avg > MINIFIED_AVG_LINE_THRESHOLD,
|
|
166
|
+
avgLineLength: avg,
|
|
167
|
+
estimatedLines: Math.round(size / avg),
|
|
168
|
+
sampledBytes: sampled,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return { binary: false, suspect: false, avgLineLength: 0, estimatedLines: null, sampledBytes: 0 };
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
await handle?.close().catch(() => { });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Path shapes that conventionally hold build output. Applied only to files that
|
|
180
|
+
* already exceeded the size cap, where the combination is high-signal.
|
|
181
|
+
*
|
|
182
|
+
* This exists because the minified heuristic alone is not enough: measured on
|
|
183
|
+
* material-ui, the three skipped files are generated but **multi-line** (75 263 /
|
|
184
|
+
* 10 757 / 32 317 lines, 31/70/44 chars per line) so `judgeMinified` correctly
|
|
185
|
+
* declines to call them minified — yet they are still compiled output sitting in
|
|
186
|
+
* the byte totals. Verified by counting newlines over the whole file after a
|
|
187
|
+
* PowerShell line count wrongly reported "1 line" for a 2.3 MB file.
|
|
188
|
+
*/
|
|
189
|
+
const GENERATED_PATH_PATTERNS = Object.freeze([
|
|
190
|
+
/(^|\/)(dist|build|out|vendor|generated|__generated__|coverage)\//i,
|
|
191
|
+
/(^|\/)lib\//i,
|
|
192
|
+
/\.min\./i,
|
|
193
|
+
/\.generated\./i,
|
|
194
|
+
/\.g\.(cs|ts|js)$/i,
|
|
195
|
+
/\.bundle\.(js|mjs|cjs)$/i,
|
|
196
|
+
]);
|
|
197
|
+
/**
|
|
198
|
+
* @param {string} filePath repo-relative
|
|
199
|
+
* @returns {boolean} whether the path conventionally denotes build output
|
|
200
|
+
*/
|
|
201
|
+
export function looksGenerated(filePath) {
|
|
202
|
+
return GENERATED_PATH_PATTERNS.some((re) => re.test(filePath));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* A file holding at least this share of its language's bytes is called out when it
|
|
206
|
+
* also looks machine-produced. The share matters because the claim being made is
|
|
207
|
+
* "this distorts the percentage", not merely "this is generated".
|
|
208
|
+
*/
|
|
209
|
+
const MINIFIED_DOMINANCE_SHARE = 0.25;
|
|
210
|
+
/** @param {number} bytes */
|
|
211
|
+
export function formatBytes(bytes) {
|
|
212
|
+
if (bytes < 1024)
|
|
213
|
+
return `${bytes} B`;
|
|
214
|
+
if (bytes < 1024 * 1024)
|
|
215
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
216
|
+
if (bytes < 1024 * 1024 * 1024)
|
|
217
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
218
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Build the full coverage report for a repository.
|
|
222
|
+
*
|
|
223
|
+
* @param repoPath absolute repository root
|
|
224
|
+
*/
|
|
225
|
+
export async function analyzeCoverage(repoPath, options = {}) {
|
|
226
|
+
const env = options.env ?? process.env;
|
|
227
|
+
const absRepo = path.resolve(repoPath);
|
|
228
|
+
const [meta, registryEntry, detector] = await Promise.all([
|
|
229
|
+
readIndexMeta(absRepo),
|
|
230
|
+
findRegistryEntry(absRepo, { env }),
|
|
231
|
+
loadLanguageDetector({ env }),
|
|
232
|
+
]);
|
|
233
|
+
// Read after the manifest, because classifying staleness needs the indexed commit.
|
|
234
|
+
const git = await readGitState(absRepo, meta?.lastCommit ?? null);
|
|
235
|
+
const staleness = classifyStaleness({ lastCommit: meta?.lastCommit ?? null, git });
|
|
236
|
+
// When the index recorded the cap it was built under, judge it by that cap —
|
|
237
|
+
// not by today's default, which would report files as "skipped" that the index
|
|
238
|
+
// in fact covers.
|
|
239
|
+
const scan = await scanRepository(absRepo, {
|
|
240
|
+
env,
|
|
241
|
+
capBytes: meta?.coverageMaxFileSizeBytes ?? undefined,
|
|
242
|
+
});
|
|
243
|
+
const largeFiles = [];
|
|
244
|
+
const minifiedBudget = options.minifiedSampleLimit ?? 40;
|
|
245
|
+
let minifiedProbes = 0;
|
|
246
|
+
for (const file of scan.large) {
|
|
247
|
+
const lang = classifyFile(file.path, detector);
|
|
248
|
+
/** @type {FileShape | null} */
|
|
249
|
+
let minified = null;
|
|
250
|
+
if (minifiedProbes < minifiedBudget) {
|
|
251
|
+
minifiedProbes += 1;
|
|
252
|
+
minified = await judgeMinified(path.join(absRepo, file.path), file.size);
|
|
253
|
+
}
|
|
254
|
+
largeFiles.push({
|
|
255
|
+
path: file.path,
|
|
256
|
+
size: file.size,
|
|
257
|
+
sizeText: formatBytes(file.size),
|
|
258
|
+
language: lang,
|
|
259
|
+
minified,
|
|
260
|
+
generatedHint: looksGenerated(file.path),
|
|
261
|
+
// Filled in below, once every file is collected and the denominators (bytes
|
|
262
|
+
// per language, total scanned bytes) are known. Declared here rather than
|
|
263
|
+
// omitted so the field cannot silently stay `undefined` — which is exactly
|
|
264
|
+
// what happened while these were JSDoc types: `shareOfScanned` was part of the
|
|
265
|
+
// documented contract and no code path ever assigned it.
|
|
266
|
+
shareOfScanned: 0,
|
|
267
|
+
shareOfLanguage: 0,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
// Share of a language's bytes held by each large file, computed over every
|
|
271
|
+
// scanned file of that language so the denominator is the honest one.
|
|
272
|
+
const allFiles = [...scan.selected, ...scan.large];
|
|
273
|
+
const langsAll = aggregateLanguages(allFiles, detector);
|
|
274
|
+
const bytesByLanguage = new Map(langsAll.rows.map((r) => [r.key, r.bytes]));
|
|
275
|
+
const largeBytes = scan.large.reduce((sum, f) => sum + f.size, 0);
|
|
276
|
+
const scannedBytes = allFiles.reduce((sum, f) => sum + f.size, 0);
|
|
277
|
+
for (const entry of largeFiles) {
|
|
278
|
+
const total = bytesByLanguage.get(entry.language.key) ?? entry.size;
|
|
279
|
+
entry.shareOfLanguage = total > 0 ? entry.size / total : 0;
|
|
280
|
+
entry.shareOfScanned = scannedBytes > 0 ? entry.size / scannedBytes : 0;
|
|
281
|
+
}
|
|
282
|
+
// Coverage: what a fresh scan would select vs what the index actually holds.
|
|
283
|
+
const indexed = new Set(Object.keys(meta?.fileHashes ?? {}).map((p) => normalizePathKey(p)));
|
|
284
|
+
const selected = new Set(scan.selected.map((f) => normalizePathKey(f.path)));
|
|
285
|
+
const uncovered = scan.selected.filter((f) => !indexed.has(normalizePathKey(f.path)));
|
|
286
|
+
const staleInIndex = meta
|
|
287
|
+
? Object.keys(meta.fileHashes).filter((p) => !selected.has(normalizePathKey(p)))
|
|
288
|
+
: [];
|
|
289
|
+
/** @type {Array<{level:'warn'|'info',code:string,message:string,evidence:object}>} */
|
|
290
|
+
const warnings = [];
|
|
291
|
+
const generatedLarge = largeFiles.filter((f) => f.generatedHint);
|
|
292
|
+
const generatedBytes = generatedLarge.reduce((sum, f) => sum + f.size, 0);
|
|
293
|
+
const binaryLarge = largeFiles.filter((f) => f.minified?.binary === true);
|
|
294
|
+
const binaryBytes = binaryLarge.reduce((sum, f) => sum + f.size, 0);
|
|
295
|
+
const textLargeBytes = largeBytes - binaryBytes;
|
|
296
|
+
if (scan.large.length > 0) {
|
|
297
|
+
// The binary split is what makes the headline honest. Without it, a repository
|
|
298
|
+
// of 3D assets reads as "97.9 % of scanned bytes were skipped" and sounds like
|
|
299
|
+
// lost source; with it, the reader learns that 413 of those 417 MB are models
|
|
300
|
+
// that could never have contributed a symbol, and the figure to act on is the
|
|
301
|
+
// much smaller text remainder.
|
|
302
|
+
const notes = [];
|
|
303
|
+
if (binaryLarge.length > 0) {
|
|
304
|
+
notes.push(`其中 ${binaryLarge.length} 个为二进制资源(${formatBytes(binaryBytes)}),本就不含可索引符号`);
|
|
305
|
+
}
|
|
306
|
+
if (generatedLarge.length > 0) {
|
|
307
|
+
notes.push(`${generatedLarge.length} 个疑似构建产物(${formatBytes(generatedBytes)})`);
|
|
308
|
+
}
|
|
309
|
+
const note = notes.length > 0 ? `,${notes.join(',')}` : '';
|
|
310
|
+
const actionable = binaryLarge.length > 0 ? `,仍可能含源码的为 ${formatBytes(textLargeBytes)}` : '';
|
|
311
|
+
warnings.push({
|
|
312
|
+
level: 'warn',
|
|
313
|
+
code: 'large-files-skipped',
|
|
314
|
+
message: `${scan.large.length} 个文件超过 ${formatBytes(scan.capBytes)} 上限被跳过,` +
|
|
315
|
+
`合计 ${formatBytes(largeBytes)}(占已扫描体积 ${scannedBytes > 0 ? ((largeBytes / scannedBytes) * 100).toFixed(1) : '0'}%)` +
|
|
316
|
+
`——这些文件里的符号完全不在索引中${note}${actionable}`,
|
|
317
|
+
evidence: {
|
|
318
|
+
count: scan.large.length,
|
|
319
|
+
bytes: largeBytes,
|
|
320
|
+
capBytes: scan.capBytes,
|
|
321
|
+
capSource: scan.capSource,
|
|
322
|
+
generatedCount: generatedLarge.length,
|
|
323
|
+
generatedBytes,
|
|
324
|
+
binaryCount: binaryLarge.length,
|
|
325
|
+
binaryBytes,
|
|
326
|
+
textBytes: textLargeBytes,
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
for (const entry of largeFiles) {
|
|
331
|
+
// Binary short-circuits both claims below. A model file is neither minified nor
|
|
332
|
+
// build output, and calling it either is how a first revision ended up telling
|
|
333
|
+
// this repository's owner that 97 % of its skipped bytes were compressed source.
|
|
334
|
+
if (entry.minified?.binary === true)
|
|
335
|
+
continue;
|
|
336
|
+
if (entry.shareOfLanguage < MINIFIED_DOMINANCE_SHARE)
|
|
337
|
+
continue;
|
|
338
|
+
if (entry.minified?.suspect) {
|
|
339
|
+
warnings.push({
|
|
340
|
+
level: 'warn',
|
|
341
|
+
code: 'minified-dominates-language',
|
|
342
|
+
message: `${entry.path}(${entry.sizeText},平均行长 ${Math.round(entry.minified.avgLineLength)} 字符)` +
|
|
343
|
+
`占 ${entry.language.label} 的 ${(entry.shareOfLanguage * 100).toFixed(0)}%,` +
|
|
344
|
+
`疑似压缩产物而非源码——该语言占比被显著放大`,
|
|
345
|
+
evidence: {
|
|
346
|
+
path: entry.path,
|
|
347
|
+
size: entry.size,
|
|
348
|
+
avgLineLength: entry.minified.avgLineLength,
|
|
349
|
+
shareOfLanguage: entry.shareOfLanguage,
|
|
350
|
+
language: entry.language.key,
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
else if (entry.generatedHint) {
|
|
355
|
+
warnings.push({
|
|
356
|
+
level: 'warn',
|
|
357
|
+
code: 'generated-dominates-language',
|
|
358
|
+
message: `${entry.path}(${entry.sizeText})占 ${entry.language.label} 的 ` +
|
|
359
|
+
`${(entry.shareOfLanguage * 100).toFixed(0)}%,路径形似构建产物——` +
|
|
360
|
+
`该语言占比可能包含编译输出`,
|
|
361
|
+
evidence: {
|
|
362
|
+
path: entry.path,
|
|
363
|
+
size: entry.size,
|
|
364
|
+
shareOfLanguage: entry.shareOfLanguage,
|
|
365
|
+
language: entry.language.key,
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
const capsNote = meta?.coverageMaxFileSizeBytes ?? null;
|
|
371
|
+
if (capsNote === null && meta !== null) {
|
|
372
|
+
warnings.push({
|
|
373
|
+
level: 'info',
|
|
374
|
+
code: 'cap-not-recorded',
|
|
375
|
+
message: '该索引未记录构建时的大小上限(旧版本写入),本次按当前生效上限判断,可能与建索引时不同',
|
|
376
|
+
evidence: { effectiveCapBytes: scan.capBytes, capSource: scan.capSource },
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
if (scan.capSource === 'env') {
|
|
380
|
+
warnings.push({
|
|
381
|
+
level: 'info',
|
|
382
|
+
code: 'cap-from-env',
|
|
383
|
+
message: `大小上限来自 GITNEXUS_MAX_FILE_SIZE=${env.GITNEXUS_MAX_FILE_SIZE}(${formatBytes(scan.capBytes)}),非默认值`,
|
|
384
|
+
evidence: { capBytes: scan.capBytes, maxCapBytes: scan.maxCapBytes },
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
if (uncovered.length > 0) {
|
|
388
|
+
warnings.push({
|
|
389
|
+
level: 'info',
|
|
390
|
+
code: 'uncovered-files',
|
|
391
|
+
message: `${uncovered.length} 个文件会被扫描选中但不在索引中——索引可能已过期,或建索引时的排除规则不同`,
|
|
392
|
+
evidence: { count: uncovered.length, sample: uncovered.slice(0, 10).map((f) => f.path) },
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
if (staleInIndex.length > 0) {
|
|
396
|
+
warnings.push({
|
|
397
|
+
level: 'info',
|
|
398
|
+
code: 'index-holds-retired-paths',
|
|
399
|
+
message: `${staleInIndex.length} 个索引中的文件在本次扫描中不存在(已删除或已被排除)`,
|
|
400
|
+
evidence: { count: staleInIndex.length, sample: staleInIndex.slice(0, 10) },
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
const languagesReport = options.includeLanguages === false
|
|
404
|
+
? null
|
|
405
|
+
: {
|
|
406
|
+
...aggregateLanguages(scan.selected, detector),
|
|
407
|
+
largeExcluded: aggregateLanguages(scan.large, detector).rows,
|
|
408
|
+
};
|
|
409
|
+
// Git activity, crossed with both sets so each touched file gets a three-way
|
|
410
|
+
// verdict rather than a bare "in the index / not in the index". Both sets are
|
|
411
|
+
// already computed above, so this costs one git call and no extra filesystem work.
|
|
412
|
+
const activity = options.includeActivity === false
|
|
413
|
+
? null
|
|
414
|
+
: await readGitActivity(absRepo, {
|
|
415
|
+
sinceDays: options.activitySinceDays ?? undefined,
|
|
416
|
+
indexedPaths: Object.keys(meta?.fileHashes ?? {}),
|
|
417
|
+
scannablePaths: scan.selected.map((f) => f.path),
|
|
418
|
+
});
|
|
419
|
+
if (activity !== null && activity.totals.verdicts.missing > 0) {
|
|
420
|
+
warnings.push({
|
|
421
|
+
level: 'warn',
|
|
422
|
+
code: 'active-files-missing-from-index',
|
|
423
|
+
message: `近 ${activity.window.sinceDays} 天内被改动过的文件里,有 ${activity.totals.verdicts.missing} 个` +
|
|
424
|
+
`本应被索引却不在索引中——索引落后于当前工作区`,
|
|
425
|
+
evidence: {
|
|
426
|
+
missing: activity.totals.verdicts.missing,
|
|
427
|
+
indexed: activity.totals.verdicts.indexed,
|
|
428
|
+
excluded: activity.totals.verdicts.excluded,
|
|
429
|
+
sample: activity.byChanges
|
|
430
|
+
.filter((f) => f.verdict === 'missing')
|
|
431
|
+
.slice(0, 10)
|
|
432
|
+
.map((f) => f.path),
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
if (activity !== null && activity.window.truncated) {
|
|
437
|
+
warnings.push({
|
|
438
|
+
level: 'info',
|
|
439
|
+
code: 'activity-window-truncated',
|
|
440
|
+
message: `Git 活动窗口达到 ${activity.window.maxCommits} 个提交上限,更早的活动未统计`,
|
|
441
|
+
evidence: { maxCommits: activity.window.maxCommits, sinceDays: activity.window.sinceDays },
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
return {
|
|
445
|
+
repo: {
|
|
446
|
+
path: absRepo,
|
|
447
|
+
name: registryEntry?.name ?? path.basename(absRepo),
|
|
448
|
+
storagePath: meta?.storagePath ?? path.join(absRepo, '.gitnexus'),
|
|
449
|
+
indexed: meta !== null,
|
|
450
|
+
registered: registryEntry !== null,
|
|
451
|
+
// Which manifest the index was read from — `gitnexus.json` (current) or
|
|
452
|
+
// `meta.json` (legacy). Surfaced so a report can be explained without
|
|
453
|
+
// re-reading the disk.
|
|
454
|
+
metaFile: meta?.metaFile ?? null,
|
|
455
|
+
indexedAt: meta?.indexedAt ?? null,
|
|
456
|
+
lastCommit: meta?.lastCommit ?? null,
|
|
457
|
+
branch: meta?.branch ?? registryEntry?.branch ?? null,
|
|
458
|
+
remoteUrl: meta?.raw?.remoteUrl ?? registryEntry?.remoteUrl ?? null,
|
|
459
|
+
stats: meta?.stats ?? null,
|
|
460
|
+
graphEmbeddings: meta?.stats?.embeddings ?? null,
|
|
461
|
+
},
|
|
462
|
+
// What the graph actually holds. Every one of these was already in the
|
|
463
|
+
// manifest and was being discarded — the panel showed the file count and
|
|
464
|
+
// nothing else about the index's contents.
|
|
465
|
+
graph: meta === null ? null : {
|
|
466
|
+
files: meta.stats?.files ?? 0,
|
|
467
|
+
nodes: meta.stats?.nodes ?? 0,
|
|
468
|
+
edges: meta.stats?.edges ?? 0,
|
|
469
|
+
communities: meta.stats?.communities ?? 0,
|
|
470
|
+
processes: meta.stats?.processes ?? 0,
|
|
471
|
+
embeddings: meta.stats?.embeddings ?? 0,
|
|
472
|
+
edgesPerNode: meta.stats?.nodes > 0 ? (meta.stats.edges ?? 0) / meta.stats.nodes : 0,
|
|
473
|
+
},
|
|
474
|
+
// Which query surfaces are actually available. A disabled FTS or vector index
|
|
475
|
+
// changes what the graph can answer, so it belongs next to the counts rather
|
|
476
|
+
// than in a log line.
|
|
477
|
+
capabilities: readCapabilities(meta?.capabilities),
|
|
478
|
+
staleness: {
|
|
479
|
+
state: staleness,
|
|
480
|
+
indexedCommit: meta?.lastCommit ?? null,
|
|
481
|
+
headCommit: git.headCommit,
|
|
482
|
+
branch: git.branch,
|
|
483
|
+
dirtyCount: git.dirtyCount,
|
|
484
|
+
aheadBehind: git.aheadBehind,
|
|
485
|
+
gitAvailable: git.available,
|
|
486
|
+
},
|
|
487
|
+
// Provenance and analysis configuration. Each of these, if changed, forces a
|
|
488
|
+
// full rebuild — so showing them is showing why an index might be about to be
|
|
489
|
+
// rebuilt rather than updated.
|
|
490
|
+
provenance: meta === null ? null : {
|
|
491
|
+
schemaFingerprint: meta.schemaFingerprint ?? null,
|
|
492
|
+
contentRetention: meta.raw?.contentRetention ?? null,
|
|
493
|
+
ftsProfile: meta.raw?.ftsProfile ?? null,
|
|
494
|
+
analysisFeatures: meta.raw?.analysisFeatures ?? null,
|
|
495
|
+
crossLanguageProperties: Array.isArray(meta.raw?.crossLanguageProperties)
|
|
496
|
+
? meta.raw.crossLanguageProperties.length
|
|
497
|
+
: 0,
|
|
498
|
+
runnerCliVersion: meta.runnerIdentity?.cliVersion ?? null,
|
|
499
|
+
},
|
|
500
|
+
// Graph quality: receiver members the resolver could not type. GitNexus's own
|
|
501
|
+
// `impact`/`context` read this to publish an `exact` vs `lower-bound` verdict,
|
|
502
|
+
// so it is the honest caveat to put in front of a reader.
|
|
503
|
+
graphQuality: readGraphQuality(meta?.raw?.unresolvedReceiverMembers),
|
|
504
|
+
analyzer: {
|
|
505
|
+
gitnexusVersion: scan.gitnexusVersion,
|
|
506
|
+
primitives: scan.primitives,
|
|
507
|
+
},
|
|
508
|
+
cap: {
|
|
509
|
+
bytes: scan.capBytes,
|
|
510
|
+
text: formatBytes(scan.capBytes),
|
|
511
|
+
source: scan.capSource,
|
|
512
|
+
defaultBytes: scan.defaultCapBytes,
|
|
513
|
+
defaultText: formatBytes(scan.defaultCapBytes),
|
|
514
|
+
maxBytes: scan.maxCapBytes,
|
|
515
|
+
maxText: formatBytes(scan.maxCapBytes),
|
|
516
|
+
recordedInIndex: scan.capSource === 'index',
|
|
517
|
+
},
|
|
518
|
+
totals: {
|
|
519
|
+
scanned: scan.scannedCount,
|
|
520
|
+
selected: scan.selected.length,
|
|
521
|
+
large: scan.large.length,
|
|
522
|
+
suppressedDeclarations: scan.suppressedDeclarations.length,
|
|
523
|
+
indexedInGraph: meta ? Object.keys(meta.fileHashes).length : 0,
|
|
524
|
+
largeBytes,
|
|
525
|
+
scannedBytes,
|
|
526
|
+
},
|
|
527
|
+
largeFiles,
|
|
528
|
+
attribution: {
|
|
529
|
+
oversizeCount: scan.large.length,
|
|
530
|
+
oversizeBytes: largeBytes,
|
|
531
|
+
oversizeShareOfScanned: scannedBytes > 0 ? largeBytes / scannedBytes : 0,
|
|
532
|
+
},
|
|
533
|
+
index: {
|
|
534
|
+
uncoveredCount: uncovered.length,
|
|
535
|
+
uncoveredSample: uncovered.slice(0, 20).map((f) => ({ path: f.path, size: f.size })),
|
|
536
|
+
staleCount: staleInIndex.length,
|
|
537
|
+
staleSample: staleInIndex.slice(0, 20),
|
|
538
|
+
dirtyPaths: meta?.dirtyPaths ?? [],
|
|
539
|
+
},
|
|
540
|
+
warnings,
|
|
541
|
+
languages: languagesReport,
|
|
542
|
+
activity,
|
|
543
|
+
// Filesystem-only probe, so it costs a few `existsSync` calls. Reported on every
|
|
544
|
+
// read rather than once at startup: a GitNexus installed while the panel is open
|
|
545
|
+
// should start working without the operator restarting anything.
|
|
546
|
+
toolchain: readToolchainStatus({
|
|
547
|
+
env: options.env,
|
|
548
|
+
...(options.toolchain?.managedPrefix === undefined ? {} : { managedPrefix: options.toolchain.managedPrefix }),
|
|
549
|
+
}),
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/gitnexus/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain-text rendering of a coverage report.
|
|
3
|
+
*
|
|
4
|
+
* Kept free of any DSH import so it can be tested — and reused — without a host
|
|
5
|
+
* running. Tool output is read by a model as often as by a person, so there is no
|
|
6
|
+
* ANSI here; `bin/gitnexus-coverage.mjs` owns the colourised terminal variant.
|
|
7
|
+
*/
|
|
8
|
+
import { type CoverageReport } from './coverage.js';
|
|
9
|
+
/**
|
|
10
|
+
* Render a coverage report as plain text.
|
|
11
|
+
*
|
|
12
|
+
* @param report the report to render
|
|
13
|
+
* @param withLanguages include the per-language breakdown
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatReport(report: CoverageReport, withLanguages?: boolean): string;
|
|
16
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/gitnexus/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAIL,KAAK,cAAc,EAEpB,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,aAAa,UAAO,GAAG,MAAM,CA0LjF"}
|