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
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyword search over the graph GitNexus already indexed.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS DOES NOT USE FTS
|
|
5
|
+
* -------------------------
|
|
6
|
+
* GitNexus's keyword surface is its BM25/FTS extension. On this machine that
|
|
7
|
+
* extension fails to load (`libfts.lbug_extension` is missing), and the existing
|
|
8
|
+
* index was built with `--skip-fts`, so there are no FTS tables to query even if the
|
|
9
|
+
* extension were present. Reporting "search unavailable" would be honest, but it
|
|
10
|
+
* would also be the end of the feature for the state most users are in.
|
|
11
|
+
*
|
|
12
|
+
* The graph itself still contains every symbol's name and file path, and a Cypher
|
|
13
|
+
* `CONTAINS` over those columns answers the question the user is actually asking
|
|
14
|
+
* when they type a symbol name. This module therefore searches **names and paths**,
|
|
15
|
+
* not source text or descriptions. That distinction is deliberate and surfaced to
|
|
16
|
+
* the panel: an FTS repair can add content search later without this module
|
|
17
|
+
* pretending it already has it.
|
|
18
|
+
*
|
|
19
|
+
* READ-ONLY, AND REUSING GITNEXUS'S OWN ADAPTER
|
|
20
|
+
* ---------------------------------------------
|
|
21
|
+
* The database is opened through GitNexus's `withLbugDb(..., { readOnly: true,
|
|
22
|
+
* skipFts: true })`, so it takes no write lock, cannot mutate the index, and does not
|
|
23
|
+
* attempt the FTS load that is known to fail here. The adapter is deep-imported from
|
|
24
|
+
* the installed package, matching the plugin's existing "reuse, don't reimplement"
|
|
25
|
+
* stance; if the package or its native engine is unavailable, search reports that
|
|
26
|
+
* state rather than falling back to a filesystem scan with different semantics.
|
|
27
|
+
*/
|
|
28
|
+
import { existsSync } from 'node:fs';
|
|
29
|
+
import fs from 'node:fs/promises';
|
|
30
|
+
import path from 'node:path';
|
|
31
|
+
import { pathToFileURL } from 'node:url';
|
|
32
|
+
import { findGitnexusRoot } from './root.js';
|
|
33
|
+
import { isProjectRoot, readIndexMeta } from './index-meta.js';
|
|
34
|
+
import { readCapabilities } from './coverage.js';
|
|
35
|
+
export class SearchError extends Error {
|
|
36
|
+
code;
|
|
37
|
+
status;
|
|
38
|
+
constructor(code, status, message) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = 'SearchError';
|
|
41
|
+
this.code = code;
|
|
42
|
+
this.status = status;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const adapters = new Map();
|
|
46
|
+
/**
|
|
47
|
+
* Load GitNexus's LadybugDB adapter from the installed package.
|
|
48
|
+
*
|
|
49
|
+
* A missing package, a missing native engine, or a reshaped adapter all become the
|
|
50
|
+
* same reported state: search is unavailable here, and the reason is carried in the
|
|
51
|
+
* message rather than hidden behind an empty result list.
|
|
52
|
+
*/
|
|
53
|
+
async function loadAdapter(options) {
|
|
54
|
+
const root = findGitnexusRoot({ env: options.env, managedPrefix: options.managedPrefix });
|
|
55
|
+
if (root === null) {
|
|
56
|
+
throw new SearchError('search-unavailable', 503, '找不到 GitNexus 包,无法打开图数据库。安装或指向 GitNexus 后重试。');
|
|
57
|
+
}
|
|
58
|
+
const cached = adapters.get(root);
|
|
59
|
+
if (cached !== undefined)
|
|
60
|
+
return cached;
|
|
61
|
+
try {
|
|
62
|
+
const mod = (await import(pathToFileURL(path.join(root, 'dist', 'core', 'lbug', 'lbug-adapter.js')).href));
|
|
63
|
+
if (typeof mod.withLbugDb !== 'function' || typeof mod.executePrepared !== 'function') {
|
|
64
|
+
throw new Error('adapter does not export withLbugDb/executePrepared');
|
|
65
|
+
}
|
|
66
|
+
const adapter = {
|
|
67
|
+
withLbugDb: mod.withLbugDb,
|
|
68
|
+
executePrepared: mod.executePrepared,
|
|
69
|
+
};
|
|
70
|
+
adapters.set(root, adapter);
|
|
71
|
+
return adapter;
|
|
72
|
+
}
|
|
73
|
+
catch (cause) {
|
|
74
|
+
throw new SearchError('search-unavailable', 503, `GitNexus 的图数据库适配器不可用:${cause instanceof Error ? cause.message : String(cause)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Normalize a user keyword into a safe Cypher string literal body.
|
|
79
|
+
*
|
|
80
|
+
* The query is interpolated as a single-quoted literal because LadybugDB's prepare
|
|
81
|
+
* path does not accept a bound parameter in this `CONTAINS` position (measured:
|
|
82
|
+
* `lower(n.name) CONTAINS $q` fails at parse time, while the same query with a
|
|
83
|
+
* literal works). Safety therefore comes from **removing** every character that
|
|
84
|
+
* could terminate or escape the literal — quotes, backslashes and control
|
|
85
|
+
* characters — rather than from escaping them. The allowed set is what a code
|
|
86
|
+
* identifier or path search needs; everything else becomes a space.
|
|
87
|
+
*
|
|
88
|
+
* Case is lowered here to match `lower(n.name)` on the other side. The length cap
|
|
89
|
+
* keeps a pathological paste from turning into an expensive graph scan.
|
|
90
|
+
*/
|
|
91
|
+
export function sanitizeSearchQuery(raw) {
|
|
92
|
+
return raw
|
|
93
|
+
.normalize('NFC')
|
|
94
|
+
.toLowerCase()
|
|
95
|
+
.replace(/[^\p{L}\p{N}\s_./:@#+-]/gu, ' ')
|
|
96
|
+
.replace(/\s+/g, ' ')
|
|
97
|
+
.trim()
|
|
98
|
+
.slice(0, 80);
|
|
99
|
+
}
|
|
100
|
+
function clampLimit(value) {
|
|
101
|
+
const n = value === undefined || !Number.isFinite(value) ? 20 : Math.floor(value);
|
|
102
|
+
return Math.max(1, Math.min(50, n));
|
|
103
|
+
}
|
|
104
|
+
function toLine(value) {
|
|
105
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
106
|
+
return Math.trunc(value);
|
|
107
|
+
if (typeof value === 'bigint')
|
|
108
|
+
return Number(value);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
function buildCypher(query, limit) {
|
|
112
|
+
// `query` has already been reduced to the safe literal alphabet by
|
|
113
|
+
// sanitizeSearchQuery; the limit is a clamped integer. Neither is user-arbitrary
|
|
114
|
+
// syntax at this point.
|
|
115
|
+
return `
|
|
116
|
+
MATCH (n)
|
|
117
|
+
WHERE (lower(n.name) CONTAINS '${query}'
|
|
118
|
+
OR (label(n) = 'File' AND lower(n.filePath) CONTAINS '${query}'))
|
|
119
|
+
RETURN label(n) AS kind, n.name AS name, n.filePath AS filePath,
|
|
120
|
+
n.startLine AS startLine, n.endLine AS endLine,
|
|
121
|
+
CASE WHEN lower(n.name) = '${query}' THEN 0
|
|
122
|
+
WHEN lower(n.name) STARTS WITH '${query}' THEN 1
|
|
123
|
+
WHEN label(n) = 'File' THEN 2
|
|
124
|
+
ELSE 3 END AS rank
|
|
125
|
+
ORDER BY rank, name
|
|
126
|
+
LIMIT ${limit}
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
function mapRows(rows) {
|
|
130
|
+
const results = [];
|
|
131
|
+
for (const value of rows) {
|
|
132
|
+
if (value === null || typeof value !== 'object')
|
|
133
|
+
continue;
|
|
134
|
+
const row = value;
|
|
135
|
+
const name = typeof row.name === 'string' ? row.name : '';
|
|
136
|
+
const filePath = typeof row.filePath === 'string' ? row.filePath : '';
|
|
137
|
+
if (name === '' || filePath === '')
|
|
138
|
+
continue;
|
|
139
|
+
results.push({
|
|
140
|
+
kind: typeof row.kind === 'string' && row.kind !== '' ? row.kind : 'Unknown',
|
|
141
|
+
name,
|
|
142
|
+
filePath,
|
|
143
|
+
startLine: toLine(row.startLine),
|
|
144
|
+
endLine: toLine(row.endLine),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return results;
|
|
148
|
+
}
|
|
149
|
+
function isBusyMessage(message) {
|
|
150
|
+
return /busy|locked|lock held|another process|timeout/i.test(message);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Search symbol names and file paths in one repository's index.
|
|
154
|
+
*
|
|
155
|
+
* @throws {SearchError} for states the route should report as status + code.
|
|
156
|
+
*/
|
|
157
|
+
export async function searchSymbols(repoPath, rawQuery, options = {}) {
|
|
158
|
+
const query = sanitizeSearchQuery(rawQuery);
|
|
159
|
+
if (query === '') {
|
|
160
|
+
throw new SearchError('invalid-query', 400, '搜索词不能为空,且至少包含一个字母或数字。');
|
|
161
|
+
}
|
|
162
|
+
const absRepo = path.resolve(repoPath);
|
|
163
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
164
|
+
throw new SearchError('not-a-project', 404, '目录不是 GitNexus 索引,也不是 git 项目根。');
|
|
165
|
+
}
|
|
166
|
+
const meta = await readIndexMeta(absRepo);
|
|
167
|
+
if (meta === null) {
|
|
168
|
+
throw new SearchError('no-index', 409, '该项目还没有 GitNexus 索引;初始化后才能搜索。');
|
|
169
|
+
}
|
|
170
|
+
const lbugPath = path.join(absRepo, '.gitnexus', 'lbug');
|
|
171
|
+
if (!existsSync(lbugPath)) {
|
|
172
|
+
throw new SearchError('no-index-store', 409, '索引缺少 .gitnexus/lbug 图存储,无法搜索。');
|
|
173
|
+
}
|
|
174
|
+
const adapter = await loadAdapter(options);
|
|
175
|
+
const limit = clampLimit(options.limit);
|
|
176
|
+
const cypher = buildCypher(query, limit);
|
|
177
|
+
let rows;
|
|
178
|
+
try {
|
|
179
|
+
// `skipFts` avoids the extension load that is known to fail on this machine;
|
|
180
|
+
// `readOnly` keeps the search from taking a writer lock or creating anything.
|
|
181
|
+
rows = (await adapter.withLbugDb(lbugPath, async () => adapter.executePrepared(cypher, {}), { readOnly: true, skipFts: true }));
|
|
182
|
+
}
|
|
183
|
+
catch (cause) {
|
|
184
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
185
|
+
if (isBusyMessage(message)) {
|
|
186
|
+
throw new SearchError('index-busy', 503, '索引正被另一个 GitNexus 操作占用,稍后重试。');
|
|
187
|
+
}
|
|
188
|
+
throw new SearchError('search-failed', 500, `图查询失败:${message}`);
|
|
189
|
+
}
|
|
190
|
+
const results = mapRows(rows);
|
|
191
|
+
const capabilities = readCapabilities(meta.raw ?? null);
|
|
192
|
+
const ftsAvailable = capabilities.fts?.status === 'available';
|
|
193
|
+
return {
|
|
194
|
+
query,
|
|
195
|
+
mode: 'graph',
|
|
196
|
+
ftsAvailable,
|
|
197
|
+
results,
|
|
198
|
+
total: results.length,
|
|
199
|
+
truncated: results.length >= limit,
|
|
200
|
+
warning: ftsAvailable
|
|
201
|
+
? null
|
|
202
|
+
: 'FTS 内容检索不可用;本次按符号名与文件路径匹配,不搜索正文。',
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function quoteFor(value) {
|
|
206
|
+
return process.platform === 'win32'
|
|
207
|
+
? `'${value.replace(/'/g, "''")}'`
|
|
208
|
+
: `'${value.replace(/'/g, "'\\''")}'`;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Parse the helper's one-object stdout without assuming it is the very first byte.
|
|
212
|
+
*
|
|
213
|
+
* GitNexus or Node can write a warning to stdout before our payload. Taking the
|
|
214
|
+
* first `{` to the last `}` is deliberately forgiving of that, while a missing
|
|
215
|
+
* object still becomes a typed failure rather than an empty result.
|
|
216
|
+
*/
|
|
217
|
+
function parseHelperOutput(text) {
|
|
218
|
+
const start = text.indexOf('{');
|
|
219
|
+
const end = text.lastIndexOf('}');
|
|
220
|
+
if (start < 0 || end <= start)
|
|
221
|
+
return null;
|
|
222
|
+
try {
|
|
223
|
+
const parsed = JSON.parse(text.slice(start, end + 1));
|
|
224
|
+
return parsed !== null && typeof parsed === 'object' ? parsed : null;
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function searchErrorCode(value) {
|
|
231
|
+
switch (value) {
|
|
232
|
+
case 'invalid-query':
|
|
233
|
+
case 'not-a-project':
|
|
234
|
+
case 'no-index':
|
|
235
|
+
case 'no-index-store':
|
|
236
|
+
case 'search-unavailable':
|
|
237
|
+
case 'index-busy':
|
|
238
|
+
case 'search-failed':
|
|
239
|
+
return value;
|
|
240
|
+
default:
|
|
241
|
+
return 'search-failed';
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function asReport(value) {
|
|
245
|
+
if (value === null || typeof value !== 'object')
|
|
246
|
+
return null;
|
|
247
|
+
const raw = value;
|
|
248
|
+
if (!Array.isArray(raw.results))
|
|
249
|
+
return null;
|
|
250
|
+
const results = [];
|
|
251
|
+
for (const item of raw.results) {
|
|
252
|
+
if (item === null || typeof item !== 'object')
|
|
253
|
+
continue;
|
|
254
|
+
const row = item;
|
|
255
|
+
if (typeof row.name !== 'string' || typeof row.filePath !== 'string')
|
|
256
|
+
continue;
|
|
257
|
+
results.push({
|
|
258
|
+
kind: typeof row.kind === 'string' ? row.kind : 'Unknown',
|
|
259
|
+
name: row.name,
|
|
260
|
+
filePath: row.filePath,
|
|
261
|
+
startLine: toLine(row.startLine),
|
|
262
|
+
endLine: toLine(row.endLine),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
query: typeof raw.query === 'string' ? raw.query : '',
|
|
267
|
+
mode: raw.mode === 'text' ? 'text' : 'graph',
|
|
268
|
+
ftsAvailable: raw.ftsAvailable === true,
|
|
269
|
+
results,
|
|
270
|
+
total: typeof raw.total === 'number' ? raw.total : results.length,
|
|
271
|
+
truncated: raw.truncated === true,
|
|
272
|
+
warning: typeof raw.warning === 'string' ? raw.warning : null,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Run the search in a child Node process.
|
|
277
|
+
*
|
|
278
|
+
* WHY A SUBPROCESS IS NOT OPTIONAL
|
|
279
|
+
* --------------------------------
|
|
280
|
+
* The DSH host runs on Electron's Node, and GitNexus's LadybugDB addon is built for
|
|
281
|
+
* the system Node ABI. Loading it in the host fails with
|
|
282
|
+
*
|
|
283
|
+
* A dynamic link library (DLL) initialization routine failed. …\lbugjs.node
|
|
284
|
+
*
|
|
285
|
+
* while the very same addon loads under the system Node 24 that the CLI uses. The
|
|
286
|
+
* host therefore cannot own the native connection; it starts `node <helper>` and
|
|
287
|
+
* parses one JSON object. That is the same execution boundary the analyze runner
|
|
288
|
+
* already uses, and it keeps the panel process free of native state it cannot load.
|
|
289
|
+
*
|
|
290
|
+
* The command has no environment prefix: a short-lived helper does not need the
|
|
291
|
+
* heap respawn guard, and avoiding `$env:` syntax keeps the command portable across
|
|
292
|
+
* PowerShell, Git Bash and POSIX shells.
|
|
293
|
+
*/
|
|
294
|
+
export async function searchViaHelper(repoPath, rawQuery, options) {
|
|
295
|
+
const query = sanitizeSearchQuery(rawQuery);
|
|
296
|
+
if (query === '') {
|
|
297
|
+
throw new SearchError('invalid-query', 400, '搜索词不能为空,且至少包含一个字母或数字。');
|
|
298
|
+
}
|
|
299
|
+
const absRepo = path.resolve(repoPath);
|
|
300
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
301
|
+
throw new SearchError('not-a-project', 404, '目录不是 GitNexus 索引,也不是 git 项目根。');
|
|
302
|
+
}
|
|
303
|
+
const meta = await readIndexMeta(absRepo);
|
|
304
|
+
if (meta === null) {
|
|
305
|
+
throw new SearchError('no-index', 409, '该项目还没有 GitNexus 索引;初始化后才能搜索。');
|
|
306
|
+
}
|
|
307
|
+
if (!existsSync(path.join(absRepo, '.gitnexus', 'lbug'))) {
|
|
308
|
+
throw new SearchError('no-index-store', 409, '索引缺少 .gitnexus/lbug 图存储,无法搜索。');
|
|
309
|
+
}
|
|
310
|
+
if (options.shell === null) {
|
|
311
|
+
throw new SearchError('search-unavailable', 503, '当前部署没有 shell 执行器,无法启动搜索子进程;搜索需要系统 Node 24 加载 GitNexus 原生模块。');
|
|
312
|
+
}
|
|
313
|
+
const limit = clampLimit(options.limit);
|
|
314
|
+
const args = [options.helperPath, absRepo, query, String(limit), options.managedPrefix ?? '']
|
|
315
|
+
.map(quoteFor)
|
|
316
|
+
.join(' ');
|
|
317
|
+
const command = `node ${args}`;
|
|
318
|
+
let result;
|
|
319
|
+
try {
|
|
320
|
+
const spec = options.shell.resolve({
|
|
321
|
+
command,
|
|
322
|
+
workdir: absRepo,
|
|
323
|
+
timeoutMs: 20_000,
|
|
324
|
+
onExpiry: 'kill',
|
|
325
|
+
stdoutMaxBytes: 2 * 1024 * 1024,
|
|
326
|
+
});
|
|
327
|
+
const execution = await options.shell.execute(spec);
|
|
328
|
+
result = await execution.result();
|
|
329
|
+
}
|
|
330
|
+
catch (cause) {
|
|
331
|
+
throw new SearchError('search-unavailable', 503, `无法启动搜索子进程:${cause instanceof Error ? cause.message : String(cause)}`);
|
|
332
|
+
}
|
|
333
|
+
if (result.timedOut === true) {
|
|
334
|
+
throw new SearchError('search-failed', 504, '搜索子进程超时(20 秒)。');
|
|
335
|
+
}
|
|
336
|
+
const stdout = typeof result.stdout?.text === 'string' ? result.stdout.text : '';
|
|
337
|
+
const stderr = typeof result.stderr?.text === 'string' ? result.stderr.text : '';
|
|
338
|
+
const parsed = parseHelperOutput(stdout);
|
|
339
|
+
if (parsed === null) {
|
|
340
|
+
const tail = stderr.trim().slice(-600);
|
|
341
|
+
throw new SearchError('search-failed', 500, `搜索子进程没有返回可解析结果${result.exitCode === undefined ? '' : ` (exit ${String(result.exitCode)})`}` + (tail === '' ? '' : `:${tail}`));
|
|
342
|
+
}
|
|
343
|
+
if (parsed.ok !== true) {
|
|
344
|
+
const status = typeof parsed.status === 'number' ? parsed.status : 500;
|
|
345
|
+
const message = typeof parsed.message === 'string' ? parsed.message : '搜索失败。';
|
|
346
|
+
throw new SearchError(searchErrorCode(parsed.code), status, message);
|
|
347
|
+
}
|
|
348
|
+
const report = asReport(parsed.report);
|
|
349
|
+
if (report === null) {
|
|
350
|
+
throw new SearchError('search-failed', 500, '搜索子进程返回了无法识别的结果形状。');
|
|
351
|
+
}
|
|
352
|
+
return report;
|
|
353
|
+
}
|
|
354
|
+
const DEFAULT_TEXT_MAX_FILES = 2_000;
|
|
355
|
+
const DEFAULT_TEXT_MAX_BYTES = 16 * 1024 * 1024;
|
|
356
|
+
const DEFAULT_TEXT_MAX_FILE_BYTES = 1024 * 1024;
|
|
357
|
+
/**
|
|
358
|
+
* Bounded keyword search over the source files listed by the index.
|
|
359
|
+
*
|
|
360
|
+
* This exists for one concrete state: the host cannot start the native query path
|
|
361
|
+
* (Electron ABI, no usable shell sandbox, busy database). In that state the index
|
|
362
|
+
* manifest still names every file the index covers, and reading those files is
|
|
363
|
+
* ordinary filesystem access the host already has. It is deliberately **not** a
|
|
364
|
+
* hidden replacement for the graph search:
|
|
365
|
+
*
|
|
366
|
+
* - it searches line text, so `mode` is `text` and the panel says so;
|
|
367
|
+
* - it only looks at files the index lists, so a brand-new untracked file is
|
|
368
|
+
* still absent until the index is refreshed;
|
|
369
|
+
* - every dimension is capped and `truncated` reports when a cap bit, because a
|
|
370
|
+
* silent partial result is the failure mode this whole project exists to avoid.
|
|
371
|
+
*
|
|
372
|
+
* It performs no spawn, no native load and no write.
|
|
373
|
+
*/
|
|
374
|
+
export async function searchText(repoPath, rawQuery, options = {}) {
|
|
375
|
+
const query = rawQuery.normalize('NFC').trim().slice(0, 200);
|
|
376
|
+
if (query === '') {
|
|
377
|
+
throw new SearchError('invalid-query', 400, '搜索词不能为空。');
|
|
378
|
+
}
|
|
379
|
+
const absRepo = path.resolve(repoPath);
|
|
380
|
+
if (!(await isProjectRoot(absRepo))) {
|
|
381
|
+
throw new SearchError('not-a-project', 404, '目录不是 GitNexus 索引,也不是 git 项目根。');
|
|
382
|
+
}
|
|
383
|
+
const meta = await readIndexMeta(absRepo);
|
|
384
|
+
if (meta === null) {
|
|
385
|
+
throw new SearchError('no-index', 409, '该项目还没有 GitNexus 索引;初始化后才能搜索。');
|
|
386
|
+
}
|
|
387
|
+
const limit = clampLimit(options.limit);
|
|
388
|
+
const maxFiles = Math.max(1, Math.min(5_000, Math.floor(options.maxFiles ?? DEFAULT_TEXT_MAX_FILES)));
|
|
389
|
+
const maxBytes = Math.max(64 * 1024, Math.min(256 * 1024 * 1024, Math.floor(options.maxBytes ?? DEFAULT_TEXT_MAX_BYTES)));
|
|
390
|
+
const maxFileBytes = Math.max(8 * 1024, Math.min(16 * 1024 * 1024, Math.floor(options.maxFileBytes ?? DEFAULT_TEXT_MAX_FILE_BYTES)));
|
|
391
|
+
const requested = Object.keys(meta.fileHashes ?? {});
|
|
392
|
+
const warning = `图查询不可用${options.reason === undefined || options.reason.trim() === ''
|
|
393
|
+
? ''
|
|
394
|
+
: `(${options.reason.trim().slice(0, 120)})`};已回退到索引文件的源码关键词搜索。结果来自文本,不是图谱。`;
|
|
395
|
+
if (requested.length === 0) {
|
|
396
|
+
return {
|
|
397
|
+
query,
|
|
398
|
+
mode: 'text',
|
|
399
|
+
ftsAvailable: false,
|
|
400
|
+
results: [],
|
|
401
|
+
total: 0,
|
|
402
|
+
truncated: false,
|
|
403
|
+
warning: `图查询不可用;索引清单没有文件列表,无法回退到源码搜索。`,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
const lower = query.toLowerCase();
|
|
407
|
+
const results = [];
|
|
408
|
+
let bytesRead = 0;
|
|
409
|
+
let truncated = requested.length > maxFiles;
|
|
410
|
+
const prefix = absRepo.endsWith(path.sep) ? absRepo : `${absRepo}${path.sep}`;
|
|
411
|
+
// A keyword in a README should not fill the result limit before the source file
|
|
412
|
+
// that defines it. Code-bearing paths go first; path order breaks the tie.
|
|
413
|
+
const codePath = /\.(?:ts|tsx|js|jsx|mjs|cjs|py|java|go|rs|c|cc|cpp|h|hpp|cs|rb|php|kt|swift|dart|vue|sh|ps1|sql)$/iu;
|
|
414
|
+
const ordered = [...requested].sort((a, b) => {
|
|
415
|
+
const aCode = codePath.test(a) ? 1 : 0;
|
|
416
|
+
const bCode = codePath.test(b) ? 1 : 0;
|
|
417
|
+
return bCode - aCode || a.localeCompare(b);
|
|
418
|
+
});
|
|
419
|
+
for (const relative of ordered.slice(0, maxFiles)) {
|
|
420
|
+
if (results.length >= limit) {
|
|
421
|
+
truncated = true;
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
if (relative.includes('\0'))
|
|
425
|
+
continue;
|
|
426
|
+
const absolute = path.resolve(absRepo, relative);
|
|
427
|
+
// The manifest is written by GitNexus, but it is still data at a boundary: do
|
|
428
|
+
// not let a `../` entry turn the fallback into a read outside the project.
|
|
429
|
+
if (!absolute.startsWith(prefix))
|
|
430
|
+
continue;
|
|
431
|
+
let size;
|
|
432
|
+
try {
|
|
433
|
+
size = (await fs.stat(absolute)).size;
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (size > maxFileBytes) {
|
|
439
|
+
truncated = true;
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
if (bytesRead + size > maxBytes) {
|
|
443
|
+
truncated = true;
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
let buffer;
|
|
447
|
+
try {
|
|
448
|
+
buffer = await fs.readFile(absolute);
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
bytesRead += buffer.length;
|
|
454
|
+
// Binary files have no meaningful line text; git's own NUL-byte rule is enough.
|
|
455
|
+
if (buffer.subarray(0, 8192).includes(0))
|
|
456
|
+
continue;
|
|
457
|
+
const text = buffer.toString('utf8');
|
|
458
|
+
if (!text.toLowerCase().includes(lower))
|
|
459
|
+
continue;
|
|
460
|
+
const lines = text.split(/\r?\n/);
|
|
461
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
462
|
+
if (results.length >= limit) {
|
|
463
|
+
truncated = true;
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
const line = lines[index];
|
|
467
|
+
if (!line.toLowerCase().includes(lower))
|
|
468
|
+
continue;
|
|
469
|
+
results.push({
|
|
470
|
+
kind: 'Text',
|
|
471
|
+
name: line.trim().slice(0, 160) || query,
|
|
472
|
+
filePath: relative.replace(/\\/g, '/'),
|
|
473
|
+
startLine: index + 1,
|
|
474
|
+
endLine: index + 1,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
query,
|
|
480
|
+
mode: 'text',
|
|
481
|
+
ftsAvailable: false,
|
|
482
|
+
results,
|
|
483
|
+
total: results.length,
|
|
484
|
+
truncated,
|
|
485
|
+
warning,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
/** Failures for which the source fallback is more useful than an error card. */
|
|
489
|
+
const FALLBACK_CODES = new Set([
|
|
490
|
+
'search-unavailable',
|
|
491
|
+
'search-failed',
|
|
492
|
+
'index-busy',
|
|
493
|
+
'no-index-store',
|
|
494
|
+
]);
|
|
495
|
+
/**
|
|
496
|
+
* Graph first, then the bounded source fallback when the native path cannot run.
|
|
497
|
+
*
|
|
498
|
+
* The fallback is not attempted for an empty query, an unidentified project, or a
|
|
499
|
+
* project with no index: in all three there is either nothing to search or no honest
|
|
500
|
+
* denominator. Every other failure gets the text search, and its report carries
|
|
501
|
+
* `mode: "text"` plus the graph failure in `warning`.
|
|
502
|
+
*/
|
|
503
|
+
export async function searchWithFallback(repoPath, rawQuery, options) {
|
|
504
|
+
try {
|
|
505
|
+
return await searchViaHelper(repoPath, rawQuery, options);
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
if (error instanceof SearchError && FALLBACK_CODES.has(error.code)) {
|
|
509
|
+
return searchText(repoPath, rawQuery, {
|
|
510
|
+
limit: options.limit,
|
|
511
|
+
reason: error.message,
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
throw error;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/gitnexus/search.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
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
|
*/
|
|
14
15
|
import type { Context } from '@deepseek-ai/cordis';
|
|
15
16
|
import { type MaintenanceCommand } from './gitnexus/commands.js';
|
|
16
17
|
export declare const name = "gitnexus-plus";
|
|
17
18
|
/**
|
|
18
19
|
* Only `tools` is required. `webServer` is reached through `ctx.inject` because a
|
|
19
|
-
* headless profile has no HTTP carrier at all
|
|
20
|
+
* headless profile has no HTTP carrier at all —naming it here would leave the
|
|
20
21
|
* plugin permanently pending there, and the tool would never register.
|
|
21
22
|
*/
|
|
22
23
|
export declare const inject: readonly ["tools"];
|
|
@@ -26,10 +27,16 @@ export interface PluginConfig {
|
|
|
26
27
|
minifiedSampleLimit: number;
|
|
27
28
|
serveRoutes: boolean;
|
|
28
29
|
/**
|
|
29
|
-
* Shapes the maintenance commands the panel hands to the operator.
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* Shapes the maintenance commands the panel hands to the operator. `memoryOff`
|
|
31
|
+
* defaults on because the CLI otherwise re-spawns itself over piped stdio, which
|
|
32
|
+
* a confined process denies.
|
|
33
|
+
*
|
|
34
|
+
* `skipFts: false` (default) means **automatic**: the plugin skips FTS when the
|
|
35
|
+
* index does not have it, and omits the flag when it does. Both static values were
|
|
36
|
+
* measured wrong on a real machine: `true` forces a 21x full rebuild on an FTS
|
|
37
|
+
* index, while an unconditional `false` makes a refresh on a non-FTS index die
|
|
38
|
+
* with `spawn EPERM` when the extension tries to install out-of-process. `true`
|
|
39
|
+
* here forces the flag for an operator who needs it.
|
|
33
40
|
*/
|
|
34
41
|
skipFts: boolean;
|
|
35
42
|
memoryOff: boolean;
|
|
@@ -50,6 +57,12 @@ export interface PluginConfig {
|
|
|
50
57
|
gitnexusInstallDir: string;
|
|
51
58
|
/** Wall-clock ceiling for that install. Compiling native modules is slow. */
|
|
52
59
|
installTimeoutMs: number;
|
|
60
|
+
/**
|
|
61
|
+
* Redirect for GitNexus's global registry write. Empty means
|
|
62
|
+
* `<project>/.gitnexus/plugin-home`, inside the workspace. The global
|
|
63
|
+
* `~/.gitnexus` is outside a confined host's writable scope, and a refresh that
|
|
64
|
+
* dies on the registry write leaves the index incomplete.
|
|
65
|
+
*/
|
|
53
66
|
gitnexusHome: string;
|
|
54
67
|
}
|
|
55
68
|
export declare const Config: import("@deepseek-ai/schemastery").SchemaLike<{
|
|
@@ -68,10 +81,16 @@ export declare const Config: import("@deepseek-ai/schemastery").SchemaLike<{
|
|
|
68
81
|
export interface MaintenanceInfo {
|
|
69
82
|
commands: MaintenanceCommand[];
|
|
70
83
|
rationale: string[];
|
|
84
|
+
/**
|
|
85
|
+
* Whether the mounted analyze route understands `force=1`. The client uses it to
|
|
86
|
+
* avoid offering a full-rebuild button against an older host, where that flag was
|
|
87
|
+
* ignored and the button would silently run an incremental refresh instead.
|
|
88
|
+
*/
|
|
89
|
+
supportsForce: true;
|
|
71
90
|
}
|
|
72
91
|
export declare function apply(ctx: Context, config: PluginConfig): void;
|
|
73
92
|
/**
|
|
74
|
-
* Human-readable rendering lives in `./gitnexus/format.js`
|
|
93
|
+
* Human-readable rendering lives in `./gitnexus/format.js` —free of DSH imports
|
|
75
94
|
* so it can be tested without a host. Re-exported here for callers that already
|
|
76
95
|
* hold the plugin module.
|
|
77
96
|
*/
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAKnD,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,wBAAwB,CAAC;AAuBhC,eAAO,MAAM,IAAI,kBAAkB,CAAC;AAEpC;;;;GAIG;AACH,eAAO,MAAM,MAAM,oBAAqB,CAAC;AAEzC,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;EAWjB,CAAC;AAqBH,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;OAIG;IACH,aAAa,EAAE,IAAI,CAAC;CACrB;AAiBD,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CA+L9D;AAED;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC"}
|