grepmax 0.23.0 → 0.25.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/.claude-plugin/marketplace.json +1 -1
- package/README.md +25 -6
- package/dist/commands/add.js +38 -31
- package/dist/commands/config.js +16 -15
- package/dist/commands/context.js +38 -13
- package/dist/commands/doctor.js +76 -83
- package/dist/commands/extract.js +12 -1
- package/dist/commands/impact.js +33 -1
- package/dist/commands/index.js +23 -24
- package/dist/commands/list.js +23 -14
- package/dist/commands/mcp.js +494 -162
- package/dist/commands/peek.js +16 -5
- package/dist/commands/repair.js +54 -120
- package/dist/commands/search-output.js +30 -9
- package/dist/commands/search-run.js +75 -47
- package/dist/commands/search-skeletons.js +28 -18
- package/dist/commands/search.js +45 -49
- package/dist/commands/serve.js +415 -373
- package/dist/commands/setup.js +2 -2
- package/dist/commands/similar.js +5 -5
- package/dist/commands/skeleton.js +67 -41
- package/dist/commands/status.js +5 -2
- package/dist/commands/summarize.js +6 -0
- package/dist/commands/surprises.js +150 -0
- package/dist/commands/watch.js +102 -38
- package/dist/config.js +3 -0
- package/dist/eval-surprising-connections.js +191 -0
- package/dist/index.js +2 -0
- package/dist/lib/analysis/surprising-connections.js +600 -0
- package/dist/lib/daemon/daemon.js +1101 -379
- package/dist/lib/daemon/ipc-handler.js +122 -13
- package/dist/lib/daemon/mlx-server-manager.js +268 -125
- package/dist/lib/daemon/process-manager.js +7 -4
- package/dist/lib/daemon/search-handler.js +23 -9
- package/dist/lib/daemon/watcher-manager.js +353 -110
- package/dist/lib/graph/impact-rollup.js +202 -0
- package/dist/lib/graph/impact.js +15 -1
- package/dist/lib/help/agent-cheatsheet.js +1 -0
- package/dist/lib/index/batch-processor.js +231 -67
- package/dist/lib/index/embedding-generation.js +109 -0
- package/dist/lib/index/embedding-status.js +23 -0
- package/dist/lib/index/file-policy.js +273 -0
- package/dist/lib/index/ignore-patterns.js +4 -0
- package/dist/lib/index/index-config.js +18 -4
- package/dist/lib/index/syncer.js +256 -79
- package/dist/lib/index/walker.js +66 -86
- package/dist/lib/index/watcher-batch.js +9 -0
- package/dist/lib/index/watcher.js +129 -3
- package/dist/lib/llm/server.js +6 -0
- package/dist/lib/search/searcher.js +30 -19
- package/dist/lib/skeleton/skeletonizer.js +118 -0
- package/dist/lib/skeleton/summary-formatter.js +8 -1
- package/dist/lib/store/store-lease.js +473 -0
- package/dist/lib/store/vector-db.js +302 -57
- package/dist/lib/utils/blocked-roots.js +63 -0
- package/dist/lib/utils/cross-project.js +7 -3
- package/dist/lib/utils/daemon-client.js +24 -1
- package/dist/lib/utils/daemon-launcher.js +38 -13
- package/dist/lib/utils/doctor-status.js +76 -0
- package/dist/lib/utils/file-utils.js +74 -4
- package/dist/lib/utils/keyed-mutex.js +101 -0
- package/dist/lib/utils/logger.js +57 -1
- package/dist/lib/utils/mlx-hf-cache.js +114 -0
- package/dist/lib/utils/operation-coordinator.js +146 -0
- package/dist/lib/utils/path-containment.js +106 -0
- package/dist/lib/utils/process.js +44 -0
- package/dist/lib/utils/project-registry.js +351 -3
- package/dist/lib/utils/scope-filter.js +3 -9
- package/dist/lib/utils/stale-hint.js +12 -19
- package/dist/lib/utils/watcher-launcher.js +5 -1
- package/dist/lib/utils/watcher-store.js +2 -2
- package/dist/lib/workers/colbert-math.js +15 -12
- package/dist/lib/workers/embeddings/colbert.js +3 -2
- package/dist/lib/workers/embeddings/granite.js +4 -3
- package/dist/lib/workers/embeddings/mlx-client.js +59 -16
- package/dist/lib/workers/orchestrator.js +39 -8
- package/dist/lib/workers/pool.js +150 -83
- package/dist/lib/workers/process-child.js +11 -2
- package/dist/lib/workers/serialized-handler.js +10 -0
- package/dist/lib/workers/worker.js +13 -4
- package/mlx-embed-server/server.py +21 -3
- package/mlx-embed-server/summarizer.py +8 -0
- package/package.json +6 -3
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/hooks/start.js +3 -170
package/dist/commands/peek.js
CHANGED
|
@@ -52,6 +52,7 @@ const agent_errors_1 = require("../lib/utils/agent-errors");
|
|
|
52
52
|
const exit_1 = require("../lib/utils/exit");
|
|
53
53
|
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
54
54
|
const language_1 = require("../lib/utils/language");
|
|
55
|
+
const path_containment_1 = require("../lib/utils/path-containment");
|
|
55
56
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
56
57
|
const project_root_1 = require("../lib/utils/project-root");
|
|
57
58
|
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
@@ -65,9 +66,9 @@ const style = {
|
|
|
65
66
|
};
|
|
66
67
|
const MAX_CALLERS = 5;
|
|
67
68
|
const MAX_CALLEES = 8;
|
|
68
|
-
function extractSignature(filePath, startLine, endLine) {
|
|
69
|
+
function extractSignature(projectRoot, filePath, startLine, endLine) {
|
|
69
70
|
try {
|
|
70
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
71
|
+
const content = fs.readFileSync((0, path_containment_1.resolveContainedFile)(projectRoot, filePath), "utf-8");
|
|
71
72
|
const lines = content.split("\n");
|
|
72
73
|
const chunk = lines.slice(startLine, endLine + 1);
|
|
73
74
|
const bodyLines = chunk.length;
|
|
@@ -249,7 +250,17 @@ exports.peek = new commander_1.Command("peek")
|
|
|
249
250
|
// Re-anchor chunk-level caller rows to actual call sites and dedupe —
|
|
250
251
|
// getCallers() returns one row per chunk, which multiplies callers for
|
|
251
252
|
// classes split across many chunks (verified: 3 real call sites → 66).
|
|
252
|
-
const
|
|
253
|
+
const readableCallers = callerList.flatMap((caller) => {
|
|
254
|
+
try {
|
|
255
|
+
return [
|
|
256
|
+
Object.assign(Object.assign({}, caller), { file: (0, path_containment_1.resolveContainedFile)(projectRoot, caller.file) }),
|
|
257
|
+
];
|
|
258
|
+
}
|
|
259
|
+
catch (_a) {
|
|
260
|
+
return [];
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
const resolvedCallers = (0, callsites_1.resolveCallSites)(readableCallers, symbol).map((c) => {
|
|
253
264
|
var _a;
|
|
254
265
|
return ({
|
|
255
266
|
symbol: c.symbol,
|
|
@@ -294,7 +305,7 @@ exports.peek = new commander_1.Command("peek")
|
|
|
294
305
|
}
|
|
295
306
|
// Signature — all lines up to the opening brace, collapsed to one
|
|
296
307
|
// line so parameters survive (first-line-only loses them).
|
|
297
|
-
const { signatureOnly } = extractSignature(center.file, startLine, endLine);
|
|
308
|
+
const { signatureOnly } = extractSignature(projectRoot, center.file, startLine, endLine);
|
|
298
309
|
const sigOnly = signatureOnly
|
|
299
310
|
.split("\n")
|
|
300
311
|
.map((l) => l.trim())
|
|
@@ -340,7 +351,7 @@ exports.peek = new commander_1.Command("peek")
|
|
|
340
351
|
}
|
|
341
352
|
console.log();
|
|
342
353
|
// Signature with collapsed body
|
|
343
|
-
const { signature } = extractSignature(center.file, startLine, endLine);
|
|
354
|
+
const { signature } = extractSignature(projectRoot, center.file, startLine, endLine);
|
|
344
355
|
for (const line of signature.split("\n")) {
|
|
345
356
|
console.log(` ${line}`);
|
|
346
357
|
}
|
package/dist/commands/repair.js
CHANGED
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -41,50 +8,78 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
41
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
9
|
});
|
|
43
10
|
};
|
|
44
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
-
};
|
|
47
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
12
|
exports.repair = void 0;
|
|
49
|
-
const readline = __importStar(require("node:readline"));
|
|
50
13
|
const commander_1 = require("commander");
|
|
51
|
-
const ora_1 = __importDefault(require("ora"));
|
|
52
14
|
const config_1 = require("../config");
|
|
53
15
|
const index_config_1 = require("../lib/index/index-config");
|
|
54
16
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
17
|
+
const daemon_client_1 = require("../lib/utils/daemon-client");
|
|
55
18
|
const exit_1 = require("../lib/utils/exit");
|
|
56
19
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
57
|
-
|
|
58
|
-
const rl = readline.createInterface({
|
|
59
|
-
input: process.stdin,
|
|
60
|
-
output: process.stdout,
|
|
61
|
-
});
|
|
62
|
-
return new Promise((resolve) => {
|
|
63
|
-
rl.question(`${message} [y/N] `, (answer) => {
|
|
64
|
-
rl.close();
|
|
65
|
-
resolve(answer.toLowerCase() === "y");
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
}
|
|
20
|
+
const REBUILD_PROTOCOL = 1;
|
|
69
21
|
exports.repair = new commander_1.Command("repair")
|
|
70
22
|
.description("Repair the centralized index (recover from a schema mismatch)")
|
|
71
|
-
.option("--rebuild", "
|
|
72
|
-
.option("-y, --yes", "Skip the confirmation prompt", false)
|
|
23
|
+
.option("--rebuild", "Run the guarded exclusive whole-corpus generation rebuild", false)
|
|
73
24
|
.addHelpText("after", `
|
|
74
25
|
The shared LanceDB \`chunks\` table is fixed-width at creation. Switching model
|
|
75
26
|
tiers (e.g. small 384d -> standard 768d) strands the table at the old width, so
|
|
76
27
|
every write then fails. A per-project \`gmax index --reset\` only deletes rows —
|
|
77
|
-
it can't change the table width.
|
|
78
|
-
|
|
28
|
+
it can't change the table width. The guarded rebuild runs only through a daemon
|
|
29
|
+
that advertises the exclusive-generation protocol; it never falls back to local
|
|
30
|
+
store access.
|
|
79
31
|
|
|
80
32
|
Examples:
|
|
81
|
-
gmax repair Show schema status
|
|
82
|
-
gmax repair --rebuild
|
|
83
|
-
gmax repair --rebuild -y Rebuild without the confirmation prompt
|
|
33
|
+
gmax repair Show schema status
|
|
34
|
+
gmax repair --rebuild Rebuild every registered project at configured width
|
|
84
35
|
`)
|
|
85
36
|
.action((opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
86
37
|
var _a, _b, _c;
|
|
87
38
|
try {
|
|
39
|
+
if (opts.rebuild) {
|
|
40
|
+
const running = yield (0, daemon_client_1.ensureDaemonRunning)();
|
|
41
|
+
if (!running)
|
|
42
|
+
throw new Error("failed to start the gmax daemon");
|
|
43
|
+
const ping = yield (0, daemon_client_1.sendDaemonCommand)({ cmd: "ping" }, { timeoutMs: 10000 });
|
|
44
|
+
const capabilities = ping.capabilities && typeof ping.capabilities === "object"
|
|
45
|
+
? ping.capabilities
|
|
46
|
+
: null;
|
|
47
|
+
if (!ping.ok ||
|
|
48
|
+
(capabilities === null || capabilities === void 0 ? void 0 : capabilities.exclusiveGenerationRebuild) !== REBUILD_PROTOCOL) {
|
|
49
|
+
throw new Error("running daemon does not support guarded rebuild protocol v1; restart the gmax daemon and retry");
|
|
50
|
+
}
|
|
51
|
+
const done = yield (0, daemon_client_1.sendStreamingCommand)({ cmd: "repair-v2", protocol: REBUILD_PROTOCOL }, (progress) => {
|
|
52
|
+
var _a;
|
|
53
|
+
const phase = String((_a = progress.phase) !== null && _a !== void 0 ? _a : "rebuild");
|
|
54
|
+
const project = typeof progress.project === "string"
|
|
55
|
+
? ` ${progress.project}`
|
|
56
|
+
: "";
|
|
57
|
+
const counts = typeof progress.processed === "number" &&
|
|
58
|
+
typeof progress.total === "number"
|
|
59
|
+
? ` ${progress.processed}/${progress.total}`
|
|
60
|
+
: "";
|
|
61
|
+
const message = typeof progress.message === "string"
|
|
62
|
+
? `: ${progress.message}`
|
|
63
|
+
: "";
|
|
64
|
+
console.log(`[${phase}]${project}${counts}${message}`);
|
|
65
|
+
}, { timeoutMs: 24 * 60 * 60 * 1000 });
|
|
66
|
+
if (!done.ok) {
|
|
67
|
+
const blockers = Array.isArray(done.blockers)
|
|
68
|
+
? ` Blockers: ${done.blockers
|
|
69
|
+
.map((owner) => {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const value = owner;
|
|
72
|
+
return `${(_a = value.role) !== null && _a !== void 0 ? _a : "unknown"} pid=${(_b = value.pid) !== null && _b !== void 0 ? _b : "?"}`;
|
|
73
|
+
})
|
|
74
|
+
.join(", ")}.`
|
|
75
|
+
: "";
|
|
76
|
+
throw new Error(`${String((_a = done.error) !== null && _a !== void 0 ? _a : "rebuild failed")}.${blockers}`);
|
|
77
|
+
}
|
|
78
|
+
console.log(`Rebuild complete: ${String((_b = done.completed) !== null && _b !== void 0 ? _b : 0)}/${String((_c = done.total) !== null && _c !== void 0 ? _c : 0)} projects indexed.`);
|
|
79
|
+
if (typeof done.warning === "string")
|
|
80
|
+
console.warn(done.warning);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
88
83
|
const globalConfig = (0, index_config_1.readGlobalConfig)();
|
|
89
84
|
const configDim = globalConfig.vectorDim;
|
|
90
85
|
// Physical width of the on-disk table (null if no table yet). Opened
|
|
@@ -106,74 +101,13 @@ Examples:
|
|
|
106
101
|
console.log(dimLine);
|
|
107
102
|
if (!opts.rebuild) {
|
|
108
103
|
if (physicalDim != null && physicalDim !== configDim) {
|
|
109
|
-
console.log(`\nRun
|
|
110
|
-
`${projects.length} project(s) at ${configDim}d.`);
|
|
104
|
+
console.log(`\nRun ${config_1.REBUILD_COMMAND} to rebuild ${projects.length} project(s) at ${configDim}d.`);
|
|
111
105
|
}
|
|
112
106
|
else {
|
|
113
|
-
console.log(
|
|
114
|
-
}
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (projects.length === 0) {
|
|
118
|
-
console.log("\nNo indexed projects to rebuild.");
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
const totalChunks = projects.reduce((sum, p) => { var _a; return sum + ((_a = p.chunkCount) !== null && _a !== void 0 ? _a : 0); }, 0);
|
|
122
|
-
console.log(`\nThis will DROP the shared vector table and re-embed ${projects.length} project(s)` +
|
|
123
|
-
(totalChunks > 0
|
|
124
|
-
? ` (~${totalChunks.toLocaleString()} chunks).`
|
|
125
|
-
: "."));
|
|
126
|
-
for (const p of projects) {
|
|
127
|
-
console.log(` - ${p.name}`);
|
|
128
|
-
}
|
|
129
|
-
if (!opts.yes) {
|
|
130
|
-
const ok = yield confirm("\nContinue?");
|
|
131
|
-
if (!ok) {
|
|
132
|
-
console.log("Cancelled.");
|
|
133
|
-
return;
|
|
107
|
+
console.log("\nNo schema mismatch detected.");
|
|
134
108
|
}
|
|
135
|
-
}
|
|
136
|
-
// The rebuild must run through the daemon — it is the single writer for
|
|
137
|
-
// the shared table. Refuse rather than risk a torn drop alongside a
|
|
138
|
-
// daemon mid-flush.
|
|
139
|
-
const { ensureDaemonRunning, sendStreamingCommand } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/daemon-client")));
|
|
140
|
-
if (!(yield ensureDaemonRunning())) {
|
|
141
|
-
console.error("Could not start the gmax daemon. Start it with 'gmax watch --daemon -b' and retry.");
|
|
142
|
-
process.exitCode = 1;
|
|
143
109
|
return;
|
|
144
110
|
}
|
|
145
|
-
const spinner = (0, ora_1.default)({
|
|
146
|
-
text: "Dropping vector table...",
|
|
147
|
-
isSilent: !process.stdout.isTTY,
|
|
148
|
-
}).start();
|
|
149
|
-
try {
|
|
150
|
-
const done = yield sendStreamingCommand({ cmd: "repair" }, (msg) => {
|
|
151
|
-
var _a, _b, _c, _d;
|
|
152
|
-
if (msg.phase === "drop") {
|
|
153
|
-
spinner.text = "Dropping vector table...";
|
|
154
|
-
}
|
|
155
|
-
else if (msg.phase === "reindex") {
|
|
156
|
-
const doneN = (_a = msg.projectsDone) !== null && _a !== void 0 ? _a : 0;
|
|
157
|
-
const totalN = (_b = msg.projectsTotal) !== null && _b !== void 0 ? _b : projects.length;
|
|
158
|
-
const processed = (_c = msg.processed) !== null && _c !== void 0 ? _c : 0;
|
|
159
|
-
const total = (_d = msg.total) !== null && _d !== void 0 ? _d : 0;
|
|
160
|
-
const counts = total > 0 ? ` ${processed}/${total}` : "";
|
|
161
|
-
spinner.text = `Re-indexing ${msg.project} (${doneN + 1}/${totalN})${counts}`;
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
if (!done.ok) {
|
|
165
|
-
spinner.fail("Rebuild failed");
|
|
166
|
-
throw new Error((_a = done.error) !== null && _a !== void 0 ? _a : "daemon repair failed");
|
|
167
|
-
}
|
|
168
|
-
const rebuilt = (_b = done.projects) !== null && _b !== void 0 ? _b : 0;
|
|
169
|
-
const indexed = (_c = done.indexed) !== null && _c !== void 0 ? _c : 0;
|
|
170
|
-
spinner.succeed(`Rebuilt ${rebuilt} project(s) at ${configDim}d • ${indexed.toLocaleString()} chunks`);
|
|
171
|
-
}
|
|
172
|
-
catch (e) {
|
|
173
|
-
if (spinner.isSpinning)
|
|
174
|
-
spinner.fail("Rebuild failed");
|
|
175
|
-
throw e;
|
|
176
|
-
}
|
|
177
111
|
}
|
|
178
112
|
catch (error) {
|
|
179
113
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -51,6 +51,7 @@ const index_state_footer_1 = require("../lib/output/index-state-footer");
|
|
|
51
51
|
const cross_project_1 = require("../lib/utils/cross-project");
|
|
52
52
|
const formatter_1 = require("../lib/utils/formatter");
|
|
53
53
|
const import_extractor_1 = require("../lib/utils/import-extractor");
|
|
54
|
+
const path_containment_1 = require("../lib/utils/path-containment");
|
|
54
55
|
const search_skeletons_1 = require("./search-skeletons");
|
|
55
56
|
/**
|
|
56
57
|
* Standalone HTTP-server search path. The per-project server answers the query
|
|
@@ -70,7 +71,7 @@ function executeServerSearch(params) {
|
|
|
70
71
|
return __awaiter(this, void 0, void 0, function* () {
|
|
71
72
|
const { server, pattern, exec_path, projectRootForServer, options, minScore, } = params;
|
|
72
73
|
try {
|
|
73
|
-
const response = yield fetch(`http://
|
|
74
|
+
const response = yield fetch(`http://127.0.0.1:${server.port}/search`, {
|
|
74
75
|
method: "POST",
|
|
75
76
|
headers: { "Content-Type": "application/json" },
|
|
76
77
|
body: JSON.stringify({
|
|
@@ -79,6 +80,11 @@ function executeServerSearch(params) {
|
|
|
79
80
|
path: exec_path
|
|
80
81
|
? path.relative(projectRootForServer, path.resolve(exec_path))
|
|
81
82
|
: undefined,
|
|
83
|
+
in: options.in,
|
|
84
|
+
exclude: options.exclude,
|
|
85
|
+
file: options.file,
|
|
86
|
+
lang: options.lang,
|
|
87
|
+
role: options.role,
|
|
82
88
|
}),
|
|
83
89
|
});
|
|
84
90
|
if (response.ok) {
|
|
@@ -119,8 +125,15 @@ function executeServerSearch(params) {
|
|
|
119
125
|
}
|
|
120
126
|
if (options.agent) {
|
|
121
127
|
const importCache = new Map();
|
|
122
|
-
const getImportsForFile = (
|
|
128
|
+
const getImportsForFile = (indexedPath) => {
|
|
123
129
|
var _a;
|
|
130
|
+
let absPath;
|
|
131
|
+
try {
|
|
132
|
+
absPath = (0, path_containment_1.resolveContainedFile)(projectRootForServer, indexedPath);
|
|
133
|
+
}
|
|
134
|
+
catch (_b) {
|
|
135
|
+
return "";
|
|
136
|
+
}
|
|
124
137
|
if (!options.imports || !absPath)
|
|
125
138
|
return "";
|
|
126
139
|
if (!importCache.has(absPath)) {
|
|
@@ -212,15 +225,23 @@ function renderSearchOutput(params) {
|
|
|
212
225
|
}
|
|
213
226
|
// Build import cache when --imports is requested
|
|
214
227
|
const importCache = new Map();
|
|
215
|
-
const
|
|
228
|
+
const getImportsForRoot = (root) => (indexedPath) => {
|
|
216
229
|
var _a;
|
|
217
|
-
if (!options.imports || !
|
|
230
|
+
if (!options.imports || !indexedPath)
|
|
231
|
+
return "";
|
|
232
|
+
let absPath;
|
|
233
|
+
try {
|
|
234
|
+
absPath = (0, path_containment_1.resolveContainedFile)(root, indexedPath);
|
|
235
|
+
}
|
|
236
|
+
catch (_b) {
|
|
218
237
|
return "";
|
|
238
|
+
}
|
|
219
239
|
if (!importCache.has(absPath)) {
|
|
220
240
|
importCache.set(absPath, (0, import_extractor_1.extractImports)(absPath));
|
|
221
241
|
}
|
|
222
242
|
return (_a = importCache.get(absPath)) !== null && _a !== void 0 ? _a : "";
|
|
223
243
|
};
|
|
244
|
+
const getImportsForFile = getImportsForRoot(effectiveRoot);
|
|
224
245
|
// Agent mode: ultra-compact one-line-per-result output
|
|
225
246
|
const resultCount = filteredData.length;
|
|
226
247
|
// Cross-project (Phase 6): render grouped by owning project so idioms
|
|
@@ -259,7 +280,7 @@ function renderSearchOutput(params) {
|
|
|
259
280
|
body = (0, agent_search_formatter_1.formatAgentSearchResults)(g.items, g.root, {
|
|
260
281
|
includeImports: options.imports,
|
|
261
282
|
query: pattern,
|
|
262
|
-
getImportsForFile,
|
|
283
|
+
getImportsForFile: getImportsForRoot(g.root),
|
|
263
284
|
explain: options.explain,
|
|
264
285
|
});
|
|
265
286
|
}
|
|
@@ -377,12 +398,10 @@ function renderSearchOutput(params) {
|
|
|
377
398
|
// aborting the loop — recovering budget the old greedy `break` wasted.
|
|
378
399
|
const candidates = filteredData.map((r, idx) => {
|
|
379
400
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
380
|
-
const
|
|
401
|
+
const indexedPath = (_c = (_a = r.path) !== null && _a !== void 0 ? _a : (_b = r.metadata) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : "";
|
|
381
402
|
const startLine = (_g = (_e = (_d = r.startLine) !== null && _d !== void 0 ? _d : r.start_line) !== null && _e !== void 0 ? _e : (_f = r.generated_metadata) === null || _f === void 0 ? void 0 : _f.start_line) !== null && _g !== void 0 ? _g : 0;
|
|
382
403
|
const endLine = (_l = (_j = (_h = r.endLine) !== null && _h !== void 0 ? _h : r.end_line) !== null && _j !== void 0 ? _j : (_k = r.generated_metadata) === null || _k === void 0 ? void 0 : _k.end_line) !== null && _l !== void 0 ? _l : startLine;
|
|
383
|
-
|
|
384
|
-
? absP.slice(projectRoot.length + 1)
|
|
385
|
-
: absP;
|
|
404
|
+
let relPath = "(invalid indexed path)";
|
|
386
405
|
const role = r.role || "IMPLEMENTATION";
|
|
387
406
|
const symbol = Array.isArray(r.defined_symbols) &&
|
|
388
407
|
r.defined_symbols.length > 0
|
|
@@ -390,6 +409,8 @@ function renderSearchOutput(params) {
|
|
|
390
409
|
: "";
|
|
391
410
|
let blobText;
|
|
392
411
|
try {
|
|
412
|
+
const absP = (0, path_containment_1.resolveContainedFile)(projectRoot, indexedPath);
|
|
413
|
+
relPath = path.relative(fs.realpathSync(projectRoot), absP);
|
|
393
414
|
const content = fs.readFileSync(absP, "utf-8");
|
|
394
415
|
const allLines = content.split("\n");
|
|
395
416
|
const body = allLines
|
|
@@ -42,15 +42,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.shouldFallbackFromDaemonError = shouldFallbackFromDaemonError;
|
|
45
46
|
exports.runSearch = runSearch;
|
|
46
47
|
const path = __importStar(require("node:path"));
|
|
47
48
|
const config_1 = require("../config");
|
|
49
|
+
const embedding_status_1 = require("../lib/index/embedding-status");
|
|
48
50
|
const grammar_loader_1 = require("../lib/index/grammar-loader");
|
|
51
|
+
const index_config_1 = require("../lib/index/index-config");
|
|
49
52
|
const sync_helpers_1 = require("../lib/index/sync-helpers");
|
|
50
53
|
const syncer_1 = require("../lib/index/syncer");
|
|
51
54
|
const searcher_1 = require("../lib/search/searcher");
|
|
52
55
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
53
56
|
const lock_1 = require("../lib/utils/lock");
|
|
57
|
+
const project_registry_1 = require("../lib/utils/project-registry");
|
|
58
|
+
const DAEMON_FALLBACK_ERRORS = new Set(["ENOENT", "ECONNREFUSED"]);
|
|
59
|
+
function shouldFallbackFromDaemonError(error) {
|
|
60
|
+
return typeof error === "string" && DAEMON_FALLBACK_ERRORS.has(error);
|
|
61
|
+
}
|
|
54
62
|
/**
|
|
55
63
|
* Acquire search results, picking the path: daemon-mediated first (ships the
|
|
56
64
|
* query over IPC to the already-warm daemon), in-process fallback otherwise
|
|
@@ -68,48 +76,65 @@ function runSearch(params) {
|
|
|
68
76
|
// caller for closing after render, or (b) closed here if indexing throws.
|
|
69
77
|
let openedDb = null;
|
|
70
78
|
try {
|
|
79
|
+
const selectedRoots = Array.isArray(searchFilters.projectRoots)
|
|
80
|
+
? new Set(searchFilters.projectRoots)
|
|
81
|
+
: new Set([projectRoot]);
|
|
82
|
+
(0, embedding_status_1.assertEmbeddingSearchCompatible)((0, project_registry_1.listProjects)().filter((project) => selectedRoots.has(project.root)), (0, index_config_1.readGlobalConfig)());
|
|
71
83
|
// Daemon-mediated search: ships query+args over IPC, daemon runs the
|
|
72
84
|
// hybrid+rerank against its already-warm VectorDB and worker pool.
|
|
73
85
|
// Drops cold-start cost (~17s wall, 6GB RAM in the CLI) to <1s. Falls
|
|
74
|
-
// back to in-process
|
|
86
|
+
// back to in-process only when no daemon socket is available. A live daemon
|
|
87
|
+
// error (busy, rebuilding, timeout, protocol, scope, store failure) must not
|
|
88
|
+
// open the shared store concurrently.
|
|
75
89
|
let searchResult = null;
|
|
76
90
|
let precomputedSkeletons;
|
|
77
91
|
let precomputedGraph;
|
|
78
92
|
let indexState;
|
|
79
93
|
if (!options.sync && !options.dryRun) {
|
|
80
94
|
try {
|
|
81
|
-
const {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
95
|
+
const { sendDaemonCommand } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/daemon-client")));
|
|
96
|
+
const crossProject = Array.isArray(searchFilters.projectRoots);
|
|
97
|
+
const resp = yield sendDaemonCommand({
|
|
98
|
+
cmd: crossProject ? "search-v2" : "search",
|
|
99
|
+
projectRoot: effectiveRoot,
|
|
100
|
+
query: pattern,
|
|
101
|
+
limit: parseInt(options.m, 10),
|
|
102
|
+
filters: Object.keys(searchFilters).length > 0 ? searchFilters : undefined,
|
|
103
|
+
pathPrefix: pathFilter,
|
|
104
|
+
rerank: process.env.GMAX_RERANK === "1",
|
|
105
|
+
explain: options.explain,
|
|
106
|
+
seeds,
|
|
107
|
+
includeSkeletons: options.skeleton,
|
|
108
|
+
includeGraph: options.symbol,
|
|
109
|
+
}, { timeoutMs: 60000 });
|
|
110
|
+
if (resp.ok) {
|
|
111
|
+
searchResult = {
|
|
112
|
+
data: resp.data,
|
|
113
|
+
warnings: resp.warnings,
|
|
114
|
+
};
|
|
115
|
+
precomputedSkeletons = resp.skeletons;
|
|
116
|
+
precomputedGraph = resp.graph;
|
|
117
|
+
indexState = resp.indexState;
|
|
118
|
+
}
|
|
119
|
+
else if (!shouldFallbackFromDaemonError(resp.error)) {
|
|
120
|
+
const detail = typeof resp.hint === "string"
|
|
121
|
+
? `: ${resp.hint}`
|
|
122
|
+
: typeof resp.error === "string"
|
|
123
|
+
? `: ${resp.error}`
|
|
124
|
+
: "";
|
|
125
|
+
throw new Error(`Daemon search failed${detail}`);
|
|
126
|
+
}
|
|
127
|
+
else if (process.env.GMAX_DEBUG === "1") {
|
|
128
|
+
console.error(`[search] daemon path unavailable: ${(_a = resp.error) !== null && _a !== void 0 ? _a : "unknown"}`);
|
|
110
129
|
}
|
|
111
130
|
}
|
|
112
131
|
catch (err) {
|
|
132
|
+
const code = err === null || err === void 0 ? void 0 : err.code;
|
|
133
|
+
if ((err instanceof Error &&
|
|
134
|
+
err.message.startsWith("Daemon search failed")) ||
|
|
135
|
+
!shouldFallbackFromDaemonError(code)) {
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
113
138
|
if (process.env.GMAX_DEBUG === "1") {
|
|
114
139
|
console.error("[search] daemon attempt threw:", err);
|
|
115
140
|
}
|
|
@@ -176,23 +201,26 @@ function runSearch(params) {
|
|
|
176
201
|
return { kind: "dry-run", vectorDb: openedDb };
|
|
177
202
|
}
|
|
178
203
|
yield vectorDb.createFTSIndex();
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
204
|
+
if (result.degraded) {
|
|
205
|
+
spinner.warn(`Indexing incomplete (${result.processed}/${result.total}) • ${result.scanErrors} scan errors • ${result.failedFiles} failed. Results may be partial.`);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const prefix = projectRoot.endsWith("/")
|
|
209
|
+
? projectRoot
|
|
210
|
+
: `${projectRoot}/`;
|
|
211
|
+
const chunkCount = yield vectorDb.countRowsForPath(prefix);
|
|
212
|
+
(0, project_registry_1.stampProjectFullSync)({
|
|
213
|
+
root: projectRoot,
|
|
214
|
+
name: path.basename(projectRoot),
|
|
215
|
+
generation: result.generation,
|
|
216
|
+
embedMode: result.embedMode,
|
|
217
|
+
chunkCount,
|
|
218
|
+
chunkerVersion: config_1.CONFIG.CHUNKER_VERSION,
|
|
219
|
+
expectedFingerprint: result.registryExpectation.embeddingFingerprint,
|
|
220
|
+
expectedRebuildId: result.registryExpectation.rebuildId,
|
|
221
|
+
});
|
|
222
|
+
spinner.succeed(`${options.sync ? "Indexing" : "Initial indexing"} complete (${result.processed}/${result.total}) • indexed ${result.indexed}`);
|
|
223
|
+
}
|
|
196
224
|
}
|
|
197
225
|
catch (e) {
|
|
198
226
|
spinner.fail("Indexing failed");
|
|
@@ -44,9 +44,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.outputSkeletons = outputSkeletons;
|
|
46
46
|
const fs = __importStar(require("node:fs"));
|
|
47
|
-
const path = __importStar(require("node:path"));
|
|
48
47
|
const skeleton_1 = require("../lib/skeleton");
|
|
49
48
|
const retriever_1 = require("../lib/skeleton/retriever");
|
|
49
|
+
const path_containment_1 = require("../lib/utils/path-containment");
|
|
50
50
|
// Reuse Skeletonizer instance
|
|
51
51
|
let globalSkeletonizer = null;
|
|
52
52
|
function outputSkeletons(results, projectRoot, limit, db, precomputed) {
|
|
@@ -77,10 +77,19 @@ function outputSkeletons(results, projectRoot, limit, db, precomputed) {
|
|
|
77
77
|
const skeletonOpts = { includeSummary: true };
|
|
78
78
|
const skeletonResults = [];
|
|
79
79
|
for (const filePath of filesToProcess) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
let absPath;
|
|
81
|
+
try {
|
|
82
|
+
absPath = (0, path_containment_1.resolveContainedFile)(projectRoot, filePath);
|
|
83
|
+
}
|
|
84
|
+
catch (_c) {
|
|
85
|
+
skeletonResults.push({
|
|
86
|
+
file: filePath,
|
|
87
|
+
skeleton: `// File not readable: ${filePath}`,
|
|
88
|
+
tokens: 0,
|
|
89
|
+
error: "File not readable",
|
|
90
|
+
});
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
84
93
|
// 0. Daemon-supplied (preferred — already-warm DB lookup, no cold open)
|
|
85
94
|
const fromDaemon = (_b = precomputed === null || precomputed === void 0 ? void 0 : precomputed[absPath]) !== null && _b !== void 0 ? _b : precomputed === null || precomputed === void 0 ? void 0 : precomputed[filePath];
|
|
86
95
|
if (fromDaemon) {
|
|
@@ -104,24 +113,25 @@ function outputSkeletons(results, projectRoot, limit, db, precomputed) {
|
|
|
104
113
|
}
|
|
105
114
|
}
|
|
106
115
|
// 2. Fallback to fresh generation
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
try {
|
|
117
|
+
yield globalSkeletonizer.init();
|
|
118
|
+
const content = fs.readFileSync(absPath, "utf-8");
|
|
119
|
+
const res = yield globalSkeletonizer.skeletonizeFile(absPath, content, skeletonOpts);
|
|
120
|
+
skeletonResults.push({
|
|
121
|
+
file: filePath,
|
|
122
|
+
skeleton: res.skeleton,
|
|
123
|
+
tokens: res.tokenEstimate,
|
|
124
|
+
error: res.error,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
catch (_d) {
|
|
109
128
|
skeletonResults.push({
|
|
110
129
|
file: filePath,
|
|
111
|
-
skeleton: `// File not
|
|
130
|
+
skeleton: `// File not readable: ${filePath}`,
|
|
112
131
|
tokens: 0,
|
|
113
|
-
error: "File not
|
|
132
|
+
error: "File not readable",
|
|
114
133
|
});
|
|
115
|
-
continue;
|
|
116
134
|
}
|
|
117
|
-
const content = fs.readFileSync(absPath, "utf-8");
|
|
118
|
-
const res = yield globalSkeletonizer.skeletonizeFile(absPath, content, skeletonOpts);
|
|
119
|
-
skeletonResults.push({
|
|
120
|
-
file: filePath,
|
|
121
|
-
skeleton: res.skeleton,
|
|
122
|
-
tokens: res.tokenEstimate,
|
|
123
|
-
error: res.error,
|
|
124
|
-
});
|
|
125
135
|
}
|
|
126
136
|
// Since search doesn't support --json explicitly yet, we just print text.
|
|
127
137
|
// But if we ever add it, we have the structure.
|