grepmax 0.26.40 → 0.26.41
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 +4 -0
- package/dist/commands/codex.js +22 -16
- package/dist/commands/impact.js +2 -2
- package/dist/commands/mcp.js +37 -14
- package/dist/commands/peek.js +2 -2
- package/dist/commands/status.js +32 -28
- package/dist/commands/test-find.js +2 -2
- package/dist/commands/trace.js +1 -1
- package/dist/commands/watch.js +7 -0
- package/dist/lib/daemon/daemon.js +47 -15
- package/dist/lib/daemon/graph-handler.js +1 -1
- package/dist/lib/daemon/ipc-handler.js +10 -8
- package/dist/lib/daemon/search-handler.js +18 -8
- package/dist/lib/daemon/watcher-manager.js +37 -4
- package/dist/lib/graph/graph-builder.js +52 -4
- package/dist/lib/graph/impact-rollup.js +2 -2
- package/dist/lib/graph/impact.js +20 -8
- package/dist/lib/graph/test-hits.js +13 -7
- package/dist/lib/index/batch-processor.js +27 -2
- package/dist/lib/index/grammar-loader.js +22 -9
- package/dist/lib/output/formatter.js +1 -1
- package/dist/lib/output/index-state-footer.js +26 -6
- package/dist/lib/utils/resource-snapshot.js +20 -0
- package/dist/lib/utils/tests-footer.js +8 -16
- package/dist/lib/workers/embedding-error.js +16 -0
- package/dist/lib/workers/embeddings/mlx-client.js +94 -66
- package/dist/lib/workers/orchestrator.js +3 -2
- package/dist/lib/workers/pool.js +1 -1
- package/dist/lib/workers/process-child.js +2 -1
- package/package.json +1 -2
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -48,6 +48,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
48
48
|
};
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
50
|
exports.validateMlxEmbeddingResponse = validateMlxEmbeddingResponse;
|
|
51
|
+
exports.requestMlxJSON = requestMlxJSON;
|
|
51
52
|
exports.isMlxUp = isMlxUp;
|
|
52
53
|
exports.mlxEmbed = mlxEmbed;
|
|
53
54
|
const http = __importStar(require("node:http"));
|
|
@@ -81,81 +82,108 @@ function validateMlxEmbeddingResponse(data, textCount, expectedModel, expectedDi
|
|
|
81
82
|
Number.isFinite(element) &&
|
|
82
83
|
Math.abs(element) <= FLOAT32_MAX)));
|
|
83
84
|
}
|
|
84
|
-
|
|
85
|
+
/** A hard deadline also bounds stalled/truncated response bodies. */
|
|
86
|
+
function requestMlxJSON(reqPath, body) {
|
|
85
87
|
const start = performance.now();
|
|
86
88
|
return new Promise((resolve) => {
|
|
87
|
-
const payload = JSON.stringify(body);
|
|
89
|
+
const payload = body === undefined ? undefined : JSON.stringify(body);
|
|
90
|
+
let settled = false;
|
|
91
|
+
let deadline;
|
|
92
|
+
const finish = (result) => {
|
|
93
|
+
if (settled)
|
|
94
|
+
return;
|
|
95
|
+
settled = true;
|
|
96
|
+
clearTimeout(deadline);
|
|
97
|
+
resolve(Object.assign(Object.assign({}, result), { ms: Math.round(performance.now() - start) }));
|
|
98
|
+
};
|
|
88
99
|
const req = http.request({
|
|
89
100
|
hostname: MLX_HOST,
|
|
90
101
|
port: MLX_PORT,
|
|
91
102
|
path: reqPath,
|
|
92
|
-
method: "POST",
|
|
93
|
-
headers:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
method: payload === undefined ? "GET" : "POST",
|
|
104
|
+
headers: payload === undefined
|
|
105
|
+
? undefined
|
|
106
|
+
: {
|
|
107
|
+
"Content-Type": "application/json",
|
|
108
|
+
"Content-Length": Buffer.byteLength(payload),
|
|
109
|
+
},
|
|
98
110
|
}, (res) => {
|
|
99
111
|
const chunks = [];
|
|
100
|
-
|
|
112
|
+
let bytes = 0;
|
|
113
|
+
res.on("data", (chunk) => {
|
|
114
|
+
bytes += chunk.length;
|
|
115
|
+
if (bytes > 16 * 1024 * 1024) {
|
|
116
|
+
finish({
|
|
117
|
+
ok: false,
|
|
118
|
+
category: "protocol",
|
|
119
|
+
status: res.statusCode,
|
|
120
|
+
detail: "response exceeds 16MiB",
|
|
121
|
+
});
|
|
122
|
+
req.destroy();
|
|
123
|
+
}
|
|
124
|
+
else
|
|
125
|
+
chunks.push(chunk);
|
|
126
|
+
});
|
|
127
|
+
res.on("aborted", () => finish({
|
|
128
|
+
ok: false,
|
|
129
|
+
category: "transport",
|
|
130
|
+
status: res.statusCode,
|
|
131
|
+
detail: "response aborted",
|
|
132
|
+
}));
|
|
133
|
+
res.on("error", (err) => finish({
|
|
134
|
+
ok: false,
|
|
135
|
+
category: "transport",
|
|
136
|
+
status: res.statusCode,
|
|
137
|
+
detail: err.message.slice(0, 512),
|
|
138
|
+
}));
|
|
101
139
|
res.on("end", () => {
|
|
140
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
141
|
+
if (res.statusCode !== 200) {
|
|
142
|
+
finish({
|
|
143
|
+
ok: false,
|
|
144
|
+
category: "http",
|
|
145
|
+
status: res.statusCode,
|
|
146
|
+
detail: raw.slice(0, 512),
|
|
147
|
+
});
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
102
150
|
try {
|
|
103
|
-
|
|
104
|
-
const ok = res.statusCode === 200;
|
|
105
|
-
(0, logger_1.debug)("mlx", `POST ${reqPath} → ${res.statusCode} ${(performance.now() - start).toFixed(0)}ms payload=${payload.length}B`);
|
|
106
|
-
resolve({ ok, data });
|
|
151
|
+
finish({ ok: true, status: res.statusCode, data: JSON.parse(raw) });
|
|
107
152
|
}
|
|
108
153
|
catch (_a) {
|
|
109
|
-
(
|
|
110
|
-
|
|
154
|
+
finish({
|
|
155
|
+
ok: false,
|
|
156
|
+
category: "protocol",
|
|
157
|
+
status: res.statusCode,
|
|
158
|
+
detail: "invalid JSON",
|
|
159
|
+
});
|
|
111
160
|
}
|
|
112
161
|
});
|
|
113
162
|
});
|
|
114
|
-
req.on("error", (err) => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
163
|
+
req.on("error", (err) => finish({
|
|
164
|
+
ok: false,
|
|
165
|
+
category: "transport",
|
|
166
|
+
detail: err.message.slice(0, 512),
|
|
167
|
+
}));
|
|
168
|
+
deadline = setTimeout(() => {
|
|
169
|
+
finish({
|
|
170
|
+
ok: false,
|
|
171
|
+
category: "timeout",
|
|
172
|
+
detail: "request deadline exceeded",
|
|
173
|
+
});
|
|
120
174
|
req.destroy();
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
req.write(payload);
|
|
124
|
-
req.end();
|
|
175
|
+
}, reqPath === "/health" ? 2000 : MLX_TIMEOUT_MS);
|
|
176
|
+
req.end(payload);
|
|
125
177
|
});
|
|
126
178
|
}
|
|
127
|
-
/**
|
|
128
|
-
* Check if MLX server is reachable. Caches result for CHECK_INTERVAL_MS.
|
|
129
|
-
*/
|
|
130
179
|
function checkHealth(expectedModel) {
|
|
131
180
|
return __awaiter(this, void 0, void 0, function* () {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
let model;
|
|
139
|
-
try {
|
|
140
|
-
model = JSON.parse(Buffer.concat(chunks).toString("utf8")).model;
|
|
141
|
-
}
|
|
142
|
-
catch (_a) { }
|
|
143
|
-
const ok = res.statusCode === 200 &&
|
|
144
|
-
(!expectedModel || model === expectedModel);
|
|
145
|
-
(0, logger_1.debug)("mlx", `health → ${ok ? "ok" : `status=${res.statusCode} model=${String(model)}`} ${(performance.now() - start).toFixed(0)}ms`);
|
|
146
|
-
resolve(ok);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
req.on("error", (err) => {
|
|
150
|
-
(0, logger_1.debug)("mlx", `health → error: ${err.message} ${(performance.now() - start).toFixed(0)}ms`);
|
|
151
|
-
resolve(false);
|
|
152
|
-
});
|
|
153
|
-
req.on("timeout", () => {
|
|
154
|
-
(0, logger_1.debug)("mlx", `health → timeout ${(performance.now() - start).toFixed(0)}ms`);
|
|
155
|
-
req.destroy();
|
|
156
|
-
resolve(false);
|
|
157
|
-
});
|
|
158
|
-
});
|
|
181
|
+
var _a;
|
|
182
|
+
var _b, _c;
|
|
183
|
+
const result = yield requestMlxJSON("/health");
|
|
184
|
+
const ok = result.ok && (!expectedModel || ((_a = result.data) === null || _a === void 0 ? void 0 : _a.model) === expectedModel);
|
|
185
|
+
(0, logger_1.debug)("mlx", `health ok=${ok} category=${(_b = result.category) !== null && _b !== void 0 ? _b : "none"} status=${(_c = result.status) !== null && _c !== void 0 ? _c : "none"} ms=${result.ms}`);
|
|
186
|
+
return ok;
|
|
159
187
|
});
|
|
160
188
|
}
|
|
161
189
|
function isMlxUp(expectedModel) {
|
|
@@ -192,7 +220,7 @@ function isMlxUp(expectedModel) {
|
|
|
192
220
|
*/
|
|
193
221
|
function mlxEmbed(texts, options) {
|
|
194
222
|
return __awaiter(this, void 0, void 0, function* () {
|
|
195
|
-
var _a;
|
|
223
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
196
224
|
const mode = (_a = options === null || options === void 0 ? void 0 : options.mode) !== null && _a !== void 0 ? _a : EMBED_MODE;
|
|
197
225
|
if (mode === "cpu")
|
|
198
226
|
return null;
|
|
@@ -201,7 +229,7 @@ function mlxEmbed(texts, options) {
|
|
|
201
229
|
(0, logger_1.debug)("mlx", `embed ${texts.length} texts`);
|
|
202
230
|
let postResult;
|
|
203
231
|
try {
|
|
204
|
-
postResult = yield
|
|
232
|
+
postResult = yield requestMlxJSON("/embed", {
|
|
205
233
|
texts,
|
|
206
234
|
expected_model: options === null || options === void 0 ? void 0 : options.expectedModel,
|
|
207
235
|
});
|
|
@@ -223,17 +251,17 @@ function mlxEmbed(texts, options) {
|
|
|
223
251
|
const now = Date.now();
|
|
224
252
|
if (wasPreviouslyAvailable ||
|
|
225
253
|
now - lastMlxWarning >= MLX_WARNING_INTERVAL_MS) {
|
|
226
|
-
console.error(
|
|
227
|
-
ok +
|
|
228
|
-
", validResponse=" +
|
|
229
|
-
responseMatches +
|
|
230
|
-
", dim=" +
|
|
231
|
-
String(data === null || data === void 0 ? void 0 : data.dim) +
|
|
232
|
-
", model=" +
|
|
233
|
-
String(data === null || data === void 0 ? void 0 : data.model) +
|
|
234
|
-
")");
|
|
254
|
+
console.error(`[mlx] Embed failed: category=${(_b = postResult.category) !== null && _b !== void 0 ? _b : "protocol"} status=${(_c = postResult.status) !== null && _c !== void 0 ? _c : "none"} ms=${postResult.ms} batch=${texts.length} detail=${JSON.stringify((_d = postResult.detail) !== null && _d !== void 0 ? _d : `invalid vectors/model: dim=${String(data === null || data === void 0 ? void 0 : data.dim)} model=${String(data === null || data === void 0 ? void 0 : data.model)}`).slice(0, 600)}`);
|
|
235
255
|
lastMlxWarning = now;
|
|
236
256
|
}
|
|
257
|
+
if ((postResult.ok && !responseMatches) ||
|
|
258
|
+
postResult.category === "protocol" ||
|
|
259
|
+
(postResult.category === "http" &&
|
|
260
|
+
((_e = postResult.status) !== null && _e !== void 0 ? _e : 500) < 500 &&
|
|
261
|
+
postResult.status !== 429 &&
|
|
262
|
+
postResult.status !== 408)) {
|
|
263
|
+
throw new Error(`MLX embedding protocol failure: status=${(_f = postResult.status) !== null && _f !== void 0 ? _f : "none"} ${(_g = postResult.detail) !== null && _g !== void 0 ? _g : "invalid vectors or model identity"}`);
|
|
264
|
+
}
|
|
237
265
|
return null;
|
|
238
266
|
}
|
|
239
267
|
return data.vectors.map((v) => new Float32Array(v));
|
|
@@ -58,6 +58,7 @@ const file_utils_1 = require("../utils/file-utils");
|
|
|
58
58
|
const logger_1 = require("../utils/logger");
|
|
59
59
|
const path_containment_1 = require("../utils/path-containment");
|
|
60
60
|
const colbert_math_1 = require("./colbert-math");
|
|
61
|
+
const embedding_error_1 = require("./embedding-error");
|
|
61
62
|
const colbert_1 = require("./embeddings/colbert");
|
|
62
63
|
const granite_1 = require("./embeddings/granite");
|
|
63
64
|
const mlx_client_1 = require("./embeddings/mlx-client");
|
|
@@ -158,10 +159,10 @@ class WorkerOrchestrator {
|
|
|
158
159
|
expectedDim: this.generation.vectorDim,
|
|
159
160
|
});
|
|
160
161
|
if (!mlxResult && !this.allowOnnxFallback) {
|
|
161
|
-
throw new
|
|
162
|
+
throw new embedding_error_1.EmbeddingBackendUnavailableError(`MLX embedding model ${this.generation.mlxModel} is unavailable; ONNX fallback is disabled for this custom embedding generation`);
|
|
162
163
|
}
|
|
163
164
|
if (!mlxResult && denseBackend === "mlx") {
|
|
164
|
-
throw new
|
|
165
|
+
throw new embedding_error_1.EmbeddingBackendUnavailableError(`MLX embedding model ${this.generation.mlxModel} became unavailable during this embedding operation`);
|
|
165
166
|
}
|
|
166
167
|
if (!mlxResult && !mlxFallbackWarned) {
|
|
167
168
|
console.warn("[embed] MLX unavailable, falling back to CPU (ONNX)");
|
package/dist/lib/workers/pool.js
CHANGED
|
@@ -384,7 +384,7 @@ class WorkerPool {
|
|
|
384
384
|
if ("error" in msg) {
|
|
385
385
|
const filePath = (_f = (_e = (_a = task.payload) === null || _a === void 0 ? void 0 : _a.path) !== null && _e !== void 0 ? _e : (_b = task.payload) === null || _b === void 0 ? void 0 : _b.absolutePath) !== null && _f !== void 0 ? _f : "unknown";
|
|
386
386
|
(0, logger_1.debug)("pool", `error task=${task.id} method=${task.method} file=${filePath}: ${msg.error}`);
|
|
387
|
-
task.reject(new Error(msg.error));
|
|
387
|
+
task.reject(Object.assign(new Error(msg.error), typeof msg.code === "string" ? { code: msg.code } : {}));
|
|
388
388
|
}
|
|
389
389
|
else {
|
|
390
390
|
const elapsed = task.startTime
|
|
@@ -93,7 +93,8 @@ const handleMessage = (msg) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
93
93
|
catch (err) {
|
|
94
94
|
const message = err instanceof Error ? err.message : String(err);
|
|
95
95
|
(0, logger_1.debug)("worker", `fail task=${id} method=${method} ${(performance.now() - start).toFixed(0)}ms: ${message}`);
|
|
96
|
-
|
|
96
|
+
const code = err === null || err === void 0 ? void 0 : err.code;
|
|
97
|
+
send(Object.assign({ id, error: message }, (typeof code === "string" ? { code } : {})));
|
|
97
98
|
}
|
|
98
99
|
});
|
|
99
100
|
const handleMessageSerially = (0, serialized_handler_1.createSerializedHandler)(handleMessage);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grepmax",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.41",
|
|
4
4
|
"author": "Robert Owens <78518764+reowens@users.noreply.github.com>",
|
|
5
5
|
"homepage": "https://github.com/reowens/grepmax",
|
|
6
6
|
"bugs": {
|
|
@@ -86,7 +86,6 @@
|
|
|
86
86
|
"cli-highlight": "^2.1.11",
|
|
87
87
|
"commander": "^15.0.0",
|
|
88
88
|
"dotenv": "^17.4.2",
|
|
89
|
-
"fast-glob": "^3.3.3",
|
|
90
89
|
"ignore": "^7.0.9",
|
|
91
90
|
"lmdb": "^3.5.6",
|
|
92
91
|
"numkong": "^7.8.2",
|