dsh-gitnexus-plus 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -49
- 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 +576 -87
- package/lib/gitnexus/analyze.d.ts +27 -2
- package/lib/gitnexus/analyze.d.ts.map +1 -1
- package/lib/gitnexus/analyze.js +31 -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.map +1 -1
- package/lib/gitnexus/coverage.js +3 -1
- package/lib/gitnexus/coverage.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 +1 -0
- package/lib/gitnexus/scan.d.ts.map +1 -1
- package/lib/gitnexus/scan.js +3 -1
- 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 +62 -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 +13 -5
- package/lib/routes/coverage.d.ts.map +1 -1
- package/lib/routes/coverage.js +24 -11
- package/lib/routes/coverage.js.map +1 -1
- 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 +2 -2
package/lib/index.js
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
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 { searchWithFallback } from './gitnexus/search.js';
|
|
22
26
|
import { createAnalyzeRunner } from './gitnexus/analyze.js';
|
|
23
|
-
import { createInstallRunner } from './gitnexus/install.js';
|
|
27
|
+
import { createInstallRunner, defaultInstallPrefix } from './gitnexus/install.js';
|
|
24
28
|
/**
|
|
25
29
|
* Whether a service resolved from the context has the shape the runner needs.
|
|
26
30
|
*
|
|
27
|
-
* `ctx.get` is untyped here
|
|
31
|
+
* `ctx.get` is untyped here —the DSH packages ship no declarations, so the service
|
|
28
32
|
* arrives as `unknown`. Checking the two methods the runner actually calls is the
|
|
29
33
|
* narrowest claim that can be made: asserting the full `ctx.shell` contract from this
|
|
30
34
|
* side would be a guess, and a wrong guess fails at the first click rather than here.
|
|
@@ -38,7 +42,7 @@ function isShellLike(value) {
|
|
|
38
42
|
export const name = 'gitnexus-plus';
|
|
39
43
|
/**
|
|
40
44
|
* Only `tools` is required. `webServer` is reached through `ctx.inject` because a
|
|
41
|
-
* headless profile has no HTTP carrier at all
|
|
45
|
+
* headless profile has no HTTP carrier at all —naming it here would leave the
|
|
42
46
|
* plugin permanently pending there, and the tool would never register.
|
|
43
47
|
*/
|
|
44
48
|
export const inject = ['tools'];
|
|
@@ -46,7 +50,7 @@ export const Config = Schema.object({
|
|
|
46
50
|
scanDefaultCapKb: Schema.natural().default(512),
|
|
47
51
|
minifiedSampleLimit: Schema.natural().default(40),
|
|
48
52
|
serveRoutes: Schema.boolean().default(true),
|
|
49
|
-
skipFts: Schema.boolean().default(
|
|
53
|
+
skipFts: Schema.boolean().default(false),
|
|
50
54
|
memoryOff: Schema.boolean().default(true),
|
|
51
55
|
analyzeHeapMb: Schema.natural().default(8192),
|
|
52
56
|
analyzeTimeoutMs: Schema.natural().default(600000),
|
|
@@ -59,6 +63,21 @@ void configShapeMatches;
|
|
|
59
63
|
export function apply(ctx, config) {
|
|
60
64
|
const cache = new Map();
|
|
61
65
|
const CACHE_TTL_MS = 15_000;
|
|
66
|
+
/**
|
|
67
|
+
* The one install location, resolved once and shared by every path that needs to
|
|
68
|
+
* know it. This was the broken link in "install, then initialize": the installer
|
|
69
|
+
* wrote a plugin-owned tree under DSH_HOME, while the coverage engine and the
|
|
70
|
+
* analyze runner probed only PATH and the declared dependency. On a machine with
|
|
71
|
+
* no global GitNexus the install succeeded and then *nothing used it* — the panel
|
|
72
|
+
* still reported "absent" and the refresh still said "no CLI". Passing the same
|
|
73
|
+
* prefix to all three (reader, language detector, runner) is what makes the
|
|
74
|
+
* install a prerequisite rather than an isolated side effect.
|
|
75
|
+
*/
|
|
76
|
+
const installPrefix = config.gitnexusInstallDir === '' ? defaultInstallPrefix() : config.gitnexusInstallDir;
|
|
77
|
+
const managedToolchain = { managedPrefix: installPrefix };
|
|
78
|
+
// Resolved at boot so a search never depends on the host's working directory. The
|
|
79
|
+
// file is run by the system Node (see `searchViaHelper`); this process only names it.
|
|
80
|
+
const searchHelperPath = fileURLToPath(new URL('./bin/search-helper.js', import.meta.url));
|
|
62
81
|
/**
|
|
63
82
|
* Resolve a coverage report, from cache when it is recent enough.
|
|
64
83
|
*
|
|
@@ -68,7 +87,7 @@ export function apply(ctx, config) {
|
|
|
68
87
|
*
|
|
69
88
|
* `fresh` bypasses the TTL. A manual refresh is an explicit instruction from a
|
|
70
89
|
* person who believes the numbers may have moved, and answering it with a cached
|
|
71
|
-
* copy makes the control look broken
|
|
90
|
+
* copy makes the control look broken —which is exactly how it was reported. A
|
|
72
91
|
* background poll is the case the TTL exists for; a click is not.
|
|
73
92
|
*/
|
|
74
93
|
const coverageFor = async (repoPath, options = {}) => {
|
|
@@ -80,6 +99,7 @@ export function apply(ctx, config) {
|
|
|
80
99
|
}
|
|
81
100
|
const report = await analyzeCoverage(key, {
|
|
82
101
|
minifiedSampleLimit: config.minifiedSampleLimit,
|
|
102
|
+
toolchain: managedToolchain,
|
|
83
103
|
});
|
|
84
104
|
cache.set(key, { at: Date.now(), report });
|
|
85
105
|
return report;
|
|
@@ -91,13 +111,18 @@ export function apply(ctx, config) {
|
|
|
91
111
|
*/
|
|
92
112
|
const maintenanceFor = (repoPath) => {
|
|
93
113
|
const options = {
|
|
94
|
-
skipFts:
|
|
114
|
+
// `skipFts: false` means automatic, not "attempt FTS": if the index has no FTS,
|
|
115
|
+
// attempting the install dies with `spawn EPERM` in a confined host.
|
|
116
|
+
skipFts: effectiveSkipFts(repoPath, config.skipFts),
|
|
95
117
|
memoryOff: config.memoryOff,
|
|
96
|
-
|
|
118
|
+
// Default to a plugin-owned home inside the project so the global registry
|
|
119
|
+
// write stays within the workspace. The explicit config still wins.
|
|
120
|
+
gitnexusHome: config.gitnexusHome === '' ? defaultGitnexusHome(repoPath) : config.gitnexusHome,
|
|
97
121
|
};
|
|
98
122
|
return {
|
|
99
123
|
commands: maintenanceCommands(repoPath, options),
|
|
100
124
|
rationale: commandRationale(options),
|
|
125
|
+
supportsForce: true,
|
|
101
126
|
};
|
|
102
127
|
};
|
|
103
128
|
ctx.tools.register(defineTool({
|
|
@@ -124,7 +149,7 @@ export function apply(ctx, config) {
|
|
|
124
149
|
additionalProperties: true,
|
|
125
150
|
properties: {
|
|
126
151
|
// `required: true` per property, never `required: [...]`. The DSL's
|
|
127
|
-
// compiler rejects the array form outright
|
|
152
|
+
// compiler rejects the array form outright —it collects these marks
|
|
128
153
|
// into the JSON Schema `required` list itself.
|
|
129
154
|
text: { type: 'string', required: true },
|
|
130
155
|
indexed: { type: 'boolean', required: true },
|
|
@@ -157,12 +182,20 @@ export function apply(ctx, config) {
|
|
|
157
182
|
// Read through `ctx.get` rather than injecting, because `shell` is optional here
|
|
158
183
|
// and `inject` would make the whole route block wait for a service a headless
|
|
159
184
|
// deployment never provides. `null` is handed to the runner, which reports
|
|
160
|
-
// `unavailable` and tells the operator to run the command themselves
|
|
185
|
+
// `unavailable` and tells the operator to run the command themselves —the
|
|
161
186
|
// read-only half of the panel keeps working either way.
|
|
162
187
|
const shellRaw = svcCtx.get('shell');
|
|
188
|
+
const searchShell = isShellLike(shellRaw) ? shellRaw : null;
|
|
163
189
|
const analyze = createAnalyzeRunner({
|
|
164
|
-
shell:
|
|
190
|
+
shell: searchShell,
|
|
165
191
|
timeoutMs: config.analyzeTimeoutMs,
|
|
192
|
+
toolchain: managedToolchain,
|
|
193
|
+
// The runner must read the same config as the command text it confirms,
|
|
194
|
+
// otherwise the dialog describes a command the run does not execute. It
|
|
195
|
+
// resolves `false` per repository (automatic), and defaults to the
|
|
196
|
+
// project-local `GITNEXUS_HOME` when the config leaves it empty.
|
|
197
|
+
skipFts: config.skipFts,
|
|
198
|
+
gitnexusHome: config.gitnexusHome === '' ? null : config.gitnexusHome,
|
|
166
199
|
});
|
|
167
200
|
// GitNexus is what produces the index this plugin reads, so a machine without it
|
|
168
201
|
// has nothing to display and no way to change that from here. This runner is the
|
|
@@ -170,7 +203,7 @@ export function apply(ctx, config) {
|
|
|
170
203
|
// out a package manager, a registry, or a global prefix themselves.
|
|
171
204
|
const install = createInstallRunner({
|
|
172
205
|
shell: isShellLike(shellRaw) ? shellRaw : null,
|
|
173
|
-
prefix:
|
|
206
|
+
prefix: installPrefix,
|
|
174
207
|
timeoutMs: config.installTimeoutMs,
|
|
175
208
|
});
|
|
176
209
|
const disposers = [
|
|
@@ -179,7 +212,7 @@ export function apply(ctx, config) {
|
|
|
179
212
|
maintenance: (repoPath) => maintenanceFor(repoPath),
|
|
180
213
|
}),
|
|
181
214
|
mountAnalyzeRoute(svcCtx.webServer, {
|
|
182
|
-
start: (repoPath) => analyze.start(repoPath),
|
|
215
|
+
start: (repoPath, options) => analyze.start(repoPath, options),
|
|
183
216
|
status: (repoPath) => analyze.status(repoPath),
|
|
184
217
|
cancel: (repoPath) => analyze.cancel(repoPath),
|
|
185
218
|
}),
|
|
@@ -189,6 +222,14 @@ export function apply(ctx, config) {
|
|
|
189
222
|
cancel: () => install.cancel(),
|
|
190
223
|
cliPath: () => install.cliPath(),
|
|
191
224
|
}),
|
|
225
|
+
mountSearchRoute(svcCtx.webServer, {
|
|
226
|
+
search: (repoPath, query, options) => searchWithFallback(repoPath, query, {
|
|
227
|
+
shell: searchShell,
|
|
228
|
+
helperPath: searchHelperPath,
|
|
229
|
+
limit: options?.limit,
|
|
230
|
+
managedPrefix: installPrefix,
|
|
231
|
+
}),
|
|
232
|
+
}),
|
|
192
233
|
];
|
|
193
234
|
ctx.effect(() => () => {
|
|
194
235
|
for (const dispose of disposers)
|
|
@@ -203,7 +244,7 @@ export function apply(ctx, config) {
|
|
|
203
244
|
}
|
|
204
245
|
}
|
|
205
246
|
/**
|
|
206
|
-
* Human-readable rendering lives in `./gitnexus/format.js`
|
|
247
|
+
* Human-readable rendering lives in `./gitnexus/format.js` —free of DSH imports
|
|
207
248
|
* so it can be tested without a host. Re-exported here for callers that already
|
|
208
249
|
* hold the plugin module.
|
|
209
250
|
*/
|
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,9 +14,17 @@
|
|
|
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
30
|
import type { CoverageReport } from '../gitnexus/coverage.js';
|
|
@@ -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,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClF,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,CAgDnG"}
|
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
|
}
|
|
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAoB3E;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAA2B,EAAE,IAAuB;IACrF,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9C,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;YAAE,OAAO;QAEjC,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;gBACjB,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,kCAAkC;aAC5C,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnC,yEAAyE;QACzE,+EAA+E;QAC/E,8EAA8E;QAC9E,8EAA8E;QAC9E,yEAAyE;QACzE,gFAAgF;QAChF,sDAAsD;QACtD,IAAI,CAAC,CAAC,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACpC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;gBACjB,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,iEAAiE;aAC3E,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,IAAI,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;YAAE,OAAO;QAEjC,+EAA+E;QAC/E,mEAAmE;QACnE,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,uEAAuE;QACvE,2EAA2E;QAC3E,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9F,iFAAiF;QACjF,gFAAgF;QAChF,oCAAoC;QACpC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,CAAC,CAAC;AACzF,CAAC"}
|
|
@@ -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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
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 path from 'node:path';
|
|
16
|
+
import { guardHandler, passGuard, answerHead, sendJson } from './guard.js';
|
|
17
|
+
import { isProjectRoot } from '../gitnexus/index-meta.js';
|
|
18
|
+
import { SearchError } from '../gitnexus/search.js';
|
|
19
|
+
const SEARCH_METHODS = new Set(['GET', 'HEAD']);
|
|
20
|
+
/**
|
|
21
|
+
* @returns disposer that unregisters the route
|
|
22
|
+
*/
|
|
23
|
+
export function mountSearchRoute(webServer, deps) {
|
|
24
|
+
const handler = guardHandler(async (req, res) => {
|
|
25
|
+
if (!passGuard(req, res, SEARCH_METHODS))
|
|
26
|
+
return;
|
|
27
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
28
|
+
const repo = url.searchParams.get('repo');
|
|
29
|
+
if (repo === null || repo.trim() === '') {
|
|
30
|
+
sendJson(res, 400, { ok: false, code: 'missing-repo', message: 'repo query parameter is required' });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const query = url.searchParams.get('q');
|
|
34
|
+
if (query === null || query.trim() === '') {
|
|
35
|
+
sendJson(res, 400, { ok: false, code: 'missing-query', message: 'q query parameter is required' });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const absRepo = path.resolve(repo);
|
|
39
|
+
// The same boundary as the coverage route: a search must not become a way to
|
|
40
|
+
// ask whether an arbitrary directory exists. The engine repeats this check for
|
|
41
|
+
// direct callers; at the HTTP edge it saves opening a database to say no.
|
|
42
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
43
|
+
sendJson(res, 404, {
|
|
44
|
+
ok: false,
|
|
45
|
+
code: 'not-a-project',
|
|
46
|
+
message: 'directory is neither a GitNexus index nor a git repository root',
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (answerHead(req, res))
|
|
51
|
+
return;
|
|
52
|
+
// `limit` is optional; the engine clamps it. A malformed value is treated as
|
|
53
|
+
// absent rather than as an error — the search itself does not depend on it.
|
|
54
|
+
const rawLimit = url.searchParams.get('limit');
|
|
55
|
+
const parsed = rawLimit === null ? Number.NaN : Number.parseInt(rawLimit, 10);
|
|
56
|
+
const limit = Number.isFinite(parsed) ? parsed : undefined;
|
|
57
|
+
try {
|
|
58
|
+
const report = await deps.search(absRepo, query, { limit });
|
|
59
|
+
sendJson(res, 200, {
|
|
60
|
+
ok: true,
|
|
61
|
+
...report,
|
|
62
|
+
readAt: new Date().toISOString(),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof SearchError) {
|
|
67
|
+
sendJson(res, error.status, { ok: false, code: error.code, message: error.message });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// `guardHandler` turns anything else into a 500; rethrow so its single error
|
|
71
|
+
// path stays the only place that formats an unexpected failure.
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return webServer.register({ kind: 'prefix', path: '/api/gitnexus/search', handler });
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/routes/search.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-gitnexus-plus",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "DSH plugin: visualize a GitNexus project index, report what it left out, and run its incremental refresh from a sidebar panel — including detecting a missing GitNexus and installing one on request.",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "DSH plugin: visualize a GitNexus project index, search its symbols by keyword, report what it left out, and run its incremental refresh from a sidebar panel — including detecting a missing GitNexus and installing one on request.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|