dsh-gitnexus-plus 0.1.1 → 0.1.3
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 +174 -0
- package/README.md +184 -447
- package/lib/bin/search-helper.d.ts +22 -0
- package/lib/bin/search-helper.d.ts.map +1 -0
- package/lib/bin/search-helper.js +57 -0
- package/lib/bin/search-helper.js.map +1 -0
- package/lib/client.js +978 -122
- package/lib/gitnexus/analyze.d.ts +27 -2
- package/lib/gitnexus/analyze.d.ts.map +1 -1
- package/lib/gitnexus/analyze.js +71 -6
- package/lib/gitnexus/analyze.js.map +1 -1
- package/lib/gitnexus/commands.d.ts +41 -8
- package/lib/gitnexus/commands.d.ts.map +1 -1
- package/lib/gitnexus/commands.js +62 -9
- 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 +61 -2
- package/lib/gitnexus/coverage.js.map +1 -1
- package/lib/gitnexus/git-activity.d.ts +85 -0
- package/lib/gitnexus/git-activity.d.ts.map +1 -1
- package/lib/gitnexus/git-activity.js +286 -1
- package/lib/gitnexus/git-activity.js.map +1 -1
- package/lib/gitnexus/index-meta.d.ts +15 -5
- package/lib/gitnexus/index-meta.d.ts.map +1 -1
- package/lib/gitnexus/index-meta.js +25 -5
- package/lib/gitnexus/index-meta.js.map +1 -1
- package/lib/gitnexus/languages.d.ts +7 -0
- package/lib/gitnexus/languages.d.ts.map +1 -1
- package/lib/gitnexus/languages.js +82 -2
- package/lib/gitnexus/languages.js.map +1 -1
- package/lib/gitnexus/root.d.ts +6 -0
- package/lib/gitnexus/root.d.ts.map +1 -1
- package/lib/gitnexus/root.js +6 -0
- package/lib/gitnexus/root.js.map +1 -1
- package/lib/gitnexus/scan.d.ts +3 -0
- package/lib/gitnexus/scan.d.ts.map +1 -1
- package/lib/gitnexus/scan.js +6 -3
- package/lib/gitnexus/scan.js.map +1 -1
- package/lib/gitnexus/search.d.ts +167 -0
- package/lib/gitnexus/search.d.ts.map +1 -0
- package/lib/gitnexus/search.js +517 -0
- package/lib/gitnexus/search.js.map +1 -0
- package/lib/index.d.ts +32 -13
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +68 -21
- package/lib/index.js.map +1 -1
- package/lib/routes/analyze.d.ts +8 -2
- package/lib/routes/analyze.d.ts.map +1 -1
- package/lib/routes/analyze.js +5 -1
- package/lib/routes/analyze.js.map +1 -1
- package/lib/routes/coverage.d.ts +15 -6
- package/lib/routes/coverage.d.ts.map +1 -1
- package/lib/routes/coverage.js +77 -12
- package/lib/routes/coverage.js.map +1 -1
- 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/search.d.ts +27 -0
- package/lib/routes/search.d.ts.map +1 -0
- package/lib/routes/search.js +77 -0
- package/lib/routes/search.js.map +1 -0
- package/package.json +3 -2
package/lib/index.js
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dsh-gitnexus-plus
|
|
2
|
+
* dsh-gitnexus-plus —host half.
|
|
3
3
|
*
|
|
4
4
|
* Registers one read-only tool and one loopback HTTP route over the coverage
|
|
5
|
-
* engine in `./gitnexus/`. Both answer the same question
|
|
6
|
-
* leave out?"
|
|
5
|
+
* engine in `./gitnexus/`. Both answer the same question —"what did this index
|
|
6
|
+
* leave out?" —for the two callers that need it: the model, and a browser half
|
|
7
7
|
* that will render it.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* The read path is still never allowed to change anything: a status check must not
|
|
10
|
+
* start a 30-second rebuild. The two mutating capabilities are separate routes with
|
|
11
|
+
* their own guards, and both go through the host's shell executor rather than
|
|
12
|
+
* spawning from the read path. Keyword search is a third read-only route over the
|
|
13
|
+
* graph itself; the tool above stays read-only.
|
|
13
14
|
*/
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
14
16
|
import Schema from '@deepseek-ai/schemastery';
|
|
15
17
|
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
16
18
|
import { analyzeCoverage } from './gitnexus/coverage.js';
|
|
17
19
|
import { formatReport } from './gitnexus/format.js';
|
|
18
|
-
import { maintenanceCommands,
|
|
20
|
+
import { commandRationale, defaultGitnexusHome, effectiveSkipFts, maintenanceCommands, } from './gitnexus/commands.js';
|
|
19
21
|
import { mountCoverageRoute } from './routes/coverage.js';
|
|
20
22
|
import { mountAnalyzeRoute } from './routes/analyze.js';
|
|
21
23
|
import { mountInstallRoute } from './routes/install.js';
|
|
24
|
+
import { mountSearchRoute } from './routes/search.js';
|
|
25
|
+
import { mountFileHistoryRoute } from './routes/file-history.js';
|
|
26
|
+
import { readFileActivity } from './gitnexus/git-activity.js';
|
|
27
|
+
import { searchWithFallback } from './gitnexus/search.js';
|
|
22
28
|
import { createAnalyzeRunner } from './gitnexus/analyze.js';
|
|
23
|
-
import { createInstallRunner } from './gitnexus/install.js';
|
|
29
|
+
import { createInstallRunner, defaultInstallPrefix } from './gitnexus/install.js';
|
|
24
30
|
/**
|
|
25
31
|
* Whether a service resolved from the context has the shape the runner needs.
|
|
26
32
|
*
|
|
27
|
-
* `ctx.get` is untyped here
|
|
33
|
+
* `ctx.get` is untyped here —the DSH packages ship no declarations, so the service
|
|
28
34
|
* arrives as `unknown`. Checking the two methods the runner actually calls is the
|
|
29
35
|
* narrowest claim that can be made: asserting the full `ctx.shell` contract from this
|
|
30
36
|
* side would be a guess, and a wrong guess fails at the first click rather than here.
|
|
@@ -38,7 +44,7 @@ function isShellLike(value) {
|
|
|
38
44
|
export const name = 'gitnexus-plus';
|
|
39
45
|
/**
|
|
40
46
|
* Only `tools` is required. `webServer` is reached through `ctx.inject` because a
|
|
41
|
-
* headless profile has no HTTP carrier at all
|
|
47
|
+
* headless profile has no HTTP carrier at all —naming it here would leave the
|
|
42
48
|
* plugin permanently pending there, and the tool would never register.
|
|
43
49
|
*/
|
|
44
50
|
export const inject = ['tools'];
|
|
@@ -46,7 +52,7 @@ export const Config = Schema.object({
|
|
|
46
52
|
scanDefaultCapKb: Schema.natural().default(512),
|
|
47
53
|
minifiedSampleLimit: Schema.natural().default(40),
|
|
48
54
|
serveRoutes: Schema.boolean().default(true),
|
|
49
|
-
skipFts: Schema.boolean().default(
|
|
55
|
+
skipFts: Schema.boolean().default(false),
|
|
50
56
|
memoryOff: Schema.boolean().default(true),
|
|
51
57
|
analyzeHeapMb: Schema.natural().default(8192),
|
|
52
58
|
analyzeTimeoutMs: Schema.natural().default(600000),
|
|
@@ -59,6 +65,21 @@ void configShapeMatches;
|
|
|
59
65
|
export function apply(ctx, config) {
|
|
60
66
|
const cache = new Map();
|
|
61
67
|
const CACHE_TTL_MS = 15_000;
|
|
68
|
+
/**
|
|
69
|
+
* The one install location, resolved once and shared by every path that needs to
|
|
70
|
+
* know it. This was the broken link in "install, then initialize": the installer
|
|
71
|
+
* wrote a plugin-owned tree under DSH_HOME, while the coverage engine and the
|
|
72
|
+
* analyze runner probed only PATH and the declared dependency. On a machine with
|
|
73
|
+
* no global GitNexus the install succeeded and then *nothing used it* — the panel
|
|
74
|
+
* still reported "absent" and the refresh still said "no CLI". Passing the same
|
|
75
|
+
* prefix to all three (reader, language detector, runner) is what makes the
|
|
76
|
+
* install a prerequisite rather than an isolated side effect.
|
|
77
|
+
*/
|
|
78
|
+
const installPrefix = config.gitnexusInstallDir === '' ? defaultInstallPrefix() : config.gitnexusInstallDir;
|
|
79
|
+
const managedToolchain = { managedPrefix: installPrefix };
|
|
80
|
+
// Resolved at boot so a search never depends on the host's working directory. The
|
|
81
|
+
// file is run by the system Node (see `searchViaHelper`); this process only names it.
|
|
82
|
+
const searchHelperPath = fileURLToPath(new URL('./bin/search-helper.js', import.meta.url));
|
|
62
83
|
/**
|
|
63
84
|
* Resolve a coverage report, from cache when it is recent enough.
|
|
64
85
|
*
|
|
@@ -68,7 +89,7 @@ export function apply(ctx, config) {
|
|
|
68
89
|
*
|
|
69
90
|
* `fresh` bypasses the TTL. A manual refresh is an explicit instruction from a
|
|
70
91
|
* person who believes the numbers may have moved, and answering it with a cached
|
|
71
|
-
* copy makes the control look broken
|
|
92
|
+
* copy makes the control look broken —which is exactly how it was reported. A
|
|
72
93
|
* background poll is the case the TTL exists for; a click is not.
|
|
73
94
|
*/
|
|
74
95
|
const coverageFor = async (repoPath, options = {}) => {
|
|
@@ -80,6 +101,8 @@ export function apply(ctx, config) {
|
|
|
80
101
|
}
|
|
81
102
|
const report = await analyzeCoverage(key, {
|
|
82
103
|
minifiedSampleLimit: config.minifiedSampleLimit,
|
|
104
|
+
toolchain: managedToolchain,
|
|
105
|
+
onProgress: options.onProgress,
|
|
83
106
|
});
|
|
84
107
|
cache.set(key, { at: Date.now(), report });
|
|
85
108
|
return report;
|
|
@@ -91,13 +114,18 @@ export function apply(ctx, config) {
|
|
|
91
114
|
*/
|
|
92
115
|
const maintenanceFor = (repoPath) => {
|
|
93
116
|
const options = {
|
|
94
|
-
skipFts:
|
|
117
|
+
// `skipFts: false` means automatic, not "attempt FTS": if the index has no FTS,
|
|
118
|
+
// attempting the install dies with `spawn EPERM` in a confined host.
|
|
119
|
+
skipFts: effectiveSkipFts(repoPath, config.skipFts),
|
|
95
120
|
memoryOff: config.memoryOff,
|
|
96
|
-
|
|
121
|
+
// Default to a plugin-owned home inside the project so the global registry
|
|
122
|
+
// write stays within the workspace. The explicit config still wins.
|
|
123
|
+
gitnexusHome: config.gitnexusHome === '' ? defaultGitnexusHome(repoPath) : config.gitnexusHome,
|
|
97
124
|
};
|
|
98
125
|
return {
|
|
99
126
|
commands: maintenanceCommands(repoPath, options),
|
|
100
127
|
rationale: commandRationale(options),
|
|
128
|
+
supportsForce: true,
|
|
101
129
|
};
|
|
102
130
|
};
|
|
103
131
|
ctx.tools.register(defineTool({
|
|
@@ -124,7 +152,7 @@ export function apply(ctx, config) {
|
|
|
124
152
|
additionalProperties: true,
|
|
125
153
|
properties: {
|
|
126
154
|
// `required: true` per property, never `required: [...]`. The DSL's
|
|
127
|
-
// compiler rejects the array form outright
|
|
155
|
+
// compiler rejects the array form outright —it collects these marks
|
|
128
156
|
// into the JSON Schema `required` list itself.
|
|
129
157
|
text: { type: 'string', required: true },
|
|
130
158
|
indexed: { type: 'boolean', required: true },
|
|
@@ -157,12 +185,20 @@ export function apply(ctx, config) {
|
|
|
157
185
|
// Read through `ctx.get` rather than injecting, because `shell` is optional here
|
|
158
186
|
// and `inject` would make the whole route block wait for a service a headless
|
|
159
187
|
// deployment never provides. `null` is handed to the runner, which reports
|
|
160
|
-
// `unavailable` and tells the operator to run the command themselves
|
|
188
|
+
// `unavailable` and tells the operator to run the command themselves —the
|
|
161
189
|
// read-only half of the panel keeps working either way.
|
|
162
190
|
const shellRaw = svcCtx.get('shell');
|
|
191
|
+
const searchShell = isShellLike(shellRaw) ? shellRaw : null;
|
|
163
192
|
const analyze = createAnalyzeRunner({
|
|
164
|
-
shell:
|
|
193
|
+
shell: searchShell,
|
|
165
194
|
timeoutMs: config.analyzeTimeoutMs,
|
|
195
|
+
toolchain: managedToolchain,
|
|
196
|
+
// The runner must read the same config as the command text it confirms,
|
|
197
|
+
// otherwise the dialog describes a command the run does not execute. It
|
|
198
|
+
// resolves `false` per repository (automatic), and defaults to the
|
|
199
|
+
// project-local `GITNEXUS_HOME` when the config leaves it empty.
|
|
200
|
+
skipFts: config.skipFts,
|
|
201
|
+
gitnexusHome: config.gitnexusHome === '' ? null : config.gitnexusHome,
|
|
166
202
|
});
|
|
167
203
|
// GitNexus is what produces the index this plugin reads, so a machine without it
|
|
168
204
|
// has nothing to display and no way to change that from here. This runner is the
|
|
@@ -170,7 +206,7 @@ export function apply(ctx, config) {
|
|
|
170
206
|
// out a package manager, a registry, or a global prefix themselves.
|
|
171
207
|
const install = createInstallRunner({
|
|
172
208
|
shell: isShellLike(shellRaw) ? shellRaw : null,
|
|
173
|
-
prefix:
|
|
209
|
+
prefix: installPrefix,
|
|
174
210
|
timeoutMs: config.installTimeoutMs,
|
|
175
211
|
});
|
|
176
212
|
const disposers = [
|
|
@@ -178,8 +214,11 @@ export function apply(ctx, config) {
|
|
|
178
214
|
get: (repoPath, options) => coverageFor(repoPath, options),
|
|
179
215
|
maintenance: (repoPath) => maintenanceFor(repoPath),
|
|
180
216
|
}),
|
|
217
|
+
mountFileHistoryRoute(svcCtx.webServer, {
|
|
218
|
+
read: (repoPath, filePath, options) => readFileActivity(repoPath, filePath, options),
|
|
219
|
+
}),
|
|
181
220
|
mountAnalyzeRoute(svcCtx.webServer, {
|
|
182
|
-
start: (repoPath) => analyze.start(repoPath),
|
|
221
|
+
start: (repoPath, options) => analyze.start(repoPath, options),
|
|
183
222
|
status: (repoPath) => analyze.status(repoPath),
|
|
184
223
|
cancel: (repoPath) => analyze.cancel(repoPath),
|
|
185
224
|
}),
|
|
@@ -189,6 +228,14 @@ export function apply(ctx, config) {
|
|
|
189
228
|
cancel: () => install.cancel(),
|
|
190
229
|
cliPath: () => install.cliPath(),
|
|
191
230
|
}),
|
|
231
|
+
mountSearchRoute(svcCtx.webServer, {
|
|
232
|
+
search: (repoPath, query, options) => searchWithFallback(repoPath, query, {
|
|
233
|
+
shell: searchShell,
|
|
234
|
+
helperPath: searchHelperPath,
|
|
235
|
+
limit: options?.limit,
|
|
236
|
+
managedPrefix: installPrefix,
|
|
237
|
+
}),
|
|
238
|
+
}),
|
|
192
239
|
];
|
|
193
240
|
ctx.effect(() => () => {
|
|
194
241
|
for (const dispose of disposers)
|
|
@@ -203,7 +250,7 @@ export function apply(ctx, config) {
|
|
|
203
250
|
}
|
|
204
251
|
}
|
|
205
252
|
/**
|
|
206
|
-
* Human-readable rendering lives in `./gitnexus/format.js`
|
|
253
|
+
* Human-readable rendering lives in `./gitnexus/format.js` —free of DSH imports
|
|
207
254
|
* so it can be tested without a host. Re-exported here for callers that already
|
|
208
255
|
* hold the plugin module.
|
|
209
256
|
*/
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/routes/analyze.d.ts
CHANGED
|
@@ -23,8 +23,14 @@
|
|
|
23
23
|
import type { WebServerService } from '@deepseek-ai/cordis';
|
|
24
24
|
import type { AnalyzeStatus } from '../gitnexus/analyze.js';
|
|
25
25
|
export interface AnalyzeRouteDeps {
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Begin a run, or return the one already in flight for this repository.
|
|
28
|
+
* `force` selects the destructive full rebuild; it is passed through, never
|
|
29
|
+
* inferred from the method or the route.
|
|
30
|
+
*/
|
|
31
|
+
start: (repoPath: string, options?: {
|
|
32
|
+
force?: boolean;
|
|
33
|
+
}) => AnalyzeStatus;
|
|
28
34
|
status: (repoPath: string) => AnalyzeStatus | null;
|
|
29
35
|
cancel: (repoPath: string) => boolean;
|
|
30
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/routes/analyze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAQ5D,MAAM,WAAW,gBAAgB;IAC/B
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/routes/analyze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAQ5D,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,aAAa,CAAC;IAC1E,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,GAAG,IAAI,CAAC;IACnD,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;CACvC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,GAAG,MAAM,IAAI,CA2CjG"}
|
package/lib/routes/analyze.js
CHANGED
|
@@ -49,7 +49,11 @@ export function mountAnalyzeRoute(webServer, deps) {
|
|
|
49
49
|
// desktop shell's own fetch.
|
|
50
50
|
if (!passWriteGuard(req, res))
|
|
51
51
|
return;
|
|
52
|
-
|
|
52
|
+
// `force=1` is the full rebuild. It is an explicit query flag rather than a
|
|
53
|
+
// body field because the panel's only other POST parameter is the repo, and a
|
|
54
|
+
// flag in the URL is visible in the run's own command and in a log.
|
|
55
|
+
const force = url.searchParams.get('force') === '1';
|
|
56
|
+
sendJson(res, 200, { ok: true, run: deps.start(absRepo, { force }) });
|
|
53
57
|
return;
|
|
54
58
|
}
|
|
55
59
|
if (req.method === 'DELETE') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/routes/analyze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3F;;;GAGG;AACH,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/routes/analyze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3F;;;GAGG;AACH,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAaxF;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAA2B,EAAE,IAAsB;IACnF,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9C,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,CAAC;YAAE,OAAO;QAElD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC,CAAC;YACrG,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;YAAE,OAAO;QAEjC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,6EAA6E;YAC7E,+EAA+E;YAC/E,6BAA6B;YAC7B,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC;gBAAE,OAAO;YACtC,4EAA4E;YAC5E,8EAA8E;YAC9E,oEAAoE;YACpE,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC;YACpD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC;gBAAE,OAAO;YACtC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACvC,8EAA8E;YAC9E,uDAAuD;YACvD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACvE,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,kFAAkF;QAClF,yCAAyC;QACzC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,CAAC,CAAC;AACxF,CAAC"}
|
package/lib/routes/coverage.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* carrier contract in `@deepseek-ai/dsh-host-webserver`: bare `node:http`, no
|
|
6
6
|
* Express, exact-then-longest-prefix matching, and a disposer for teardown.
|
|
7
7
|
*
|
|
8
|
-
* THE BOUND IS "IS A
|
|
9
|
-
*
|
|
8
|
+
* THE BOUND IS "IS A PROJECT ROOT", NOT "IS IN THE REGISTRY"
|
|
9
|
+
* ----------------------------------------------------------
|
|
10
10
|
* An earlier revision accepted only paths present in `~/.gitnexus/registry.json`.
|
|
11
11
|
* That was wrong for the panel's actual job: it shows the project the user is
|
|
12
12
|
* *in*, and a working directory the global registry has never heard of — a fresh
|
|
@@ -14,12 +14,20 @@
|
|
|
14
14
|
* panel exists to report on. Refusing it would have been a correctness bug wearing
|
|
15
15
|
* a security costume.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* A later revision required an index. That was also wrong, for the same reason at a
|
|
18
|
+
* different state: a project with no index yet still has a readable working tree,
|
|
19
|
+
* and the engine already builds a useful scan-only report for it. The bound is now a
|
|
20
|
+
* project root (`.gitnexus` or `.git`), which still refuses arbitrary directories.
|
|
21
|
+
*
|
|
22
|
+
* The route still refuses to describe arbitrary directories: the path must be a
|
|
23
|
+
* project root — carrying `.gitnexus/gitnexus.json`, `.gitnexus/meta.json`, or a
|
|
24
|
+
* `.git` marker — so a caller cannot use it to enumerate a filesystem. An index is
|
|
25
|
+
* no longer required: the engine's scan-only report is what makes the "no index
|
|
26
|
+
* yet" state informative instead of an empty command. Loopback and method guards
|
|
27
|
+
* live in `./guard.js`.
|
|
20
28
|
*/
|
|
21
29
|
import type { WebServerService } from '@deepseek-ai/cordis';
|
|
22
|
-
import type { CoverageReport } from '../gitnexus/coverage.js';
|
|
30
|
+
import type { CoverageProgress, CoverageReport } from '../gitnexus/coverage.js';
|
|
23
31
|
import type { MaintenanceInfo } from '../index.js';
|
|
24
32
|
/**
|
|
25
33
|
* What the route needs from the host half.
|
|
@@ -34,6 +42,7 @@ export interface CoverageRouteDeps {
|
|
|
34
42
|
*/
|
|
35
43
|
get: (repoPath: string, options?: {
|
|
36
44
|
fresh?: boolean;
|
|
45
|
+
onProgress?: (progress: CoverageProgress) => void;
|
|
37
46
|
}) => Promise<CoverageReport>;
|
|
38
47
|
maintenance?: (repoPath: string) => MaintenanceInfo;
|
|
39
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/routes/coverage.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/routes/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,GAAG,EAAE,CACH,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAA;KAAE,KAC7E,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,eAAe,CAAC;CACrD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAmGnG"}
|
package/lib/routes/coverage.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* carrier contract in `@deepseek-ai/dsh-host-webserver`: bare `node:http`, no
|
|
6
6
|
* Express, exact-then-longest-prefix matching, and a disposer for teardown.
|
|
7
7
|
*
|
|
8
|
-
* THE BOUND IS "IS A
|
|
9
|
-
*
|
|
8
|
+
* THE BOUND IS "IS A PROJECT ROOT", NOT "IS IN THE REGISTRY"
|
|
9
|
+
* ----------------------------------------------------------
|
|
10
10
|
* An earlier revision accepted only paths present in `~/.gitnexus/registry.json`.
|
|
11
11
|
* That was wrong for the panel's actual job: it shows the project the user is
|
|
12
12
|
* *in*, and a working directory the global registry has never heard of — a fresh
|
|
@@ -14,12 +14,20 @@
|
|
|
14
14
|
* panel exists to report on. Refusing it would have been a correctness bug wearing
|
|
15
15
|
* a security costume.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* A later revision required an index. That was also wrong, for the same reason at a
|
|
18
|
+
* different state: a project with no index yet still has a readable working tree,
|
|
19
|
+
* and the engine already builds a useful scan-only report for it. The bound is now a
|
|
20
|
+
* project root (`.gitnexus` or `.git`), which still refuses arbitrary directories.
|
|
21
|
+
*
|
|
22
|
+
* The route still refuses to describe arbitrary directories: the path must be a
|
|
23
|
+
* project root — carrying `.gitnexus/gitnexus.json`, `.gitnexus/meta.json`, or a
|
|
24
|
+
* `.git` marker — so a caller cannot use it to enumerate a filesystem. An index is
|
|
25
|
+
* no longer required: the engine's scan-only report is what makes the "no index
|
|
26
|
+
* yet" state informative instead of an empty command. Loopback and method guards
|
|
27
|
+
* live in `./guard.js`.
|
|
20
28
|
*/
|
|
21
29
|
import path from 'node:path';
|
|
22
|
-
import {
|
|
30
|
+
import { isProjectRoot } from '../gitnexus/index-meta.js';
|
|
23
31
|
import { guardHandler, passGuard, answerHead, sendJson } from './guard.js';
|
|
24
32
|
/**
|
|
25
33
|
* @returns disposer that unregisters the route
|
|
@@ -39,13 +47,18 @@ export function mountCoverageRoute(webServer, deps) {
|
|
|
39
47
|
return;
|
|
40
48
|
}
|
|
41
49
|
const absRepo = path.resolve(repo);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
// The bound changed from "is a GitNexus index" to "is a project root": a
|
|
51
|
+
// directory with neither an index nor a `.git` marker is still refused, so the
|
|
52
|
+
// route cannot be used to enumerate a filesystem. A git repository without an
|
|
53
|
+
// index is the state the panel's initialize action exists for, and the engine
|
|
54
|
+
// already produces a useful scan-only report for it (file counts, bytes,
|
|
55
|
+
// languages, the size cap). Refusing that state was hiding data, not protecting
|
|
56
|
+
// anything — the route only answers loopback callers.
|
|
57
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
45
58
|
sendJson(res, 404, {
|
|
46
59
|
ok: false,
|
|
47
|
-
code: 'not-
|
|
48
|
-
message: 'directory
|
|
60
|
+
code: 'not-a-project',
|
|
61
|
+
message: 'directory is neither a GitNexus index nor a git repository root',
|
|
49
62
|
});
|
|
50
63
|
return;
|
|
51
64
|
}
|
|
@@ -54,10 +67,62 @@ export function mountCoverageRoute(webServer, deps) {
|
|
|
54
67
|
// `refresh=1` comes from the panel's manual refresh control. A background poll
|
|
55
68
|
// omits it and gets the cached copy, which is what the TTL is for.
|
|
56
69
|
const fresh = url.searchParams.get('refresh') === '1';
|
|
57
|
-
const report = await deps.get(absRepo, { fresh });
|
|
58
70
|
// The maintenance commands ride along with the report because they are
|
|
59
71
|
// config-derived and only meaningful next to the index they would rebuild.
|
|
60
72
|
const maintenance = typeof deps.maintenance === 'function' ? deps.maintenance(absRepo) : null;
|
|
73
|
+
// `stream=1` is the panel's numeric-progress channel. NDJSON rather than SSE:
|
|
74
|
+
// one JSON object per line needs no event naming and falls back to plain JSON
|
|
75
|
+
// for any caller that does not ask for it.
|
|
76
|
+
if (url.searchParams.get('stream') === '1') {
|
|
77
|
+
const write = (payload) => {
|
|
78
|
+
if (res.writableEnded)
|
|
79
|
+
return;
|
|
80
|
+
try {
|
|
81
|
+
res.write(`${JSON.stringify(payload)}\n`);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// The reader disconnected; the rest of the work is already in flight.
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
res.statusCode = 200;
|
|
88
|
+
res.setHeader('content-type', 'application/x-ndjson; charset=utf-8');
|
|
89
|
+
res.setHeader('cache-control', 'no-store');
|
|
90
|
+
res.setHeader('x-content-type-options', 'nosniff');
|
|
91
|
+
res.setHeader('referrer-policy', 'no-referrer');
|
|
92
|
+
res.setHeader('x-accel-buffering', 'no');
|
|
93
|
+
res.flushHeaders();
|
|
94
|
+
try {
|
|
95
|
+
const report = await deps.get(absRepo, {
|
|
96
|
+
fresh,
|
|
97
|
+
onProgress: (progress) => write({ type: 'progress', ...progress }),
|
|
98
|
+
});
|
|
99
|
+
// The engine ends at 99%; the final boundary is the route having the whole
|
|
100
|
+
// report in hand, so 100 is emitted here rather than invented earlier.
|
|
101
|
+
write({
|
|
102
|
+
type: 'progress',
|
|
103
|
+
phase: 'assemble',
|
|
104
|
+
percent: 100,
|
|
105
|
+
label: '报告已读取',
|
|
106
|
+
});
|
|
107
|
+
write({
|
|
108
|
+
type: 'report',
|
|
109
|
+
report,
|
|
110
|
+
maintenance,
|
|
111
|
+
readAt: new Date().toISOString(),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
write({
|
|
116
|
+
type: 'error',
|
|
117
|
+
status: 500,
|
|
118
|
+
code: 'internal-error',
|
|
119
|
+
message: error instanceof Error ? error.message : String(error),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
res.end();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const report = await deps.get(absRepo, { fresh });
|
|
61
126
|
// `readAt` is what makes a refresh visible: without it two reads of an unchanged
|
|
62
127
|
// repository are byte-identical on screen, so the control looks inert even when
|
|
63
128
|
// it did exactly what it was asked.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/routes/coverage.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/routes/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/file-history?repo=<project>&path=<file>&days=7`
|
|
3
|
+
*
|
|
4
|
+
* The file timeline is read on demand. It is deliberately a separate route from
|
|
5
|
+
* coverage: a report already crosses every file in the activity window, while
|
|
6
|
+
* "show me this one file's commits" is a single bounded `git log --follow`.
|
|
7
|
+
*
|
|
8
|
+
* Read-only like coverage/search. The path is resolved inside the project root, and
|
|
9
|
+
* the engine clamps `days` to 1–30, so a hand-written URL cannot walk the filesystem
|
|
10
|
+
* or request an unbounded history.
|
|
11
|
+
*/
|
|
12
|
+
import type { WebServerService } from '@deepseek-ai/cordis';
|
|
13
|
+
import type { FileHistory } from '../gitnexus/git-activity.js';
|
|
14
|
+
export interface FileHistoryRouteDeps {
|
|
15
|
+
read: (repoPath: string, filePath: string, options?: {
|
|
16
|
+
days?: number;
|
|
17
|
+
}) => Promise<FileHistory>;
|
|
18
|
+
}
|
|
19
|
+
/** @returns disposer that unregisters the route */
|
|
20
|
+
export declare function mountFileHistoryRoute(webServer: WebServerService, deps: FileHistoryRouteDeps): () => void;
|
|
21
|
+
//# sourceMappingURL=file-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-history.d.ts","sourceRoot":"","sources":["../../src/routes/file-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE/D,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,CACJ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KACxB,OAAO,CAAC,WAAW,CAAC,CAAC;CAC3B;AAED,mDAAmD;AACnD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,gBAAgB,EAC3B,IAAI,EAAE,oBAAoB,GACzB,MAAM,IAAI,CAyDZ"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/file-history?repo=<project>&path=<file>&days=7`
|
|
3
|
+
*
|
|
4
|
+
* The file timeline is read on demand. It is deliberately a separate route from
|
|
5
|
+
* coverage: a report already crosses every file in the activity window, while
|
|
6
|
+
* "show me this one file's commits" is a single bounded `git log --follow`.
|
|
7
|
+
*
|
|
8
|
+
* Read-only like coverage/search. The path is resolved inside the project root, and
|
|
9
|
+
* the engine clamps `days` to 1–30, so a hand-written URL cannot walk the filesystem
|
|
10
|
+
* or request an unbounded history.
|
|
11
|
+
*/
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { isProjectRoot } from '../gitnexus/index-meta.js';
|
|
14
|
+
import { guardHandler, passGuard, answerHead, sendJson } from './guard.js';
|
|
15
|
+
/** @returns disposer that unregisters the route */
|
|
16
|
+
export function mountFileHistoryRoute(webServer, deps) {
|
|
17
|
+
const handler = guardHandler(async (req, res) => {
|
|
18
|
+
if (!passGuard(req, res))
|
|
19
|
+
return;
|
|
20
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
21
|
+
const repo = url.searchParams.get('repo');
|
|
22
|
+
const file = url.searchParams.get('path');
|
|
23
|
+
if (repo === null || repo.trim() === '' || file === null || file.trim() === '') {
|
|
24
|
+
sendJson(res, 400, {
|
|
25
|
+
ok: false,
|
|
26
|
+
code: 'missing-params',
|
|
27
|
+
message: 'repo and path query parameters are required',
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const absRepo = path.resolve(repo);
|
|
32
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
33
|
+
sendJson(res, 404, {
|
|
34
|
+
ok: false,
|
|
35
|
+
code: 'not-a-project',
|
|
36
|
+
message: 'directory is neither a GitNexus index nor a git repository root',
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const relative = file.trim();
|
|
41
|
+
const prefix = absRepo.endsWith(path.sep) ? absRepo : `${absRepo}${path.sep}`;
|
|
42
|
+
const absolute = path.resolve(absRepo, relative);
|
|
43
|
+
// Windows paths compare case-insensitively; normalising both sides avoids a
|
|
44
|
+
// false "outside project" for a path the caller spelled with another drive case.
|
|
45
|
+
const inside = process.platform === 'win32'
|
|
46
|
+
? absolute.toLowerCase().startsWith(prefix.toLowerCase())
|
|
47
|
+
: absolute.startsWith(prefix);
|
|
48
|
+
if (!inside) {
|
|
49
|
+
sendJson(res, 400, {
|
|
50
|
+
ok: false,
|
|
51
|
+
code: 'invalid-path',
|
|
52
|
+
message: 'path must resolve inside the project root',
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (answerHead(req, res))
|
|
57
|
+
return;
|
|
58
|
+
const parsedDays = Number.parseInt(url.searchParams.get('days') ?? '7', 10);
|
|
59
|
+
const days = Number.isFinite(parsedDays) ? Math.max(1, Math.min(30, parsedDays)) : 7;
|
|
60
|
+
const history = await deps.read(absRepo, relative, { days });
|
|
61
|
+
sendJson(res, 200, {
|
|
62
|
+
ok: true,
|
|
63
|
+
...history,
|
|
64
|
+
readAt: new Date().toISOString(),
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
return webServer.register({ kind: 'prefix', path: '/api/gitnexus/file-history', handler });
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=file-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-history.js","sourceRoot":"","sources":["../../src/routes/file-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/gitnexus/search?repo=<project>&q=<keyword>` — keyword search.
|
|
3
|
+
*
|
|
4
|
+
* The fourth route, and the first that is neither a reading of the index manifest
|
|
5
|
+
* nor a maintenance action: it queries the graph's symbol names and file paths.
|
|
6
|
+
* It is read-only in the strongest sense this plugin can offer — the engine opens
|
|
7
|
+
* LadybugDB with `readOnly: true` and takes no write lock — so the method policy is
|
|
8
|
+
* the read-only one (GET/HEAD), not the analyze route's wider set.
|
|
9
|
+
*
|
|
10
|
+
* The bound is the same project-root check the coverage route uses: a directory
|
|
11
|
+
* that is neither indexed nor a `.git` root is refused, so the route cannot be used
|
|
12
|
+
* to enumerate a filesystem. Search itself additionally requires a complete index
|
|
13
|
+
* store and returns a typed error when the graph is missing.
|
|
14
|
+
*/
|
|
15
|
+
import type { WebServerService } from '@deepseek-ai/cordis';
|
|
16
|
+
import { type SearchReport } from '../gitnexus/search.js';
|
|
17
|
+
export interface SearchRouteDeps {
|
|
18
|
+
/** Run one keyword search. Errors are `SearchError` instances when typed. */
|
|
19
|
+
search: (repoPath: string, query: string, options?: {
|
|
20
|
+
limit?: number;
|
|
21
|
+
}) => Promise<SearchReport>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @returns disposer that unregisters the route
|
|
25
|
+
*/
|
|
26
|
+
export declare function mountSearchRoute(webServer: WebServerService, deps: SearchRouteDeps): () => void;
|
|
27
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/routes/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAIvE,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CAClG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,eAAe,GAAG,MAAM,IAAI,CAwD/F"}
|