dsh-gitnexus-plus 0.1.3 → 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 +22 -7
- package/README.md +41 -8
- 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 +4081 -2370
- package/lib/gitnexus/analyze.d.ts +48 -8
- package/lib/gitnexus/analyze.d.ts.map +1 -1
- package/lib/gitnexus/analyze.js +345 -84
- 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/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 +13 -21
- package/lib/gitnexus/git-activity.d.ts.map +1 -1
- package/lib/gitnexus/git-activity.js +60 -26
- 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/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 +165 -3
- 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/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/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 +2 -2
package/lib/gitnexus/commands.js
CHANGED
|
@@ -161,6 +161,25 @@ export function maintenanceCommands(repoPath, options = {}) {
|
|
|
161
161
|
destructive: true,
|
|
162
162
|
caveat: '--force 重建图与 FTS,未变更文件的解析产物仍会复用。',
|
|
163
163
|
},
|
|
164
|
+
// Offered only when the index says FTS is unavailable — otherwise it is a no-op
|
|
165
|
+
// that looks like a feature. Deliberately **not** built on `common`: that array
|
|
166
|
+
// carries `--skip-fts` in the deployment where FTS is missing, and passing
|
|
167
|
+
// `--skip-fts --repair-fts` asks to repair what it was just told to skip.
|
|
168
|
+
...(options.includeRepair === true
|
|
169
|
+
? [
|
|
170
|
+
{
|
|
171
|
+
mode: 'repair-fts',
|
|
172
|
+
label: '修复搜索索引(FTS)',
|
|
173
|
+
when: '面板显示 FTS 不可用、关键词搜索只能按名称匹配时使用。只重建搜索索引,不重跑分析。修复要在子进程里加载 FTS 扩展,因此系统需要具备原生运行时(Windows:VC++ 2015-2022 x64 与 OpenSSL 3)。',
|
|
174
|
+
argv: `gitnexus ${['analyze', '--index-only', '--repair-fts', quote(repoPath)].join(' ')}`,
|
|
175
|
+
shell: envPrefix() +
|
|
176
|
+
`gitnexus ${['analyze', '--index-only', '--repair-fts', quote(repoPath)].join(' ')}`,
|
|
177
|
+
destructive: false,
|
|
178
|
+
caveat: '只修复搜索索引,不改图。两种失败要分清:受限沙箱会拒绝子进程(spawn EPERM,需在普通终端执行);' +
|
|
179
|
+
'若提示"扩展文件存在但加载不了",那是系统缺少原生运行时,装好后再修复,重装 GitNexus 通常无用。',
|
|
180
|
+
},
|
|
181
|
+
]
|
|
182
|
+
: []),
|
|
164
183
|
];
|
|
165
184
|
}
|
|
166
185
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/gitnexus/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,8EAA8E;AAC9E,MAAM,OAAO,GAAG,IAAI,CAAC;AAErB;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,KAAK,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAElF,CAAC;YACF,0EAA0E;YAC1E,6EAA6E;YAC7E,wCAAwC;YACxC,OAAO,GAAG,CAAC,YAAY,EAAE,GAAG,EAAE,MAAM,KAAK,WAAW,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,iCAAiC;QACnC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,UAAmB;IACpE,OAAO,UAAU,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;AAC/C,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/gitnexus/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
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
|
+
/**
|
|
49
|
+
* How much a changed file is, for the panel's purposes.
|
|
50
|
+
*
|
|
51
|
+
* `updated` covers both "content differs from the hash" and "the file is gone", but the
|
|
52
|
+
* distinction matters to the operator — a deletion is not a modification of the same
|
|
53
|
+
* unit — so they stay separate kinds.
|
|
54
|
+
*/
|
|
55
|
+
export type DeltaKind = 'modified' | 'added' | 'deleted' | 'excluded';
|
|
56
|
+
export interface DeltaEntry {
|
|
57
|
+
/** repo-relative, forward slashes — the same form `fileHashes` uses */
|
|
58
|
+
path: string;
|
|
59
|
+
kind: DeltaKind;
|
|
60
|
+
/** why this path was classified as excluded; null for every other kind */
|
|
61
|
+
reason: string | null;
|
|
62
|
+
}
|
|
63
|
+
/** Which side the candidate set came from. */
|
|
64
|
+
export type DeltaBasis =
|
|
65
|
+
/** the index recorded a commit that git still knows: exact comparison */
|
|
66
|
+
'index'
|
|
67
|
+
/** the index recorded no usable commit: only working-tree-vs-HEAD was checked */
|
|
68
|
+
| 'worktree';
|
|
69
|
+
export interface DeltaCounts {
|
|
70
|
+
/** candidates examined */
|
|
71
|
+
checked: number;
|
|
72
|
+
/** content actually read for a hash — the cost signal */
|
|
73
|
+
hashed: number;
|
|
74
|
+
/** hashes that matched the index */
|
|
75
|
+
unchanged: number;
|
|
76
|
+
modified: number;
|
|
77
|
+
added: number;
|
|
78
|
+
deleted: number;
|
|
79
|
+
/** changed, but the index's own policy would skip these */
|
|
80
|
+
excluded: number;
|
|
81
|
+
}
|
|
82
|
+
export interface DeltaReport {
|
|
83
|
+
repoPath: string;
|
|
84
|
+
/** whether an index manifest was found at all */
|
|
85
|
+
indexed: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Whether a content comparison was possible. `false` with a `notes` entry is the
|
|
88
|
+
* answer for a project with no index, an older manifest without `fileHashes`, or no
|
|
89
|
+
* usable git — in each case the caller should fall back to asking the analyzer.
|
|
90
|
+
*/
|
|
91
|
+
comparable: boolean;
|
|
92
|
+
basis: DeltaBasis | null;
|
|
93
|
+
indexedCommit: string | null;
|
|
94
|
+
headCommit: string | null;
|
|
95
|
+
/** actionable + excluded entries, sorted by path */
|
|
96
|
+
entries: DeltaEntry[];
|
|
97
|
+
counts: DeltaCounts;
|
|
98
|
+
/**
|
|
99
|
+
* Whether a refresh would plausibly change the index. Excluded files do not count:
|
|
100
|
+
* re-running the analyzer would skip them again.
|
|
101
|
+
*
|
|
102
|
+
* Only meaningful together with {@link certain}. A `false` from a worktree-basis
|
|
103
|
+
* comparison means "no uncommitted change", not "the index is current".
|
|
104
|
+
*/
|
|
105
|
+
needsRefresh: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Whether the answer is anchored to the index's own commit.
|
|
108
|
+
*
|
|
109
|
+
* When the manifest records no usable commit, the comparison degrades to
|
|
110
|
+
* working-tree-vs-HEAD, which cannot see commits made after the index was built. That
|
|
111
|
+
* is exactly the case a staleness gate must not report as clean — measured on this
|
|
112
|
+
* repository: a rebuild wrote an empty `lastCommit`, the tree was clean, and the gate
|
|
113
|
+
* said 无需刷新 while any later commit would have made it stale.
|
|
114
|
+
*/
|
|
115
|
+
certain: boolean;
|
|
116
|
+
/** the candidate set hit the cap; entries may be incomplete */
|
|
117
|
+
truncated: boolean;
|
|
118
|
+
/** operator-facing explanation of the verdict, in order of importance */
|
|
119
|
+
notes: string[];
|
|
120
|
+
durationMs: number;
|
|
121
|
+
readAt: string;
|
|
122
|
+
}
|
|
123
|
+
export interface DeltaOptions {
|
|
124
|
+
/**
|
|
125
|
+
* Candidate cap. A candidate set this large means the index is far behind or the
|
|
126
|
+
* repository has thousands of dirty files; at that point the precise answer stops
|
|
127
|
+
* being worth the reads and the caller should just refresh.
|
|
128
|
+
*/
|
|
129
|
+
maxFiles?: number;
|
|
130
|
+
/** Parallel file reads while hashing. Small: these are local reads. */
|
|
131
|
+
hashConcurrency?: number;
|
|
132
|
+
/** `git` timeout for one call. */
|
|
133
|
+
gitTimeoutMs?: number;
|
|
134
|
+
now?: () => number;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Compare the working tree against the content the index recorded.
|
|
138
|
+
*
|
|
139
|
+
* @param repoPath absolute repository root
|
|
140
|
+
*/
|
|
141
|
+
export declare function readDelta(repoPath: string, options?: DeltaOptions): Promise<DeltaReport>;
|
|
142
|
+
/** One-line verdict for a tool result or a log line. */
|
|
143
|
+
export declare function describeDelta(report: DeltaReport): string;
|
|
144
|
+
//# sourceMappingURL=delta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.d.ts","sourceRoot":"","sources":["../../src/gitnexus/delta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAyBH;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,8CAA8C;AAC9C,MAAM,MAAM,UAAU;AACpB,yEAAyE;AACvE,OAAO;AACT,iFAAiF;GAC/E,UAAU,CAAC;AAEf,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oDAAoD;IACpD,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;IACpB;;;;;;OAMG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;;;;OAQG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,SAAS,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AA6DD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAqOlG;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAmBzD"}
|
|
@@ -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
|
|
@@ -156,27 +157,18 @@ export interface ActivityInfo {
|
|
|
156
157
|
/** True when the activity window held more commits than the timeline cap. */
|
|
157
158
|
timelineTruncated: boolean;
|
|
158
159
|
}
|
|
159
|
-
/** One commit
|
|
160
|
-
export
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
export
|
|
171
|
-
path: string;
|
|
172
|
-
available: boolean;
|
|
173
|
-
days: number;
|
|
174
|
-
commits: number;
|
|
175
|
-
insertions: number;
|
|
176
|
-
deletions: number;
|
|
177
|
-
timeline: FileHistoryCommit[];
|
|
178
|
-
reason: string | null;
|
|
179
|
-
}
|
|
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';
|
|
180
172
|
export interface ReadFileHistoryOptions {
|
|
181
173
|
days?: number;
|
|
182
174
|
maxCommits?: number;
|
|
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAqB,MAAM,mBAAmB,CAAC;AAoCpF;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,2EAA2E;IAC3E,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACtC,UAAU,EAAE,OAAO,CAAC;IACpB,0BAA0B,EAAE,MAAM,CAAC;IACnC,6BAA6B,EAAE,MAAM,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gEAAgE;IAChE,KAAK,EAAE,aAAa,CAAC;IACrB,oFAAoF;IACpF,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,8EAA8E;IAC9E,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,6EAA6E;IAC7E,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,mEAAmE;AACnE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKpD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,CAAC,CAsBrB;AAED,yEAAyE;AACzE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAExE,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AA8BD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,iBAAiB,CAiD5F;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAga9B;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,WAAW,CAAC,CAuGtB"}
|