grepmax 0.18.1 → 0.19.0
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 +27 -2
- package/dist/commands/add.js +4 -2
- package/dist/commands/claude-code.js +1 -1
- package/dist/commands/codex.js +3 -1
- package/dist/commands/dead.js +2 -6
- package/dist/commands/doctor.js +26 -7
- package/dist/commands/extract.js +3 -5
- package/dist/commands/impact.js +6 -4
- package/dist/commands/index.js +7 -2
- package/dist/commands/log.js +4 -2
- package/dist/commands/mcp.js +587 -715
- package/dist/commands/peek.js +15 -9
- package/dist/commands/plugin.js +1 -1
- package/dist/commands/project.js +15 -5
- package/dist/commands/related.js +8 -9
- package/dist/commands/review.js +1 -1
- package/dist/commands/similar.js +4 -4
- package/dist/commands/status.js +5 -3
- package/dist/commands/summarize.js +6 -4
- package/dist/commands/test-find.js +2 -2
- package/dist/commands/trace.js +12 -5
- package/dist/commands/watch.js +9 -5
- package/dist/eval-graph-nav.js +4 -1
- package/dist/eval-graph-recovery-probe.js +56 -14
- package/dist/eval-graph-spotcheck.js +10 -2
- package/dist/eval-graph-totals.js +5 -2
- package/dist/eval-oss.js +212 -37
- package/dist/eval-seed.js +13 -4
- package/dist/index.js +9 -9
- package/dist/lib/daemon/daemon.js +22 -13
- package/dist/lib/daemon/ipc-handler.js +18 -5
- package/dist/lib/daemon/mlx-server-manager.js +11 -3
- package/dist/lib/daemon/process-manager.js +1 -2
- package/dist/lib/daemon/watcher-manager.js +4 -4
- package/dist/lib/graph/callsites.js +151 -25
- package/dist/lib/index/batch-processor.js +6 -5
- package/dist/lib/index/chunker.js +2 -0
- package/dist/lib/index/syncer.js +7 -6
- package/dist/lib/llm/diff.js +56 -11
- package/dist/lib/llm/investigate.js +12 -5
- package/dist/lib/llm/review.js +21 -8
- package/dist/lib/llm/server.js +16 -7
- package/dist/lib/output/agent-search-formatter.js +25 -3
- package/dist/lib/output/index-state-footer.js +1 -1
- package/dist/lib/review/risk.js +2 -4
- package/dist/lib/search/searcher.js +37 -11
- package/dist/lib/search/seed-weight.js +4 -1
- package/dist/lib/skeleton/symbol-extractor.js +2 -1
- package/dist/lib/utils/cross-project.js +5 -1
- package/dist/lib/utils/daemon-client.js +5 -1
- package/dist/lib/utils/git.js +10 -2
- package/dist/lib/utils/project-registry.js +3 -2
- package/dist/lib/utils/scope-filter.js +3 -1
- package/dist/lib/utils/watcher-launcher.js +4 -1
- package/dist/lib/utils/watcher-store.js +2 -1
- package/dist/lib/workers/embeddings/mlx-client.js +7 -2
- package/dist/lib/workers/pool.js +9 -6
- package/dist/lib/workers/process-child.js +1 -1
- package/package.json +22 -19
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/hooks/cwd-changed.js +4 -1
- package/plugins/grepmax/hooks/pre-grep.js +2 -1
- package/plugins/grepmax/hooks/start.js +45 -10
- package/plugins/grepmax/hooks/subagent-start.js +1 -4
|
@@ -110,37 +110,163 @@ function resolveCallSites(callers, targetSymbol, fileCache = new Map()) {
|
|
|
110
110
|
*/
|
|
111
111
|
const BUILTIN_CALLEES = new Set([
|
|
112
112
|
// Object/primitive methods
|
|
113
|
-
"toString",
|
|
113
|
+
"toString",
|
|
114
|
+
"valueOf",
|
|
115
|
+
"hasOwnProperty",
|
|
114
116
|
// Array/String methods
|
|
115
|
-
"push",
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
117
|
+
"push",
|
|
118
|
+
"pop",
|
|
119
|
+
"shift",
|
|
120
|
+
"unshift",
|
|
121
|
+
"slice",
|
|
122
|
+
"splice",
|
|
123
|
+
"concat",
|
|
124
|
+
"join",
|
|
125
|
+
"map",
|
|
126
|
+
"filter",
|
|
127
|
+
"reduce",
|
|
128
|
+
"forEach",
|
|
129
|
+
"find",
|
|
130
|
+
"findIndex",
|
|
131
|
+
"some",
|
|
132
|
+
"every",
|
|
133
|
+
"includes",
|
|
134
|
+
"indexOf",
|
|
135
|
+
"lastIndexOf",
|
|
136
|
+
"sort",
|
|
137
|
+
"reverse",
|
|
138
|
+
"flat",
|
|
139
|
+
"flatMap",
|
|
140
|
+
"keys",
|
|
141
|
+
"values",
|
|
142
|
+
"entries",
|
|
143
|
+
"fill",
|
|
144
|
+
"split",
|
|
145
|
+
"trim",
|
|
146
|
+
"trimStart",
|
|
147
|
+
"trimEnd",
|
|
148
|
+
"replace",
|
|
149
|
+
"replaceAll",
|
|
150
|
+
"match",
|
|
151
|
+
"matchAll",
|
|
152
|
+
"test",
|
|
153
|
+
"exec",
|
|
154
|
+
"padStart",
|
|
155
|
+
"padEnd",
|
|
156
|
+
"repeat",
|
|
157
|
+
"charAt",
|
|
158
|
+
"charCodeAt",
|
|
159
|
+
"codePointAt",
|
|
160
|
+
"startsWith",
|
|
161
|
+
"endsWith",
|
|
162
|
+
"toLowerCase",
|
|
163
|
+
"toUpperCase",
|
|
164
|
+
"substring",
|
|
165
|
+
"substr",
|
|
166
|
+
"localeCompare",
|
|
167
|
+
"normalize",
|
|
123
168
|
// Map/Set methods
|
|
124
|
-
"get",
|
|
169
|
+
"get",
|
|
170
|
+
"set",
|
|
171
|
+
"has",
|
|
172
|
+
"add",
|
|
173
|
+
"delete",
|
|
174
|
+
"clear",
|
|
125
175
|
// Math/Date/Number members
|
|
126
|
-
"trunc",
|
|
127
|
-
"
|
|
128
|
-
"
|
|
176
|
+
"trunc",
|
|
177
|
+
"floor",
|
|
178
|
+
"ceil",
|
|
179
|
+
"round",
|
|
180
|
+
"abs",
|
|
181
|
+
"min",
|
|
182
|
+
"max",
|
|
183
|
+
"random",
|
|
184
|
+
"pow",
|
|
185
|
+
"sqrt",
|
|
186
|
+
"log2",
|
|
187
|
+
"log10",
|
|
188
|
+
"sign",
|
|
189
|
+
"now",
|
|
190
|
+
"parse",
|
|
191
|
+
"parseInt",
|
|
192
|
+
"parseFloat",
|
|
193
|
+
"isInteger",
|
|
194
|
+
"isFinite",
|
|
195
|
+
"isNaN",
|
|
196
|
+
"toFixed",
|
|
197
|
+
"toISOString",
|
|
129
198
|
// Promise/Function members
|
|
130
|
-
"then",
|
|
131
|
-
"
|
|
199
|
+
"then",
|
|
200
|
+
"catch",
|
|
201
|
+
"finally",
|
|
202
|
+
"resolve",
|
|
203
|
+
"reject",
|
|
204
|
+
"all",
|
|
205
|
+
"allSettled",
|
|
206
|
+
"race",
|
|
207
|
+
"any",
|
|
208
|
+
"call",
|
|
209
|
+
"apply",
|
|
210
|
+
"bind",
|
|
132
211
|
// JSON / global constructors & functions
|
|
133
|
-
"JSON",
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
212
|
+
"JSON",
|
|
213
|
+
"stringify",
|
|
214
|
+
"Math",
|
|
215
|
+
"Date",
|
|
216
|
+
"Promise",
|
|
217
|
+
"Array",
|
|
218
|
+
"Object",
|
|
219
|
+
"String",
|
|
220
|
+
"Number",
|
|
221
|
+
"Boolean",
|
|
222
|
+
"Symbol",
|
|
223
|
+
"RegExp",
|
|
224
|
+
"Error",
|
|
225
|
+
"TypeError",
|
|
226
|
+
"RangeError",
|
|
227
|
+
"Map",
|
|
228
|
+
"Set",
|
|
229
|
+
"WeakMap",
|
|
230
|
+
"WeakSet",
|
|
231
|
+
"Buffer",
|
|
232
|
+
"URL",
|
|
233
|
+
"URLSearchParams",
|
|
234
|
+
"isArray",
|
|
235
|
+
"from",
|
|
236
|
+
"of",
|
|
237
|
+
"assign",
|
|
238
|
+
"freeze",
|
|
239
|
+
"create",
|
|
240
|
+
"getOwnPropertyNames",
|
|
241
|
+
"fromEntries",
|
|
242
|
+
"setTimeout",
|
|
243
|
+
"setInterval",
|
|
244
|
+
"clearTimeout",
|
|
245
|
+
"clearInterval",
|
|
246
|
+
"queueMicrotask",
|
|
247
|
+
"structuredClone",
|
|
248
|
+
"fetch",
|
|
249
|
+
"console",
|
|
250
|
+
"process",
|
|
251
|
+
"require",
|
|
252
|
+
"encodeURIComponent",
|
|
253
|
+
"decodeURIComponent",
|
|
254
|
+
"encodeURI",
|
|
255
|
+
"decodeURI",
|
|
256
|
+
"atob",
|
|
257
|
+
"btoa",
|
|
141
258
|
// console members
|
|
142
|
-
"warn",
|
|
143
|
-
"
|
|
259
|
+
"warn",
|
|
260
|
+
"info",
|
|
261
|
+
"debug",
|
|
262
|
+
"trace",
|
|
263
|
+
"table",
|
|
264
|
+
"dir",
|
|
265
|
+
"group",
|
|
266
|
+
"groupEnd",
|
|
267
|
+
"assert",
|
|
268
|
+
"time",
|
|
269
|
+
"timeEnd",
|
|
144
270
|
]);
|
|
145
271
|
/** True when an UNRESOLVED callee name is a known JS/TS builtin. */
|
|
146
272
|
function isBuiltinCallee(name) {
|
|
@@ -46,10 +46,10 @@ exports.ProjectBatchProcessor = void 0;
|
|
|
46
46
|
const fs = __importStar(require("node:fs"));
|
|
47
47
|
const path = __importStar(require("node:path"));
|
|
48
48
|
const config_1 = require("../../config");
|
|
49
|
+
const vector_db_1 = require("../store/vector-db");
|
|
49
50
|
const cache_check_1 = require("../utils/cache-check");
|
|
50
51
|
const file_utils_1 = require("../utils/file-utils");
|
|
51
52
|
const logger_1 = require("../utils/logger");
|
|
52
|
-
const vector_db_1 = require("../store/vector-db");
|
|
53
53
|
const pool_1 = require("../workers/pool");
|
|
54
54
|
const watcher_batch_1 = require("./watcher-batch");
|
|
55
55
|
// Fast path-segment check to reject events that leak through FSEvents overflow.
|
|
@@ -164,7 +164,8 @@ class ProjectBatchProcessor {
|
|
|
164
164
|
break;
|
|
165
165
|
attempted.add(absPath);
|
|
166
166
|
processed++;
|
|
167
|
-
if (batch.size > 10 &&
|
|
167
|
+
if (batch.size > 10 &&
|
|
168
|
+
(processed % 10 === 0 || processed === batch.size)) {
|
|
168
169
|
(0, logger_1.log)(this.wtag, `Progress: ${processed}/${batch.size} (${reindexed} reindexed)`);
|
|
169
170
|
}
|
|
170
171
|
if (event === "unlink") {
|
|
@@ -184,7 +185,7 @@ class ProjectBatchProcessor {
|
|
|
184
185
|
}
|
|
185
186
|
// Fast path: if only mtime changed but size matches and we have a hash,
|
|
186
187
|
// verify in-process instead of dispatching to a worker (~220ms saved).
|
|
187
|
-
if (cached
|
|
188
|
+
if ((cached === null || cached === void 0 ? void 0 : cached.hash) && cached.size === stats.size) {
|
|
188
189
|
const buf = yield fs.promises.readFile(absPath);
|
|
189
190
|
const hash = (0, file_utils_1.computeBufferHash)(buf);
|
|
190
191
|
if (hash === cached.hash) {
|
|
@@ -319,8 +320,8 @@ class ProjectBatchProcessor {
|
|
|
319
320
|
}
|
|
320
321
|
}
|
|
321
322
|
if (dropped > 0) {
|
|
322
|
-
const droppedPaths = [...batch.keys()].filter(p => !requeued.has(p));
|
|
323
|
-
(0, logger_1.log)(this.wtag, `Dropped ${dropped} file(s) after ${MAX_RETRIES} retries: ${droppedPaths.map(p => path.basename(p)).join(", ")}`);
|
|
323
|
+
const droppedPaths = [...batch.keys()].filter((p) => !requeued.has(p));
|
|
324
|
+
(0, logger_1.log)(this.wtag, `Dropped ${dropped} file(s) after ${MAX_RETRIES} retries: ${droppedPaths.map((p) => path.basename(p)).join(", ")}`);
|
|
324
325
|
}
|
|
325
326
|
backoffOverrideMs = this.pending.size > 0 ? backoffMs : 0;
|
|
326
327
|
}
|
|
@@ -256,6 +256,7 @@ class TreeSitterChunker {
|
|
|
256
256
|
if (c.definedSymbols && c.content.length > 100) {
|
|
257
257
|
const extra = [];
|
|
258
258
|
let m;
|
|
259
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex exec loop
|
|
259
260
|
while ((m = PROP_FN_RE.exec(c.content)) !== null) {
|
|
260
261
|
const name = m[1];
|
|
261
262
|
if (name.length > 1 && !c.definedSymbols.includes(name)) {
|
|
@@ -278,6 +279,7 @@ class TreeSitterChunker {
|
|
|
278
279
|
const existing = new Set(c.referencedSymbols);
|
|
279
280
|
let jm;
|
|
280
281
|
const jsxRefs = [];
|
|
282
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex exec loop
|
|
281
283
|
while ((jm = JSX_RE.exec(c.content)) !== null) {
|
|
282
284
|
// Extract base component name (e.g., "Foo" from "Foo.Bar")
|
|
283
285
|
const full = jm[1];
|
package/dist/lib/index/syncer.js
CHANGED
|
@@ -55,11 +55,11 @@ exports.initialSync = initialSync;
|
|
|
55
55
|
const fs = __importStar(require("node:fs"));
|
|
56
56
|
const path = __importStar(require("node:path"));
|
|
57
57
|
const config_1 = require("../../config");
|
|
58
|
-
const logger_1 = require("../utils/logger");
|
|
59
58
|
const meta_cache_1 = require("../store/meta-cache");
|
|
60
59
|
const vector_db_1 = require("../store/vector-db");
|
|
61
60
|
// isIndexableFile no longer used — extension check inlined for performance
|
|
62
61
|
const lock_1 = require("../utils/lock");
|
|
62
|
+
const logger_1 = require("../utils/logger");
|
|
63
63
|
const project_root_1 = require("../utils/project-root");
|
|
64
64
|
const pool_1 = require("../workers/pool");
|
|
65
65
|
const index_config_1 = require("./index-config");
|
|
@@ -173,7 +173,8 @@ function initialSync(options) {
|
|
|
173
173
|
}
|
|
174
174
|
projectKeys.clear();
|
|
175
175
|
}
|
|
176
|
-
else if (projectKeys.size > 0 &&
|
|
176
|
+
else if (projectKeys.size > 0 &&
|
|
177
|
+
vectorFileCount < projectKeys.size * 0.8) {
|
|
177
178
|
(0, logger_1.log)("index", `Partial cache detected: ${vectorFileCount} files in vectors vs ${projectKeys.size} in cache — clearing cache to re-embed missing files`);
|
|
178
179
|
for (const key of projectKeys) {
|
|
179
180
|
mc.delete(key);
|
|
@@ -351,13 +352,13 @@ function initialSync(options) {
|
|
|
351
352
|
return; // Broken symlink
|
|
352
353
|
}
|
|
353
354
|
}
|
|
354
|
-
if (!stats.isFile() ||
|
|
355
|
+
if (!stats.isFile() ||
|
|
356
|
+
stats.size === 0 ||
|
|
357
|
+
stats.size > config_1.MAX_FILE_SIZE_BYTES) {
|
|
355
358
|
return;
|
|
356
359
|
}
|
|
357
360
|
// Use absolute path as the key for MetaCache
|
|
358
|
-
const cached = treatAsEmptyCache
|
|
359
|
-
? undefined
|
|
360
|
-
: mc.get(absPath);
|
|
361
|
+
const cached = treatAsEmptyCache ? undefined : mc.get(absPath);
|
|
361
362
|
if (cached &&
|
|
362
363
|
cached.mtimeMs === stats.mtimeMs &&
|
|
363
364
|
cached.size === stats.size) {
|
package/dist/lib/llm/diff.js
CHANGED
|
@@ -11,14 +11,59 @@ const node_child_process_1 = require("node:child_process");
|
|
|
11
11
|
exports.DIFF_MAX_LINES = 500;
|
|
12
12
|
exports.SYMBOL_MAX = 10;
|
|
13
13
|
const KEYWORD_SKIP = new Set([
|
|
14
|
-
"public",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
14
|
+
"public",
|
|
15
|
+
"private",
|
|
16
|
+
"internal",
|
|
17
|
+
"protected",
|
|
18
|
+
"open",
|
|
19
|
+
"final",
|
|
20
|
+
"static",
|
|
21
|
+
"override",
|
|
22
|
+
"class",
|
|
23
|
+
"struct",
|
|
24
|
+
"enum",
|
|
25
|
+
"func",
|
|
26
|
+
"function",
|
|
27
|
+
"def",
|
|
28
|
+
"const",
|
|
29
|
+
"let",
|
|
30
|
+
"var",
|
|
31
|
+
"export",
|
|
32
|
+
"async",
|
|
33
|
+
"await",
|
|
34
|
+
"import",
|
|
35
|
+
"return",
|
|
36
|
+
"if",
|
|
37
|
+
"else",
|
|
38
|
+
"for",
|
|
39
|
+
"while",
|
|
40
|
+
"switch",
|
|
41
|
+
"case",
|
|
42
|
+
"guard",
|
|
43
|
+
"interface",
|
|
44
|
+
"abstract",
|
|
45
|
+
"sealed",
|
|
46
|
+
"data",
|
|
47
|
+
"suspend",
|
|
48
|
+
"inline",
|
|
49
|
+
"typealias",
|
|
50
|
+
"extension",
|
|
51
|
+
"protocol",
|
|
52
|
+
"throws",
|
|
53
|
+
"mutating",
|
|
54
|
+
"nonmutating",
|
|
55
|
+
"convenience",
|
|
56
|
+
"required",
|
|
57
|
+
"weak",
|
|
58
|
+
"unowned",
|
|
59
|
+
"lazy",
|
|
60
|
+
"dynamic",
|
|
61
|
+
"optional",
|
|
62
|
+
"objc",
|
|
63
|
+
"nonisolated",
|
|
64
|
+
"isolated",
|
|
65
|
+
"consuming",
|
|
66
|
+
"borrowing",
|
|
22
67
|
]);
|
|
23
68
|
const DECL_RE = /(?:function|class|struct|enum|interface|func|def)\s+([a-zA-Z_][a-zA-Z0-9_]*)/g;
|
|
24
69
|
const IDENT_RE = /[a-zA-Z_][a-zA-Z0-9_]*/g;
|
|
@@ -122,6 +167,7 @@ function extractSymbols(diff) {
|
|
|
122
167
|
const idents = [];
|
|
123
168
|
let m;
|
|
124
169
|
IDENT_RE.lastIndex = 0;
|
|
170
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex exec loop
|
|
125
171
|
while ((m = IDENT_RE.exec(ctx)) !== null) {
|
|
126
172
|
if (!KEYWORD_SKIP.has(m[0]))
|
|
127
173
|
idents.push(m[0]);
|
|
@@ -134,15 +180,14 @@ function extractSymbols(diff) {
|
|
|
134
180
|
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
135
181
|
DECL_RE.lastIndex = 0;
|
|
136
182
|
let m;
|
|
183
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex exec loop
|
|
137
184
|
while ((m = DECL_RE.exec(line)) !== null) {
|
|
138
185
|
symbols.add(m[1]);
|
|
139
186
|
}
|
|
140
187
|
}
|
|
141
188
|
}
|
|
142
189
|
// Filter short identifiers and cap
|
|
143
|
-
return [...symbols]
|
|
144
|
-
.filter((s) => s.length >= 2)
|
|
145
|
-
.slice(0, exports.SYMBOL_MAX);
|
|
190
|
+
return [...symbols].filter((s) => s.length >= 2).slice(0, exports.SYMBOL_MAX);
|
|
146
191
|
}
|
|
147
192
|
/**
|
|
148
193
|
* Detect languages from file extensions.
|
|
@@ -56,9 +56,7 @@ const config_1 = require("./config");
|
|
|
56
56
|
const prompts_1 = require("./prompts");
|
|
57
57
|
const tools_1 = require("./tools");
|
|
58
58
|
function stripThinkTags(text) {
|
|
59
|
-
return text
|
|
60
|
-
.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/g, "")
|
|
61
|
-
.trim();
|
|
59
|
+
return text.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/g, "").trim();
|
|
62
60
|
}
|
|
63
61
|
function investigate(opts) {
|
|
64
62
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -83,7 +81,12 @@ function investigate(opts) {
|
|
|
83
81
|
const vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
84
82
|
const searcher = new searcher_1.Searcher(vectorDb);
|
|
85
83
|
const graphBuilder = new graph_builder_1.GraphBuilder(vectorDb, projectRoot);
|
|
86
|
-
const ctx = {
|
|
84
|
+
const ctx = {
|
|
85
|
+
vectorDb,
|
|
86
|
+
searcher,
|
|
87
|
+
graphBuilder,
|
|
88
|
+
projectRoot,
|
|
89
|
+
};
|
|
87
90
|
const messages = [
|
|
88
91
|
{ role: "system", content: prompts_1.SYSTEM_PROMPT },
|
|
89
92
|
{ role: "user", content: question },
|
|
@@ -160,7 +163,11 @@ function investigate(opts) {
|
|
|
160
163
|
if (verbose) {
|
|
161
164
|
process.stderr.write(` ${fn.name}() — BLOCKED (limit)\n`);
|
|
162
165
|
}
|
|
163
|
-
messages.push({
|
|
166
|
+
messages.push({
|
|
167
|
+
role: "tool",
|
|
168
|
+
tool_call_id: tc.id,
|
|
169
|
+
content: result,
|
|
170
|
+
});
|
|
164
171
|
continue;
|
|
165
172
|
}
|
|
166
173
|
}
|
package/dist/lib/llm/review.js
CHANGED
|
@@ -49,6 +49,7 @@ exports.reviewCommit = reviewCommit;
|
|
|
49
49
|
const path = __importStar(require("node:path"));
|
|
50
50
|
const openai_1 = __importDefault(require("openai"));
|
|
51
51
|
const graph_builder_1 = require("../graph/graph-builder");
|
|
52
|
+
const risk_1 = require("../review/risk");
|
|
52
53
|
const searcher_1 = require("../search/searcher");
|
|
53
54
|
const vector_db_1 = require("../store/vector-db");
|
|
54
55
|
const project_root_1 = require("../utils/project-root");
|
|
@@ -56,7 +57,6 @@ const config_1 = require("./config");
|
|
|
56
57
|
const diff_1 = require("./diff");
|
|
57
58
|
const report_1 = require("./report");
|
|
58
59
|
const tools_1 = require("./tools");
|
|
59
|
-
const risk_1 = require("../review/risk");
|
|
60
60
|
function reviewCommit(opts) {
|
|
61
61
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62
62
|
var _a, _b, _c, _d;
|
|
@@ -88,13 +88,21 @@ function reviewCommit(opts) {
|
|
|
88
88
|
try {
|
|
89
89
|
const searcher = new searcher_1.Searcher(vectorDb);
|
|
90
90
|
const graphBuilder = new graph_builder_1.GraphBuilder(vectorDb, projectRoot);
|
|
91
|
-
const ctx = {
|
|
91
|
+
const ctx = {
|
|
92
|
+
vectorDb,
|
|
93
|
+
searcher,
|
|
94
|
+
graphBuilder,
|
|
95
|
+
projectRoot,
|
|
96
|
+
};
|
|
92
97
|
// Deterministic risk ranking (Phase 8) — gives the LLM an explicit
|
|
93
98
|
// blast-radius × tests × churn ordering to anchor its judgement, rather
|
|
94
99
|
// than inferring importance from prose alone.
|
|
95
100
|
const [context, riskInputs] = yield Promise.all([
|
|
96
101
|
gatherContext(symbols, changedFiles, ctx, verbose),
|
|
97
|
-
(0, risk_1.gatherRiskInputs)(commitRef, projectRoot, {
|
|
102
|
+
(0, risk_1.gatherRiskInputs)(commitRef, projectRoot, {
|
|
103
|
+
vectorDb,
|
|
104
|
+
graphBuilder,
|
|
105
|
+
}).catch(() => []),
|
|
98
106
|
]);
|
|
99
107
|
contextStr = context;
|
|
100
108
|
const riskRows = (0, risk_1.computeRiskTable)(riskInputs);
|
|
@@ -202,7 +210,11 @@ function gatherContext(symbols, changedFiles, ctx, verbose) {
|
|
|
202
210
|
if (s.status !== "fulfilled")
|
|
203
211
|
continue;
|
|
204
212
|
const { type, result } = s.value;
|
|
205
|
-
if (result.startsWith("(") &&
|
|
213
|
+
if (result.startsWith("(") &&
|
|
214
|
+
(result.includes("not found") ||
|
|
215
|
+
result.includes("error") ||
|
|
216
|
+
result.includes("not indexed") ||
|
|
217
|
+
result.includes("none")))
|
|
206
218
|
continue;
|
|
207
219
|
if (type === "peek")
|
|
208
220
|
peekResults.push(result);
|
|
@@ -356,12 +368,13 @@ ${diff}
|
|
|
356
368
|
// Response parsing
|
|
357
369
|
// ---------------------------------------------------------------------------
|
|
358
370
|
function stripThinkTags(text) {
|
|
359
|
-
return text
|
|
360
|
-
.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/g, "")
|
|
361
|
-
.trim();
|
|
371
|
+
return text.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/g, "").trim();
|
|
362
372
|
}
|
|
363
373
|
function parseFindings(content) {
|
|
364
|
-
const empty = {
|
|
374
|
+
const empty = {
|
|
375
|
+
findings: [],
|
|
376
|
+
summary: "Parse error — could not extract findings from model output.",
|
|
377
|
+
};
|
|
365
378
|
if (!content)
|
|
366
379
|
return empty;
|
|
367
380
|
// Strip think tags and markdown fences
|
package/dist/lib/llm/server.js
CHANGED
|
@@ -85,7 +85,9 @@ class LlmServer {
|
|
|
85
85
|
const runningModel = (_b = (_a = body === null || body === void 0 ? void 0 : body.data) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id;
|
|
86
86
|
if (runningModel) {
|
|
87
87
|
const configBasename = path.basename(this.config.model);
|
|
88
|
-
if (runningModel !== configBasename &&
|
|
88
|
+
if (runningModel !== configBasename &&
|
|
89
|
+
!configBasename.includes(runningModel) &&
|
|
90
|
+
!runningModel.includes(configBasename)) {
|
|
89
91
|
console.log(`[llm] Model mismatch: running "${runningModel}" but config expects "${configBasename}" — will restart`);
|
|
90
92
|
resolve(false);
|
|
91
93
|
return;
|
|
@@ -142,11 +144,16 @@ class LlmServer {
|
|
|
142
144
|
}
|
|
143
145
|
const logFd = (0, log_rotate_1.openRotatedLog)(config_1.PATHS.llmLogFile);
|
|
144
146
|
const child = (0, node_child_process_1.spawn)(binary, [
|
|
145
|
-
"-m",
|
|
146
|
-
|
|
147
|
-
"--
|
|
148
|
-
|
|
149
|
-
"--
|
|
147
|
+
"-m",
|
|
148
|
+
this.config.model,
|
|
149
|
+
"--host",
|
|
150
|
+
this.config.host,
|
|
151
|
+
"--port",
|
|
152
|
+
String(this.config.port),
|
|
153
|
+
"-ngl",
|
|
154
|
+
String(this.config.ngl),
|
|
155
|
+
"--ctx-size",
|
|
156
|
+
String(this.config.ctxSize),
|
|
150
157
|
], { detached: true, stdio: ["ignore", logFd, logFd] });
|
|
151
158
|
child.unref();
|
|
152
159
|
fs.closeSync(logFd);
|
|
@@ -256,7 +263,9 @@ class LlmServer {
|
|
|
256
263
|
pid: alive ? pid : null,
|
|
257
264
|
port: this.config.port,
|
|
258
265
|
model: this.config.model,
|
|
259
|
-
uptime: alive && this.startTime
|
|
266
|
+
uptime: alive && this.startTime
|
|
267
|
+
? Math.floor((Date.now() - this.startTime) / 1000)
|
|
268
|
+
: 0,
|
|
260
269
|
};
|
|
261
270
|
}
|
|
262
271
|
startIdleWatchdog() {
|
|
@@ -102,9 +102,31 @@ function firstSignatureLine(chunk) {
|
|
|
102
102
|
return "";
|
|
103
103
|
}
|
|
104
104
|
const QUERY_STOPWORDS = new Set([
|
|
105
|
-
"the",
|
|
106
|
-
"
|
|
107
|
-
"
|
|
105
|
+
"the",
|
|
106
|
+
"and",
|
|
107
|
+
"for",
|
|
108
|
+
"with",
|
|
109
|
+
"that",
|
|
110
|
+
"this",
|
|
111
|
+
"from",
|
|
112
|
+
"into",
|
|
113
|
+
"where",
|
|
114
|
+
"when",
|
|
115
|
+
"how",
|
|
116
|
+
"what",
|
|
117
|
+
"does",
|
|
118
|
+
"not",
|
|
119
|
+
"are",
|
|
120
|
+
"was",
|
|
121
|
+
"has",
|
|
122
|
+
"have",
|
|
123
|
+
"its",
|
|
124
|
+
"all",
|
|
125
|
+
"can",
|
|
126
|
+
"use",
|
|
127
|
+
"uses",
|
|
128
|
+
"using",
|
|
129
|
+
"code",
|
|
108
130
|
]);
|
|
109
131
|
function extractQueryTerms(query) {
|
|
110
132
|
if (!query)
|
|
@@ -14,7 +14,7 @@ exports.formatIndexStateFooter = formatIndexStateFooter;
|
|
|
14
14
|
* while results may actually be incomplete.
|
|
15
15
|
*/
|
|
16
16
|
function formatIndexStateFooter(state, opts) {
|
|
17
|
-
if (!state ||
|
|
17
|
+
if (!(state === null || state === void 0 ? void 0 : state.indexing))
|
|
18
18
|
return null;
|
|
19
19
|
const count = state.pendingFiles > 0 ? `~${state.pendingFiles} files pending` : null;
|
|
20
20
|
if (opts.agent) {
|
package/dist/lib/review/risk.js
CHANGED
|
@@ -40,9 +40,7 @@ function computeRiskTable(inputs) {
|
|
|
40
40
|
/** Render the ranking — TSV-ish for agents, an aligned table for humans. */
|
|
41
41
|
function formatRiskTable(rows, opts) {
|
|
42
42
|
if (rows.length === 0) {
|
|
43
|
-
return opts.agent
|
|
44
|
-
? "(no changed symbols)"
|
|
45
|
-
: "No changed symbols to rank.";
|
|
43
|
+
return opts.agent ? "(no changed symbols)" : "No changed symbols to rank.";
|
|
46
44
|
}
|
|
47
45
|
if (opts.agent) {
|
|
48
46
|
return rows
|
|
@@ -70,7 +68,7 @@ function gatherRiskInputs(ref, projectRoot, deps) {
|
|
|
70
68
|
if (symbols.length === 0)
|
|
71
69
|
return [];
|
|
72
70
|
const root = projectRoot.endsWith("/") ? projectRoot : `${projectRoot}/`;
|
|
73
|
-
const relativize = (f) =>
|
|
71
|
+
const relativize = (f) => f.startsWith(root) ? f.slice(root.length) : f;
|
|
74
72
|
const inputs = yield Promise.all(symbols.map((symbol) => __awaiter(this, void 0, void 0, function* () {
|
|
75
73
|
var _a, _b;
|
|
76
74
|
const [callers, loc, tests] = yield Promise.all([
|