grepmax 0.26.40 → 0.26.42
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 +6 -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/store/vector-db.js +28 -8
- 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
|
@@ -188,6 +188,9 @@ const COMPACTION_MIN_INTERVAL_MS = 30 * 60 * 1000;
|
|
|
188
188
|
* so a store that cannot be improved stops paying for the attempt.
|
|
189
189
|
*/
|
|
190
190
|
const COMPACTION_MAX_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
191
|
+
// Failed rewrites leave complete fragment copies until a later successful prune.
|
|
192
|
+
// One fresh-snapshot retry is enough; five attempts stranded ~70 GB in Oct 2026.
|
|
193
|
+
const COMPACTION_MAX_ATTEMPTS = 2;
|
|
191
194
|
/**
|
|
192
195
|
* Bounds for LanceDB's per-connection caches.
|
|
193
196
|
*
|
|
@@ -1083,7 +1086,7 @@ class VectorDB {
|
|
|
1083
1086
|
});
|
|
1084
1087
|
}
|
|
1085
1088
|
optimize() {
|
|
1086
|
-
return __awaiter(this, arguments, void 0, function* (retries =
|
|
1089
|
+
return __awaiter(this, arguments, void 0, function* (retries = COMPACTION_MAX_ATTEMPTS, retentionMs = 0, bypassExclusiveMutation = false) {
|
|
1087
1090
|
if (!bypassExclusiveMutation) {
|
|
1088
1091
|
while (this.exclusiveMutationPromise)
|
|
1089
1092
|
yield this.exclusiveMutationPromise;
|
|
@@ -1102,12 +1105,28 @@ class VectorDB {
|
|
|
1102
1105
|
});
|
|
1103
1106
|
this.activeCompactions++;
|
|
1104
1107
|
try {
|
|
1105
|
-
const
|
|
1106
|
-
const cutoff = new Date(Date.now() - retentionMs);
|
|
1108
|
+
const maxAttempts = Math.min(retries, COMPACTION_MAX_ATTEMPTS);
|
|
1107
1109
|
let rebuiltFts = false;
|
|
1108
|
-
for (let attempt = 1; attempt <=
|
|
1110
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1109
1111
|
yield this.drainWrites();
|
|
1110
1112
|
try {
|
|
1113
|
+
// Open AFTER outstanding writes commit, and reopen on every retry.
|
|
1114
|
+
// A handle opened before drainWrites carries the old snapshot even
|
|
1115
|
+
// though new writes are gated. Reusing it repeats the same conflict.
|
|
1116
|
+
const table = yield this.ensureTableUnsafe();
|
|
1117
|
+
const { totalBytes } = yield table.stats();
|
|
1118
|
+
if (!Number.isFinite(totalBytes) || totalBytes < 0) {
|
|
1119
|
+
throw new Error("Cannot estimate compaction size from table stats");
|
|
1120
|
+
}
|
|
1121
|
+
// Bypass the cached pressure check: a failed attempt can consume a
|
|
1122
|
+
// whole table within its 30s cache window. Budget two logical copies
|
|
1123
|
+
// for rewrite/index overhead, leaving the critical reserve untouched.
|
|
1124
|
+
const availableBytes = this.getAvailableBytes();
|
|
1125
|
+
const requiredBytes = totalBytes * 2 + config_1.DISK_CRITICAL_BYTES;
|
|
1126
|
+
if (availableBytes < requiredBytes) {
|
|
1127
|
+
(0, logger_1.log)("vectordb", `Optimize skipped: insufficient rewrite headroom (${(availableBytes / Math.pow(1024, 3)).toFixed(1)}GB free, ${(requiredBytes / Math.pow(1024, 3)).toFixed(1)}GB required)`);
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1111
1130
|
const done = (0, logger_1.timer)("vectordb", "optimize");
|
|
1112
1131
|
// deleteUnverified deletes files Lance cannot prove are unreferenced.
|
|
1113
1132
|
// LanceDB's own docs: only safe "if you can guarantee that no other
|
|
@@ -1119,7 +1138,8 @@ class VectorDB {
|
|
|
1119
1138
|
// Anything new that calls optimize() must preserve that: either be the
|
|
1120
1139
|
// daemon, or be the only process on the store.
|
|
1121
1140
|
const stats = yield table.optimize({
|
|
1122
|
-
|
|
1141
|
+
// Include fragment copies left by earlier failed attempts.
|
|
1142
|
+
cleanupOlderThan: new Date(Date.now() - retentionMs),
|
|
1123
1143
|
deleteUnverified: true,
|
|
1124
1144
|
});
|
|
1125
1145
|
done();
|
|
@@ -1150,10 +1170,10 @@ class VectorDB {
|
|
|
1150
1170
|
(0, logger_1.log)("vectordb", `Optimize failed (ENOSPC): disk full — skipping retries`);
|
|
1151
1171
|
return;
|
|
1152
1172
|
}
|
|
1153
|
-
if (attempt <
|
|
1173
|
+
if (attempt < maxAttempts &&
|
|
1154
1174
|
(msg.includes("conflict") || msg.includes("Retryable"))) {
|
|
1155
1175
|
const delay = 1000 * Math.pow(2, (attempt - 1));
|
|
1156
|
-
(0, logger_1.log)("vectordb", `Optimize conflict (attempt ${attempt}/${
|
|
1176
|
+
(0, logger_1.log)("vectordb", `Optimize conflict (attempt ${attempt}/${maxAttempts}), retrying with a fresh snapshot in ${delay}ms`);
|
|
1157
1177
|
yield new Promise((r) => setTimeout(r, delay));
|
|
1158
1178
|
continue;
|
|
1159
1179
|
}
|
|
@@ -1165,7 +1185,7 @@ class VectorDB {
|
|
|
1165
1185
|
// Unsafe variant: the public createFTSIndex waits on
|
|
1166
1186
|
// compactingPromise, which we hold.
|
|
1167
1187
|
if (msg.includes("Panic")) {
|
|
1168
|
-
if (attempt <
|
|
1188
|
+
if (attempt < maxAttempts &&
|
|
1169
1189
|
!rebuiltFts &&
|
|
1170
1190
|
!this.ftsPanicRecoveryExhausted) {
|
|
1171
1191
|
rebuiltFts = true;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildResourceSnapshot = buildResourceSnapshot;
|
|
4
|
+
function buildResourceSnapshot(counters, memory = process.memoryUsage(), at = Date.now()) {
|
|
5
|
+
const mb = (bytes) => Math.round(bytes / 1024 / 1024);
|
|
6
|
+
return {
|
|
7
|
+
at,
|
|
8
|
+
reason: counters.reason,
|
|
9
|
+
footprintMb: counters.footprintMb,
|
|
10
|
+
rssMb: mb(memory.rss),
|
|
11
|
+
heapUsedMb: mb(memory.heapUsed),
|
|
12
|
+
externalMb: mb(memory.external),
|
|
13
|
+
arrayBuffersMb: mb(memory.arrayBuffers),
|
|
14
|
+
lanceCacheMb: counters.lanceCacheBytes === null ? null : mb(counters.lanceCacheBytes),
|
|
15
|
+
workers: counters.workers,
|
|
16
|
+
pendingFiles: counters.pendingFiles,
|
|
17
|
+
operations: counters.operations,
|
|
18
|
+
maintenance: counters.maintenance,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -15,6 +15,7 @@ exports.fetchTestsForFooter = fetchTestsForFooter;
|
|
|
15
15
|
exports.renderTestsFooterAgent = renderTestsFooterAgent;
|
|
16
16
|
exports.renderTestsFooterHuman = renderTestsFooterHuman;
|
|
17
17
|
const impact_1 = require("../graph/impact");
|
|
18
|
+
const test_hits_1 = require("../graph/test-hits");
|
|
18
19
|
/**
|
|
19
20
|
* The footer is a courtesy line under a body the user asked for; it must never
|
|
20
21
|
* make the command feel slow. Past this budget the lookup is abandoned and the
|
|
@@ -57,24 +58,10 @@ function fetchTestsForFooter(symbol, vectorDb, pathPrefix, excludePrefixes) {
|
|
|
57
58
|
function relPath(p, projectRoot) {
|
|
58
59
|
return p.startsWith(`${projectRoot}/`) ? p.slice(projectRoot.length + 1) : p;
|
|
59
60
|
}
|
|
60
|
-
function hopLabelAgent(hops) {
|
|
61
|
-
if (hops === -1)
|
|
62
|
-
return "via-import";
|
|
63
|
-
if (hops === 0)
|
|
64
|
-
return "direct";
|
|
65
|
-
return `${hops}-hop`;
|
|
66
|
-
}
|
|
67
|
-
function hopLabelHuman(hops) {
|
|
68
|
-
if (hops === -1)
|
|
69
|
-
return "via import";
|
|
70
|
-
if (hops === 0)
|
|
71
|
-
return "direct";
|
|
72
|
-
return `${hops} hop${hops > 1 ? "s" : ""}`;
|
|
73
|
-
}
|
|
74
61
|
function renderTestsFooterAgent(tests, projectRoot) {
|
|
75
62
|
const lines = [];
|
|
76
63
|
for (const t of tests.slice(0, MAX_SHOWN)) {
|
|
77
|
-
lines.push(`t: ${relPath(t.file, projectRoot)}:${t.line + 1}\t${t.symbol}\t${hopLabelAgent(t.hops)}`);
|
|
64
|
+
lines.push(`t: ${relPath(t.file, projectRoot)}:${t.line + 1}\t${t.symbol}\t${(0, test_hits_1.hopLabelAgent)(t.hops, t.evidence)}`);
|
|
78
65
|
}
|
|
79
66
|
if (tests.length > MAX_SHOWN) {
|
|
80
67
|
lines.push(`t: ... ${tests.length - MAX_SHOWN} more`);
|
|
@@ -86,7 +73,12 @@ function renderTestsFooterHuman(tests, projectRoot) {
|
|
|
86
73
|
lines.push("");
|
|
87
74
|
lines.push(`tests (${tests.length}):`);
|
|
88
75
|
for (const t of tests.slice(0, MAX_SHOWN)) {
|
|
89
|
-
|
|
76
|
+
const label = t.evidence
|
|
77
|
+
? "same-file candidate"
|
|
78
|
+
: t.hops === -1
|
|
79
|
+
? "via import"
|
|
80
|
+
: (0, test_hits_1.hopLabelAgent)(t.hops);
|
|
81
|
+
lines.push(` ${t.symbol.padEnd(25)} ${dim(`${relPath(t.file, projectRoot)}:${t.line + 1}`)} ${dim(`(${label})`)}`);
|
|
90
82
|
}
|
|
91
83
|
if (tests.length > MAX_SHOWN) {
|
|
92
84
|
lines.push(dim(` ... and ${tests.length - MAX_SHOWN} more`));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EmbeddingBackendUnavailableError = void 0;
|
|
4
|
+
exports.isEmbeddingBackendUnavailable = isEmbeddingBackendUnavailable;
|
|
5
|
+
/** Shared backend outages are retryable; malformed inputs/protocols are not. */
|
|
6
|
+
class EmbeddingBackendUnavailableError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.code = "EMBED_BACKEND_UNAVAILABLE";
|
|
10
|
+
this.name = "EmbeddingBackendUnavailableError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.EmbeddingBackendUnavailableError = EmbeddingBackendUnavailableError;
|
|
14
|
+
function isEmbeddingBackendUnavailable(error) {
|
|
15
|
+
return ((error === null || error === void 0 ? void 0 : error.code) === "EMBED_BACKEND_UNAVAILABLE");
|
|
16
|
+
}
|
|
@@ -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.42",
|
|
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",
|