dsh-gitnexus-plus 0.1.2 → 0.1.4
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-CN.md +189 -0
- package/README.md +219 -597
- package/lib/bin/graph-helper.d.ts +21 -0
- package/lib/bin/graph-helper.d.ts.map +1 -0
- package/lib/bin/graph-helper.js +71 -0
- package/lib/bin/graph-helper.js.map +1 -0
- package/lib/client.js +4107 -2029
- package/lib/gitnexus/analyze.d.ts +48 -8
- package/lib/gitnexus/analyze.d.ts.map +1 -1
- package/lib/gitnexus/analyze.js +376 -75
- package/lib/gitnexus/analyze.js.map +1 -1
- package/lib/gitnexus/commands.d.ts +8 -1
- package/lib/gitnexus/commands.d.ts.map +1 -1
- package/lib/gitnexus/commands.js +19 -0
- package/lib/gitnexus/commands.js.map +1 -1
- package/lib/gitnexus/coverage.d.ts +16 -0
- package/lib/gitnexus/coverage.d.ts.map +1 -1
- package/lib/gitnexus/coverage.js +58 -1
- package/lib/gitnexus/coverage.js.map +1 -1
- package/lib/gitnexus/delta.d.ts +144 -0
- package/lib/gitnexus/delta.d.ts.map +1 -0
- package/lib/gitnexus/delta.js +347 -0
- package/lib/gitnexus/delta.js.map +1 -0
- package/lib/gitnexus/git-activity.d.ts +77 -0
- package/lib/gitnexus/git-activity.d.ts.map +1 -1
- package/lib/gitnexus/git-activity.js +327 -8
- package/lib/gitnexus/git-activity.js.map +1 -1
- package/lib/gitnexus/graph.d.ts +126 -0
- package/lib/gitnexus/graph.d.ts.map +1 -0
- package/lib/gitnexus/graph.js +472 -0
- package/lib/gitnexus/graph.js.map +1 -0
- package/lib/gitnexus/root.d.ts +0 -3
- package/lib/gitnexus/root.d.ts.map +1 -1
- package/lib/gitnexus/root.js +64 -5
- package/lib/gitnexus/root.js.map +1 -1
- package/lib/gitnexus/scan.d.ts +2 -0
- package/lib/gitnexus/scan.d.ts.map +1 -1
- package/lib/gitnexus/scan.js +3 -2
- package/lib/gitnexus/scan.js.map +1 -1
- package/lib/gitnexus/search.d.ts +21 -8
- package/lib/gitnexus/search.d.ts.map +1 -1
- package/lib/gitnexus/search.js +87 -13
- package/lib/gitnexus/search.js.map +1 -1
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +170 -2
- package/lib/index.js.map +1 -1
- package/lib/routes/analyze.d.ts +3 -2
- package/lib/routes/analyze.d.ts.map +1 -1
- package/lib/routes/analyze.js +8 -2
- package/lib/routes/analyze.js.map +1 -1
- package/lib/routes/coverage.d.ts +2 -1
- package/lib/routes/coverage.d.ts.map +1 -1
- package/lib/routes/coverage.js +53 -1
- package/lib/routes/coverage.js.map +1 -1
- package/lib/routes/delta.d.ts +22 -0
- package/lib/routes/delta.d.ts.map +1 -0
- package/lib/routes/delta.js +50 -0
- package/lib/routes/delta.js.map +1 -0
- package/lib/routes/file-diff.d.ts +19 -0
- package/lib/routes/file-diff.d.ts.map +1 -0
- package/lib/routes/file-diff.js +69 -0
- package/lib/routes/file-diff.js.map +1 -0
- package/lib/routes/file-history.d.ts +21 -0
- package/lib/routes/file-history.d.ts.map +1 -0
- package/lib/routes/file-history.js +69 -0
- package/lib/routes/file-history.js.map +1 -0
- package/lib/routes/graph.d.ts +22 -0
- package/lib/routes/graph.d.ts.map +1 -0
- package/lib/routes/graph.js +71 -0
- package/lib/routes/graph.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 0 staleness: is a refresh worth running at all?
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS
|
|
5
|
+
* ---------------
|
|
6
|
+
* The panel's only maintenance action used to be "run `gitnexus analyze`", and it ran
|
|
7
|
+
* the analyzer every time — on a repository where nothing had changed since the index
|
|
8
|
+
* was written. That is not a correctness bug, it is a cost bug with a bad shape: the
|
|
9
|
+
* work is measured in seconds on a small repository and in minutes on a large one, and
|
|
10
|
+
* the user has no way to know beforehand whether they are about to spend it.
|
|
11
|
+
*
|
|
12
|
+
* The index already records what it saw: `.gitnexus/gitnexus.json` carries
|
|
13
|
+
* `fileHashes`, a map of repo-relative path to sha256. Comparing the working tree
|
|
14
|
+
* against those hashes answers "would a re-analysis change anything?" exactly, and it
|
|
15
|
+
* needs nothing but git and a hash function.
|
|
16
|
+
*
|
|
17
|
+
* WHAT IS COMPARED, AND AGAINST WHAT
|
|
18
|
+
* ----------------------------------
|
|
19
|
+
* The baseline is the **index snapshot**, not `HEAD`. Those differ whenever the index
|
|
20
|
+
* was built from a dirty tree, and the manifest records that case in
|
|
21
|
+
* `indexCoverage.dirtyPaths`. Comparing against `HEAD` would call a file unchanged
|
|
22
|
+
* merely because it was committed, even though the index remembered different content
|
|
23
|
+
* — which is the direction that produces a stale graph the panel says is current.
|
|
24
|
+
*
|
|
25
|
+
* The candidate set is therefore everything that differs from the *indexed commit*:
|
|
26
|
+
*
|
|
27
|
+
* `git diff --no-renames --name-only <lastCommit>` tracked files, working tree vs
|
|
28
|
+
* that commit (staged and unstaged)
|
|
29
|
+
* `git ls-files --others --exclude-standard` untracked files git would include
|
|
30
|
+
*
|
|
31
|
+
* `--no-renames` on purpose: with rename detection on, git reports only the new path,
|
|
32
|
+
* so a rename looks like a pure addition and the index's old path silently disappears
|
|
33
|
+
* from the comparison. Forcing add+delete pairs lets each side be classified on its
|
|
34
|
+
* own evidence.
|
|
35
|
+
*
|
|
36
|
+
* Hash comparison is per candidate, not per indexed file, which is what keeps this
|
|
37
|
+
* cheap: a clean working tree produces an empty candidate set and no file is read at
|
|
38
|
+
* all. `mtime` is *not* used as a prefilter even though the plan called for one — the
|
|
39
|
+
* manifest stores a hash and no mtime, so "the mtime did not move" cannot prove the
|
|
40
|
+
* content matches, and using it would trade an exact answer for a fast wrong one.
|
|
41
|
+
*
|
|
42
|
+
* WHAT IT DOES NOT DO
|
|
43
|
+
* -------------------
|
|
44
|
+
* It never runs the analyzer, never writes, and never reads the graph. It also does not
|
|
45
|
+
* decide *which* tier of refresh to run — that needs the analyzer's own judgement about
|
|
46
|
+
* schema and FTS state. It answers one question: has indexed content changed?
|
|
47
|
+
*/
|
|
48
|
+
import { createHash } from 'node:crypto';
|
|
49
|
+
import { createReadStream } from 'node:fs';
|
|
50
|
+
import fs from 'node:fs/promises';
|
|
51
|
+
import path from 'node:path';
|
|
52
|
+
import { execFile } from 'node:child_process';
|
|
53
|
+
import { promisify } from 'node:util';
|
|
54
|
+
import { formatBytes } from './coverage.js';
|
|
55
|
+
import { readIndexMeta } from './index-meta.js';
|
|
56
|
+
/**
|
|
57
|
+
* `execFile`, promisified, resolved as decoded text.
|
|
58
|
+
*
|
|
59
|
+
* No shell: the repository path is caller-supplied and only ever travels as `cwd`.
|
|
60
|
+
* `-z` output is NUL-separated rather than newline-separated precisely because a path
|
|
61
|
+
* may contain a newline, and `git status` would otherwise quote it into an unparseable
|
|
62
|
+
* form.
|
|
63
|
+
*/
|
|
64
|
+
const run = promisify(execFile);
|
|
65
|
+
const DEFAULT_MAX_FILES = 4000;
|
|
66
|
+
const DEFAULT_HASH_CONCURRENCY = 8;
|
|
67
|
+
const DEFAULT_GIT_TIMEOUT_MS = 15_000;
|
|
68
|
+
/** Run one git command, or report that git could not answer. */
|
|
69
|
+
async function git(repoPath, args, timeoutMs) {
|
|
70
|
+
try {
|
|
71
|
+
const { stdout } = await run('git', args, {
|
|
72
|
+
cwd: repoPath,
|
|
73
|
+
timeout: timeoutMs,
|
|
74
|
+
windowsHide: true,
|
|
75
|
+
// Name lists on a very large repository can exceed the default 1 MB cap. The
|
|
76
|
+
// cap exists so a runaway command cannot exhaust memory; 32 MB of paths is
|
|
77
|
+
// already an unreasonable candidate set, and `maxFiles` truncates it anyway.
|
|
78
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
79
|
+
});
|
|
80
|
+
return stdout;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Split `-z` output on NUL and drop the trailing empty record. */
|
|
87
|
+
function splitNul(text) {
|
|
88
|
+
return text.split('\0').filter((part) => part !== '');
|
|
89
|
+
}
|
|
90
|
+
/** The key form `fileHashes` uses: forward slashes, no leading `./`. */
|
|
91
|
+
function toKey(relativePath) {
|
|
92
|
+
return relativePath.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
93
|
+
}
|
|
94
|
+
/** Stream one file through sha256. Returns null when it cannot be read. */
|
|
95
|
+
async function hashFile(absolutePath) {
|
|
96
|
+
try {
|
|
97
|
+
const hash = createHash('sha256');
|
|
98
|
+
await new Promise((resolvePromise, reject) => {
|
|
99
|
+
const stream = createReadStream(absolutePath);
|
|
100
|
+
stream.on('error', reject);
|
|
101
|
+
stream.on('data', (chunk) => hash.update(chunk));
|
|
102
|
+
stream.on('end', () => resolvePromise());
|
|
103
|
+
});
|
|
104
|
+
return hash.digest('hex');
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** The counts of an empty report, so every early return carries the same shape. */
|
|
111
|
+
const ZERO_COUNTS = {
|
|
112
|
+
checked: 0,
|
|
113
|
+
hashed: 0,
|
|
114
|
+
unchanged: 0,
|
|
115
|
+
modified: 0,
|
|
116
|
+
added: 0,
|
|
117
|
+
deleted: 0,
|
|
118
|
+
excluded: 0,
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Compare the working tree against the content the index recorded.
|
|
122
|
+
*
|
|
123
|
+
* @param repoPath absolute repository root
|
|
124
|
+
*/
|
|
125
|
+
export async function readDelta(repoPath, options = {}) {
|
|
126
|
+
const now = options.now ?? (() => Date.now());
|
|
127
|
+
const startedAt = now();
|
|
128
|
+
const absRepo = path.resolve(repoPath);
|
|
129
|
+
const maxFiles = options.maxFiles ?? DEFAULT_MAX_FILES;
|
|
130
|
+
const concurrency = Math.max(1, options.hashConcurrency ?? DEFAULT_HASH_CONCURRENCY);
|
|
131
|
+
const gitTimeoutMs = options.gitTimeoutMs ?? DEFAULT_GIT_TIMEOUT_MS;
|
|
132
|
+
const empty = (patch) => ({
|
|
133
|
+
repoPath: absRepo,
|
|
134
|
+
indexed: false,
|
|
135
|
+
comparable: false,
|
|
136
|
+
basis: null,
|
|
137
|
+
indexedCommit: null,
|
|
138
|
+
headCommit: null,
|
|
139
|
+
entries: [],
|
|
140
|
+
counts: { ...ZERO_COUNTS },
|
|
141
|
+
needsRefresh: false,
|
|
142
|
+
certain: false,
|
|
143
|
+
truncated: false,
|
|
144
|
+
notes: [],
|
|
145
|
+
durationMs: now() - startedAt,
|
|
146
|
+
readAt: new Date().toISOString(),
|
|
147
|
+
...patch,
|
|
148
|
+
});
|
|
149
|
+
const meta = await readIndexMeta(absRepo);
|
|
150
|
+
if (meta === null) {
|
|
151
|
+
return empty({ notes: ['该项目还没有 GitNexus 索引,先初始化再说'] });
|
|
152
|
+
}
|
|
153
|
+
const indexedCommit = meta.lastCommit === '' ? null : meta.lastCommit;
|
|
154
|
+
const base = { indexed: true, indexedCommit };
|
|
155
|
+
// The map is normalized-key -> original key, and the hash is read through the
|
|
156
|
+
// original: `fileHashes` is written by GitNexus, and a manifest whose keys use
|
|
157
|
+
// backslashes (Windows builds did) must still match the forward-slash key git
|
|
158
|
+
// reports. Rewriting the manifest's keys instead would mutate what we only read.
|
|
159
|
+
const hashByKey = new Map();
|
|
160
|
+
for (const [rawPath, hash] of Object.entries(meta.fileHashes)) {
|
|
161
|
+
hashByKey.set(toKey(rawPath), hash.toLowerCase());
|
|
162
|
+
}
|
|
163
|
+
if (hashByKey.size === 0) {
|
|
164
|
+
return empty({
|
|
165
|
+
...base,
|
|
166
|
+
notes: ['该索引没有记录文件哈希(旧格式 manifest),无法判断内容是否变化 —— 直接刷新'],
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const headCommit = (await git(absRepo, ['rev-parse', 'HEAD'], gitTimeoutMs))?.trim() ?? null;
|
|
170
|
+
let basis = null;
|
|
171
|
+
let candidates = [];
|
|
172
|
+
if (indexedCommit !== null && headCommit !== null) {
|
|
173
|
+
const diff = await git(absRepo, ['diff', '--no-renames', '--name-only', '-z', indexedCommit, '--'], gitTimeoutMs);
|
|
174
|
+
if (diff !== null) {
|
|
175
|
+
basis = 'index';
|
|
176
|
+
candidates = splitNul(diff);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (basis === null && headCommit !== null) {
|
|
180
|
+
// The recorded commit is gone (rebase, branch rewrite, shallow clone) or the
|
|
181
|
+
// manifest never had one. Working tree vs HEAD is the honest fallback: it finds
|
|
182
|
+
// uncommitted and newly committed files, and it cannot see a difference that was
|
|
183
|
+
// committed before the index was written. Say so rather than implying otherwise.
|
|
184
|
+
const againstHead = await git(absRepo, ['diff', '--no-renames', '--name-only', '-z', 'HEAD', '--'], gitTimeoutMs);
|
|
185
|
+
if (againstHead !== null) {
|
|
186
|
+
basis = 'worktree';
|
|
187
|
+
candidates = splitNul(againstHead);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (basis === null) {
|
|
191
|
+
return empty({
|
|
192
|
+
...base,
|
|
193
|
+
headCommit,
|
|
194
|
+
notes: [
|
|
195
|
+
indexedCommit === null
|
|
196
|
+
? '索引没有记录提交基线,且 git 也无法读取 HEAD —— 无法比较,直接刷新'
|
|
197
|
+
: '索引记录的提交在本地 git 历史中已不可用,且无法读取 HEAD —— 无法比较,直接刷新',
|
|
198
|
+
],
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
const untracked = await git(absRepo, ['ls-files', '--others', '--exclude-standard', '-z'], gitTimeoutMs);
|
|
202
|
+
if (untracked !== null) {
|
|
203
|
+
candidates.push(...splitNul(untracked));
|
|
204
|
+
}
|
|
205
|
+
const seen = new Set();
|
|
206
|
+
const unique = [];
|
|
207
|
+
for (const candidate of candidates) {
|
|
208
|
+
const key = toKey(candidate);
|
|
209
|
+
if (key === '' || seen.has(key))
|
|
210
|
+
continue;
|
|
211
|
+
// The index's own storage is never indexed content. `.gitnexus/` self-ignores in
|
|
212
|
+
// most repositories (GitNexus writes a `*` .gitignore there), so this only matters
|
|
213
|
+
// where it does not — but in exactly that case every read would report the index
|
|
214
|
+
// manifest itself as a new file and ask for a refresh forever.
|
|
215
|
+
if (key.startsWith('.gitnexus/') || key.startsWith('.git/'))
|
|
216
|
+
continue;
|
|
217
|
+
seen.add(key);
|
|
218
|
+
unique.push(key);
|
|
219
|
+
}
|
|
220
|
+
unique.sort();
|
|
221
|
+
const truncated = unique.length > maxFiles;
|
|
222
|
+
const examined = truncated ? unique.slice(0, maxFiles) : unique;
|
|
223
|
+
const entries = [];
|
|
224
|
+
const counts = { ...ZERO_COUNTS };
|
|
225
|
+
counts.checked = examined.length;
|
|
226
|
+
// Bounded parallelism rather than one read at a time: a 4000-file candidate set read
|
|
227
|
+
// sequentially is dominated by syscall latency, and these are local files.
|
|
228
|
+
for (let offset = 0; offset < examined.length; offset += concurrency) {
|
|
229
|
+
const batch = examined.slice(offset, offset + concurrency);
|
|
230
|
+
const settled = await Promise.all(batch.map(async (key) => {
|
|
231
|
+
const absolute = path.join(absRepo, key);
|
|
232
|
+
let size;
|
|
233
|
+
try {
|
|
234
|
+
const stat = await fs.stat(absolute);
|
|
235
|
+
if (!stat.isFile())
|
|
236
|
+
return null;
|
|
237
|
+
size = stat.size;
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Gone from the working tree. Only worth reporting when the index had it;
|
|
241
|
+
// an untracked file deleted between `ls-files` and this stat is not news.
|
|
242
|
+
return hashByKey.has(key) ? { path: key, kind: 'deleted', reason: null } : null;
|
|
243
|
+
}
|
|
244
|
+
const recorded = hashByKey.get(key);
|
|
245
|
+
if (recorded === undefined) {
|
|
246
|
+
const cap = meta.coverageMaxFileSizeBytes;
|
|
247
|
+
if (cap !== null && size > cap) {
|
|
248
|
+
return {
|
|
249
|
+
path: key,
|
|
250
|
+
kind: 'excluded',
|
|
251
|
+
reason: `超过索引记录的大小上限(${formatBytes(cap)}),刷新也会被跳过`,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return { path: key, kind: 'added', reason: null };
|
|
255
|
+
}
|
|
256
|
+
counts.hashed += 1;
|
|
257
|
+
const current = await hashFile(absolute);
|
|
258
|
+
if (current === null) {
|
|
259
|
+
// Unreadable is not unchanged. Treating it as modified makes the panel ask
|
|
260
|
+
// for a refresh; treating it as unchanged would report a stale index as
|
|
261
|
+
// current, which is the one error this module exists to prevent.
|
|
262
|
+
return { path: key, kind: 'modified', reason: '无法读取文件内容,按已变更处理' };
|
|
263
|
+
}
|
|
264
|
+
if (current === recorded) {
|
|
265
|
+
counts.unchanged += 1;
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
return { path: key, kind: 'modified', reason: null };
|
|
269
|
+
}));
|
|
270
|
+
for (const entry of settled) {
|
|
271
|
+
if (entry !== null)
|
|
272
|
+
entries.push(entry);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
entries.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
276
|
+
for (const entry of entries)
|
|
277
|
+
counts[entry.kind] += 1;
|
|
278
|
+
const actionable = counts.modified + counts.added + counts.deleted;
|
|
279
|
+
const certain = basis === 'index';
|
|
280
|
+
const notes = [];
|
|
281
|
+
if (basis === 'worktree') {
|
|
282
|
+
notes.push('索引没有记录可用的提交基线:只比较了工作区相对 HEAD 的改动,索引建立之后已提交的改动看不到');
|
|
283
|
+
}
|
|
284
|
+
if (truncated) {
|
|
285
|
+
notes.push(`候选文件超过 ${maxFiles} 个,只检查了前 ${maxFiles} 个 —— 建议直接刷新`);
|
|
286
|
+
}
|
|
287
|
+
if (actionable === 0) {
|
|
288
|
+
// A clean worktree is not the same claim as a clean index. Saying "一致" on the
|
|
289
|
+
// worktree basis is how a stale index gets reported as current: the next commit
|
|
290
|
+
// makes it stale and this comparison will still be empty.
|
|
291
|
+
notes.push(certain
|
|
292
|
+
? counts.checked === 0
|
|
293
|
+
? '工作区与索引记录一致:没有任何文件相对索引提交发生改动'
|
|
294
|
+
: `工作区与索引记录一致:${counts.checked} 个候选文件中 ${counts.unchanged} 个内容哈希匹配` +
|
|
295
|
+
(counts.excluded > 0 ? `,${counts.excluded} 个属索引策略排除` : '')
|
|
296
|
+
: '工作区相对 HEAD 没有改动,但无法确认索引已包含当前提交 —— 需要刷新才能确定');
|
|
297
|
+
if (counts.excluded > 0) {
|
|
298
|
+
notes.push('被排除的文件刷新也会再次跳过,因此不需要为它们刷新索引');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
const parts = [];
|
|
303
|
+
if (counts.modified > 0)
|
|
304
|
+
parts.push(`${counts.modified} 个修改`);
|
|
305
|
+
if (counts.added > 0)
|
|
306
|
+
parts.push(`${counts.added} 个新增`);
|
|
307
|
+
if (counts.deleted > 0)
|
|
308
|
+
parts.push(`${counts.deleted} 个删除`);
|
|
309
|
+
notes.unshift(`索引内容已落后:${parts.join('、')}`);
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
repoPath: absRepo,
|
|
313
|
+
indexed: true,
|
|
314
|
+
comparable: true,
|
|
315
|
+
basis,
|
|
316
|
+
indexedCommit,
|
|
317
|
+
headCommit,
|
|
318
|
+
entries,
|
|
319
|
+
counts,
|
|
320
|
+
needsRefresh: actionable > 0,
|
|
321
|
+
certain,
|
|
322
|
+
truncated,
|
|
323
|
+
notes,
|
|
324
|
+
durationMs: now() - startedAt,
|
|
325
|
+
readAt: new Date().toISOString(),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
/** One-line verdict for a tool result or a log line. */
|
|
329
|
+
export function describeDelta(report) {
|
|
330
|
+
if (!report.comparable) {
|
|
331
|
+
return `无法差量判断:${report.notes[0] ?? '原因未知'}`;
|
|
332
|
+
}
|
|
333
|
+
if (!report.needsRefresh) {
|
|
334
|
+
return report.certain
|
|
335
|
+
? `无需刷新(${report.counts.checked} 个候选,${report.counts.hashed} 次哈希,${report.durationMs}ms)`
|
|
336
|
+
: `无法确认(${report.counts.checked} 个候选,${report.durationMs}ms):${report.notes[0] ?? '索引没有记录提交基线'}`;
|
|
337
|
+
}
|
|
338
|
+
const changed = report.entries.filter((entry) => entry.kind !== 'excluded');
|
|
339
|
+
const preview = changed
|
|
340
|
+
.slice(0, 10)
|
|
341
|
+
.map((entry) => `${entry.kind === 'modified' ? 'M' : entry.kind === 'added' ? 'A' : 'D'} ${entry.path}`)
|
|
342
|
+
.join('\n');
|
|
343
|
+
const more = changed.length > 10 ? `\n…还有 ${changed.length - 10} 个` : '';
|
|
344
|
+
return (`需要刷新:${report.counts.modified} 改 / ${report.counts.added} 增 / ${report.counts.deleted} 删` +
|
|
345
|
+
`(${report.durationMs}ms)\n${preview}${more}`);
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=delta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.js","sourceRoot":"","sources":["../../src/gitnexus/delta.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* truncated activity list reads as "this is all the activity there was", which is
|
|
22
22
|
* the one thing it must not mean.
|
|
23
23
|
*/
|
|
24
|
+
import type { CommitDiff, FileHistory } from 'dsh-gitnexus-wire';
|
|
24
25
|
/**
|
|
25
26
|
* indexed — the manifest holds this path, so the graph can answer about it.
|
|
26
27
|
* excluded — a fresh scan would not select it either (dotfile, ignore rule, or
|
|
@@ -58,6 +59,48 @@ export interface ActivityBranch {
|
|
|
58
59
|
lastAuthor: string;
|
|
59
60
|
current: boolean;
|
|
60
61
|
}
|
|
62
|
+
/** One commit in the activity window, with the index verdict of its touched files. */
|
|
63
|
+
export interface ActivityCommit {
|
|
64
|
+
sha: string;
|
|
65
|
+
shortSha: string;
|
|
66
|
+
date: string;
|
|
67
|
+
author: string;
|
|
68
|
+
subject: string;
|
|
69
|
+
files: number;
|
|
70
|
+
insertions: number;
|
|
71
|
+
deletions: number;
|
|
72
|
+
verdict: FileVerdict;
|
|
73
|
+
}
|
|
74
|
+
/** One row of the activity × index cross-tab. */
|
|
75
|
+
export interface ActivityCrossRow {
|
|
76
|
+
verdict: FileVerdict;
|
|
77
|
+
files: number;
|
|
78
|
+
changes: number;
|
|
79
|
+
insertions: number;
|
|
80
|
+
deletions: number;
|
|
81
|
+
}
|
|
82
|
+
export interface ActivityCross {
|
|
83
|
+
rows: ActivityCrossRow[];
|
|
84
|
+
totalFiles: number;
|
|
85
|
+
totalChanges: number;
|
|
86
|
+
}
|
|
87
|
+
/** What changed since the commit the index was built from. */
|
|
88
|
+
export interface ActivityBaseline {
|
|
89
|
+
ref: string | null;
|
|
90
|
+
/** `window` is the explicit fallback when the index recorded no commit. */
|
|
91
|
+
source: 'index' | 'window';
|
|
92
|
+
available: boolean;
|
|
93
|
+
shortSha: string | null;
|
|
94
|
+
date: string | null;
|
|
95
|
+
subject: string | null;
|
|
96
|
+
author: string | null;
|
|
97
|
+
commits: number;
|
|
98
|
+
files: number;
|
|
99
|
+
insertions: number;
|
|
100
|
+
deletions: number;
|
|
101
|
+
changedFiles: ActivityFile[];
|
|
102
|
+
reason: string | null;
|
|
103
|
+
}
|
|
61
104
|
export interface HistogramBucket {
|
|
62
105
|
label: string;
|
|
63
106
|
commits: number;
|
|
@@ -105,6 +148,30 @@ export interface ActivityInfo {
|
|
|
105
148
|
branches: ActivityBranch[];
|
|
106
149
|
histogram: ActivityHistogram;
|
|
107
150
|
currentBranch: string | null;
|
|
151
|
+
/** Activity × index cross-tab over every file in the window. */
|
|
152
|
+
cross: ActivityCross;
|
|
153
|
+
/** Changes since the index's recorded commit, or null when there is no baseline. */
|
|
154
|
+
baseline: ActivityBaseline | null;
|
|
155
|
+
/** Newest commits first, capped; each carries its aggregate index verdict. */
|
|
156
|
+
timeline: ActivityCommit[];
|
|
157
|
+
/** True when the activity window held more commits than the timeline cap. */
|
|
158
|
+
timelineTruncated: boolean;
|
|
159
|
+
}
|
|
160
|
+
/** One commit's patch for a single file, bounded for the panel. */
|
|
161
|
+
export type { CommitDiff } from 'dsh-gitnexus-wire';
|
|
162
|
+
/**
|
|
163
|
+
* The change a commit made to one file.
|
|
164
|
+
*
|
|
165
|
+
* `git show <sha> -- <path>` is the only command that answers this without checking
|
|
166
|
+
* out anything, and it is read-only. The path has already been resolved inside the
|
|
167
|
+
* project by the route; the sha is validated here because it reaches git as an argument.
|
|
168
|
+
*/
|
|
169
|
+
export declare function readCommitDiff(repoPath: string, filePath: string, sha: string): Promise<CommitDiff>;
|
|
170
|
+
/** One commit touching a specific file, and a file's bounded history. */
|
|
171
|
+
export type { FileHistory, FileHistoryCommit } from 'dsh-gitnexus-wire';
|
|
172
|
+
export interface ReadFileHistoryOptions {
|
|
173
|
+
days?: number;
|
|
174
|
+
maxCommits?: number;
|
|
108
175
|
}
|
|
109
176
|
export interface ReadGitActivityOptions {
|
|
110
177
|
sinceDays?: number;
|
|
@@ -114,6 +181,8 @@ export interface ReadGitActivityOptions {
|
|
|
114
181
|
maxBranches?: number;
|
|
115
182
|
indexedPaths?: Iterable<string>;
|
|
116
183
|
scannablePaths?: Iterable<string>;
|
|
184
|
+
/** The index's recorded commit; when set, also review HEAD against it. */
|
|
185
|
+
baselineRef?: string | null;
|
|
117
186
|
}
|
|
118
187
|
/**
|
|
119
188
|
* Bucket commit stamps into a time histogram.
|
|
@@ -133,4 +202,12 @@ export declare function buildHistogram(stamps: ActivityStamp[], sinceDays: numbe
|
|
|
133
202
|
* Returns `null` when git cannot answer at all.
|
|
134
203
|
*/
|
|
135
204
|
export declare function readGitActivity(repoPath: string, options?: ReadGitActivityOptions): Promise<ActivityInfo | null>;
|
|
205
|
+
/**
|
|
206
|
+
* Read one file's commits for its own timeline.
|
|
207
|
+
*
|
|
208
|
+
* Kept separate from {@link readGitActivity} because "show me this file's history"
|
|
209
|
+
* should not pay for the whole repository's numstat. `--follow` is intentional: a
|
|
210
|
+
* renamed file's timeline that stops at the rename is a misleading one.
|
|
211
|
+
*/
|
|
212
|
+
export declare function readFileActivity(repoPath: string, filePath: string, options?: ReadFileHistoryOptions): Promise<FileHistory>;
|
|
136
213
|
//# sourceMappingURL=git-activity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-activity.d.ts","sourceRoot":"","sources":["../../src/gitnexus/git-activity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;
|
|
1
|
+
{"version":3,"file":"git-activity.d.ts","sourceRoot":"","sources":["../../src/gitnexus/git-activity.ts"],"names":[],"mappings":"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"}
|