grepmax 0.26.57 → 0.26.58
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 +5 -1
- package/dist/commands/doctor.js +29 -13
- package/dist/commands/status.js +27 -14
- package/dist/commands/watch.js +22 -3
- package/dist/lib/daemon/daemon.js +214 -76
- package/dist/lib/daemon/ipc-handler.js +35 -14
- package/dist/lib/daemon/paused-reads.js +155 -0
- package/dist/lib/daemon/rows-handler.js +14 -8
- package/dist/lib/skeleton/retriever.js +3 -3
- package/dist/lib/store/vector-db.js +23 -14
- package/dist/lib/utils/daemon-launcher.js +8 -3
- package/dist/lib/utils/operation-coordinator.js +6 -0
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DaemonPausedError = exports.PAUSED_CACHE_OPTIONS = exports.PAUSED_RESULT_LIMIT = exports.PAUSED_QUERY_TIMEOUT_MS = void 0;
|
|
13
|
+
exports.isPausedRead = isPausedRead;
|
|
14
|
+
exports.validatePausedRead = validatePausedRead;
|
|
15
|
+
exports.searchPausedIndex = searchPausedIndex;
|
|
16
|
+
const intent_1 = require("../search/intent");
|
|
17
|
+
const per_file_1 = require("../search/per-file");
|
|
18
|
+
const searcher_1 = require("../search/searcher");
|
|
19
|
+
const arrow_1 = require("../utils/arrow");
|
|
20
|
+
const query_timeout_1 = require("../utils/query-timeout");
|
|
21
|
+
const rows_handler_1 = require("./rows-handler");
|
|
22
|
+
exports.PAUSED_QUERY_TIMEOUT_MS = 2000;
|
|
23
|
+
exports.PAUSED_RESULT_LIMIT = 20;
|
|
24
|
+
exports.PAUSED_CACHE_OPTIONS = {
|
|
25
|
+
readOnly: true,
|
|
26
|
+
indexCacheMb: 32,
|
|
27
|
+
metadataCacheMb: 16,
|
|
28
|
+
};
|
|
29
|
+
class DaemonPausedError extends Error {
|
|
30
|
+
constructor(reason) {
|
|
31
|
+
super(`gmax is serving bounded reads; indexing and heavy work are paused: ${reason}`);
|
|
32
|
+
this.code = "DAEMON_PAUSED";
|
|
33
|
+
this.name = "DaemonPausedError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.DaemonPausedError = DaemonPausedError;
|
|
37
|
+
function isPausedRead(name) {
|
|
38
|
+
return [
|
|
39
|
+
"keyword-search",
|
|
40
|
+
"rows.locate",
|
|
41
|
+
"rows.skeleton",
|
|
42
|
+
"graph.resolve",
|
|
43
|
+
"unwatch",
|
|
44
|
+
"llm-stop",
|
|
45
|
+
].includes(name);
|
|
46
|
+
}
|
|
47
|
+
/** Refuse oversized requests rather than silently truncating exact lookups. */
|
|
48
|
+
function validatePausedRead(name, payload) {
|
|
49
|
+
if (!isPausedRead(name))
|
|
50
|
+
throw new DaemonPausedError(`${name} needs the full service`);
|
|
51
|
+
if (name === "graph.resolve" &&
|
|
52
|
+
(typeof payload.target !== "string" ||
|
|
53
|
+
payload.target.length > 4096 ||
|
|
54
|
+
!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(payload.target)))
|
|
55
|
+
throw new DaemonPausedError("file-wide symbol enumeration is paused; use an exact symbol or bounded file lookup");
|
|
56
|
+
if (name === "rows.skeleton" && typeof payload.path !== "string")
|
|
57
|
+
throw new DaemonPausedError("paused skeleton lookup requires an exact file path");
|
|
58
|
+
if (name !== "rows.locate")
|
|
59
|
+
return;
|
|
60
|
+
const matches = Array.isArray(payload.matches) ? payload.matches : [];
|
|
61
|
+
const limit = payload.limit === undefined ? exports.PAUSED_RESULT_LIMIT : Number(payload.limit);
|
|
62
|
+
if (matches.length > 4 ||
|
|
63
|
+
!Number.isInteger(limit) ||
|
|
64
|
+
limit < 1 ||
|
|
65
|
+
limit > exports.PAUSED_RESULT_LIMIT ||
|
|
66
|
+
payload.scoped === false ||
|
|
67
|
+
matches.some((m) => !m ||
|
|
68
|
+
!["definedSymbol", "path"].includes(String(m.kind)))) {
|
|
69
|
+
throw new DaemonPausedError("use at most four scoped symbol/file lookups with a limit of 20");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Existing FTS only: no embedding, vector columns, rebuild or scan fallback. */
|
|
73
|
+
function searchPausedIndex(db, payload, reason, signal) {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
var _a, _b;
|
|
76
|
+
var _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
77
|
+
signal.throwIfAborted();
|
|
78
|
+
const root = (0, rows_handler_1.assertReadableProject)(payload.projectRoot);
|
|
79
|
+
for (const candidate of (_c = (_a = payload.filters) === null || _a === void 0 ? void 0 : _a.projectRoots) !== null && _c !== void 0 ? _c : [root])
|
|
80
|
+
(0, rows_handler_1.assertReadableProject)(candidate);
|
|
81
|
+
if (payload.query.length > 4096)
|
|
82
|
+
throw new DaemonPausedError("query exceeds 4096 characters");
|
|
83
|
+
const requestedLimit = (_d = payload.limit) !== null && _d !== void 0 ? _d : 10;
|
|
84
|
+
if (!Number.isInteger(requestedLimit) || requestedLimit < 1)
|
|
85
|
+
throw new Error("invalid limit");
|
|
86
|
+
const limit = Math.min(requestedLimit, exports.PAUSED_RESULT_LIMIT);
|
|
87
|
+
const maxPerFile = (0, per_file_1.validateMaxPerFile)(payload.maxPerFile);
|
|
88
|
+
yield db.adoptFTSIndex();
|
|
89
|
+
signal.throwIfAborted();
|
|
90
|
+
const table = yield db.ensureTable();
|
|
91
|
+
const prefix = (_e = payload.pathPrefix) !== null && _e !== void 0 ? _e : `${root.replace(/\/$/, "")}/`;
|
|
92
|
+
const where = (0, searcher_1.buildWhereClause)(((_b = payload.filters) === null || _b === void 0 ? void 0 : _b.projectRoots) ? undefined : prefix, payload.filters, (0, intent_1.detectIntent)(payload.query));
|
|
93
|
+
let query = table
|
|
94
|
+
.search(payload.query)
|
|
95
|
+
.fastSearch()
|
|
96
|
+
.select([
|
|
97
|
+
"path",
|
|
98
|
+
"hash",
|
|
99
|
+
"content",
|
|
100
|
+
"start_line",
|
|
101
|
+
"end_line",
|
|
102
|
+
"chunk_index",
|
|
103
|
+
"role",
|
|
104
|
+
"defined_symbols",
|
|
105
|
+
"parent_symbol",
|
|
106
|
+
"_score",
|
|
107
|
+
])
|
|
108
|
+
.limit(exports.PAUSED_RESULT_LIMIT);
|
|
109
|
+
if (where)
|
|
110
|
+
query = query.where(where);
|
|
111
|
+
const rows = yield (0, query_timeout_1.withQueryTimeout)(query.toArray({ timeoutMs: exports.PAUSED_QUERY_TIMEOUT_MS }), "paused keyword search", exports.PAUSED_QUERY_TIMEOUT_MS);
|
|
112
|
+
signal.throwIfAborted();
|
|
113
|
+
const data = [];
|
|
114
|
+
const counts = new Map();
|
|
115
|
+
const best = Math.max(1, ...rows.map((r) => Number(r._score) || 0));
|
|
116
|
+
for (const row of rows) {
|
|
117
|
+
const path = String((_f = row.path) !== null && _f !== void 0 ? _f : "");
|
|
118
|
+
const count = (_g = counts.get(path)) !== null && _g !== void 0 ? _g : 0;
|
|
119
|
+
if (maxPerFile !== undefined && count >= maxPerFile)
|
|
120
|
+
continue;
|
|
121
|
+
counts.set(path, count + 1);
|
|
122
|
+
data.push({
|
|
123
|
+
type: "text",
|
|
124
|
+
text: String((_h = row.content) !== null && _h !== void 0 ? _h : "").slice(0, 8192),
|
|
125
|
+
score: (Number(row._score) || 0) / best,
|
|
126
|
+
metadata: { path, hash: String((_j = row.hash) !== null && _j !== void 0 ? _j : "") },
|
|
127
|
+
generated_metadata: {
|
|
128
|
+
start_line: Number((_k = row.start_line) !== null && _k !== void 0 ? _k : 0),
|
|
129
|
+
end_line: Number((_l = row.end_line) !== null && _l !== void 0 ? _l : 0),
|
|
130
|
+
},
|
|
131
|
+
chunk_index: Number((_m = row.chunk_index) !== null && _m !== void 0 ? _m : 0),
|
|
132
|
+
role: String((_o = row.role) !== null && _o !== void 0 ? _o : ""),
|
|
133
|
+
parent_symbol: String((_p = row.parent_symbol) !== null && _p !== void 0 ? _p : ""),
|
|
134
|
+
defined_symbols: (0, arrow_1.toArr)(row.defined_symbols).filter((s) => typeof s === "string"),
|
|
135
|
+
});
|
|
136
|
+
if (data.length >= limit)
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
data,
|
|
142
|
+
warnings: [
|
|
143
|
+
`Keyword search only; embeddings and indexing are paused: ${reason}. Results use the retained FTS index and keyword scores; unindexed rows are excluded.`,
|
|
144
|
+
...(requestedLimit > limit
|
|
145
|
+
? [`Paused search is limited to ${limit} results.`]
|
|
146
|
+
: []),
|
|
147
|
+
...(payload.includeGraph || payload.includeSkeletons
|
|
148
|
+
? [
|
|
149
|
+
"Inline graph/skeleton enrichment is paused; use bounded file lookups.",
|
|
150
|
+
]
|
|
151
|
+
: []),
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
}
|
|
@@ -440,7 +440,7 @@ function normalizeRow(row, select) {
|
|
|
440
440
|
/** Run a batch of row selects, one result array per matcher, order preserved. */
|
|
441
441
|
function runLocate(deps, req) {
|
|
442
442
|
return __awaiter(this, void 0, void 0, function* () {
|
|
443
|
-
var _a, _b;
|
|
443
|
+
var _a, _b, _c;
|
|
444
444
|
const table = yield tableOf(deps);
|
|
445
445
|
const scoped = req.scoped !== false;
|
|
446
446
|
const pathScope = (0, scope_filter_1.buildScopeWhere)(req.scope);
|
|
@@ -452,9 +452,11 @@ function runLocate(deps, req) {
|
|
|
452
452
|
.select(req.select)
|
|
453
453
|
.where(scoped ? `${where} AND ${pathScope}` : where);
|
|
454
454
|
query = query.limit((_a = req.limit) !== null && _a !== void 0 ? _a : exports.MAX_LOCATE_ROWS);
|
|
455
|
-
const rows = yield (0, query_timeout_2.withQueryTimeout)(query.toArray(
|
|
455
|
+
const rows = yield (0, query_timeout_2.withQueryTimeout)(query.toArray({
|
|
456
|
+
timeoutMs: (_b = deps.queryTimeoutMs) !== null && _b !== void 0 ? _b : query_timeout_1.QUERY_EXECUTION_OPTIONS.timeoutMs,
|
|
457
|
+
}), label, deps.queryTimeoutMs);
|
|
456
458
|
results.push(rows
|
|
457
|
-
.slice(0, (
|
|
459
|
+
.slice(0, (_c = req.limit) !== null && _c !== void 0 ? _c : exports.MAX_LOCATE_ROWS)
|
|
458
460
|
.map((row) => normalizeRow(row, req.select)));
|
|
459
461
|
}
|
|
460
462
|
return results;
|
|
@@ -525,23 +527,27 @@ function runSkeleton(deps, req) {
|
|
|
525
527
|
const db = deps.vectorDb;
|
|
526
528
|
let filePath = (_b = req.path) !== null && _b !== void 0 ? _b : null;
|
|
527
529
|
if (!filePath && req.symbol) {
|
|
528
|
-
filePath = yield findFileBySymbol(db, req.symbol, req.projectRoot);
|
|
530
|
+
filePath = yield findFileBySymbol(db, req.symbol, req.projectRoot, deps.queryTimeoutMs);
|
|
529
531
|
}
|
|
530
532
|
if (!filePath)
|
|
531
533
|
return { path: null, skeleton: null };
|
|
532
|
-
return {
|
|
534
|
+
return {
|
|
535
|
+
path: filePath,
|
|
536
|
+
skeleton: yield (0, retriever_1.getStoredSkeleton)(db, filePath, deps.queryTimeoutMs),
|
|
537
|
+
};
|
|
533
538
|
});
|
|
534
539
|
}
|
|
535
540
|
/** FTS lookup for the file that defines `symbol`; null when nothing matches. */
|
|
536
|
-
function findFileBySymbol(
|
|
537
|
-
return __awaiter(this,
|
|
541
|
+
function findFileBySymbol(db_1, symbol_1, projectRoot_1) {
|
|
542
|
+
return __awaiter(this, arguments, void 0, function* (db, symbol, projectRoot, timeoutMs = query_timeout_1.QUERY_EXECUTION_OPTIONS.timeoutMs) {
|
|
538
543
|
try {
|
|
539
544
|
const table = yield db.ensureTable();
|
|
540
545
|
const results = yield table
|
|
541
546
|
.search(symbol)
|
|
547
|
+
.select(["path", "defined_symbols"])
|
|
542
548
|
.where((0, filter_builder_1.pathStartsWith)(`${projectRoot}/`))
|
|
543
549
|
.limit(10)
|
|
544
|
-
.toArray(
|
|
550
|
+
.toArray({ timeoutMs });
|
|
545
551
|
for (const result of results) {
|
|
546
552
|
const defined = result.defined_symbols;
|
|
547
553
|
if ((0, arrow_1.toArr)(defined).includes(symbol)) {
|
|
@@ -12,8 +12,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.getStoredSkeleton = getStoredSkeleton;
|
|
13
13
|
const filter_builder_1 = require("../utils/filter-builder");
|
|
14
14
|
const query_timeout_1 = require("../utils/query-timeout");
|
|
15
|
-
function getStoredSkeleton(
|
|
16
|
-
return __awaiter(this,
|
|
15
|
+
function getStoredSkeleton(db_1, filePath_1) {
|
|
16
|
+
return __awaiter(this, arguments, void 0, function* (db, filePath, timeoutMs = query_timeout_1.QUERY_EXECUTION_OPTIONS.timeoutMs) {
|
|
17
17
|
try {
|
|
18
18
|
const table = yield db.ensureTable();
|
|
19
19
|
// LanceDB query
|
|
@@ -22,7 +22,7 @@ function getStoredSkeleton(db, filePath) {
|
|
|
22
22
|
.select(["file_skeleton"])
|
|
23
23
|
.where(`path = '${(0, filter_builder_1.escapeSqlString)(filePath)}' AND is_anchor = true`)
|
|
24
24
|
.limit(1)
|
|
25
|
-
.toArray(
|
|
25
|
+
.toArray({ timeoutMs });
|
|
26
26
|
if (results.length > 0) {
|
|
27
27
|
const skel = results[0].file_skeleton;
|
|
28
28
|
if (typeof skel === "string" && skel.length > 0) {
|
|
@@ -213,14 +213,16 @@ function envMb(name, fallback) {
|
|
|
213
213
|
const parsed = Number(process.env[name]);
|
|
214
214
|
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;
|
|
215
215
|
}
|
|
216
|
-
function createLanceSession() {
|
|
216
|
+
function createLanceSession(options = {}) {
|
|
217
|
+
var _a, _b;
|
|
217
218
|
const mb = (n) => BigInt(n * 1024 * 1024);
|
|
218
|
-
return new lancedb.Session(mb(LANCE_INDEX_CACHE_MB), mb(LANCE_METADATA_CACHE_MB));
|
|
219
|
+
return new lancedb.Session(mb((_a = options.indexCacheMb) !== null && _a !== void 0 ? _a : LANCE_INDEX_CACHE_MB), mb((_b = options.metadataCacheMb) !== null && _b !== void 0 ? _b : LANCE_METADATA_CACHE_MB));
|
|
219
220
|
}
|
|
220
221
|
class VectorDB {
|
|
221
|
-
constructor(lancedbDir, vectorDim, suppliedLease) {
|
|
222
|
+
constructor(lancedbDir, vectorDim, suppliedLease, options = {}) {
|
|
222
223
|
this.lancedbDir = lancedbDir;
|
|
223
224
|
this.suppliedLease = suppliedLease;
|
|
225
|
+
this.options = options;
|
|
224
226
|
this.db = null;
|
|
225
227
|
this.session = null;
|
|
226
228
|
this.closed = false;
|
|
@@ -270,6 +272,11 @@ class VectorDB {
|
|
|
270
272
|
this.vectorDim = vectorDim !== null && vectorDim !== void 0 ? vectorDim : (0, index_config_1.readGlobalConfig)().vectorDim;
|
|
271
273
|
this.unregisterCleanup = (0, cleanup_1.registerCleanup)(() => this.close());
|
|
272
274
|
}
|
|
275
|
+
assertMutationAllowed() {
|
|
276
|
+
if (this.options.readOnly)
|
|
277
|
+
throw new Error("gmax store is read-only");
|
|
278
|
+
(0, maintenance_policy_1.assertStoreMutationAllowed)();
|
|
279
|
+
}
|
|
273
280
|
/**
|
|
274
281
|
* Start a periodic maintenance timer (FTS rebuild + optimize).
|
|
275
282
|
* Call once from the daemon — replaces per-processor maintenance intervals.
|
|
@@ -372,7 +379,7 @@ class VectorDB {
|
|
|
372
379
|
}
|
|
373
380
|
const creatingStore = !fs.existsSync(this.lancedbDir);
|
|
374
381
|
if (creatingStore) {
|
|
375
|
-
|
|
382
|
+
this.assertMutationAllowed();
|
|
376
383
|
(0, maintenance_policy_1.assertFreshDiskMutationAllowed)(this.lancedbDir);
|
|
377
384
|
}
|
|
378
385
|
yield this.getLease();
|
|
@@ -381,11 +388,11 @@ class VectorDB {
|
|
|
381
388
|
}
|
|
382
389
|
if (!this.db) {
|
|
383
390
|
if (creatingStore || !fs.existsSync(this.lancedbDir)) {
|
|
384
|
-
|
|
391
|
+
this.assertMutationAllowed();
|
|
385
392
|
(0, maintenance_policy_1.assertFreshDiskMutationAllowed)(this.lancedbDir);
|
|
386
393
|
}
|
|
387
394
|
fs.mkdirSync(this.lancedbDir, { recursive: true });
|
|
388
|
-
this.session = createLanceSession();
|
|
395
|
+
this.session = createLanceSession(this.options);
|
|
389
396
|
// 0.38 accepts the legacy third argument in its types but drops it in
|
|
390
397
|
// the JS wrapper. Put the session in native ConnectionOptions instead.
|
|
391
398
|
this.db = yield lancedb.connect(this.lancedbDir, {
|
|
@@ -430,6 +437,7 @@ class VectorDB {
|
|
|
430
437
|
/** Upgrade and retain this instance's current lease for transfer to a new DB. */
|
|
431
438
|
upgradeStoreLease(signal) {
|
|
432
439
|
return __awaiter(this, void 0, void 0, function* () {
|
|
440
|
+
this.assertMutationAllowed();
|
|
433
441
|
if (this.closed)
|
|
434
442
|
throw new Error("VectorDB connection is closed");
|
|
435
443
|
if (this.exclusiveMutationPromise)
|
|
@@ -526,7 +534,7 @@ class VectorDB {
|
|
|
526
534
|
*/
|
|
527
535
|
withWriteGate(fn) {
|
|
528
536
|
return __awaiter(this, void 0, void 0, function* () {
|
|
529
|
-
|
|
537
|
+
this.assertMutationAllowed();
|
|
530
538
|
this.ensureDiskOk();
|
|
531
539
|
while (this.exclusiveMutationPromise || this.compactingPromise) {
|
|
532
540
|
if (this.closed)
|
|
@@ -535,7 +543,7 @@ class VectorDB {
|
|
|
535
543
|
}
|
|
536
544
|
if (this.closed)
|
|
537
545
|
throw new Error("VectorDB connection is closed");
|
|
538
|
-
|
|
546
|
+
this.assertMutationAllowed();
|
|
539
547
|
this.ensureDiskOk();
|
|
540
548
|
this.activeWrites++;
|
|
541
549
|
try {
|
|
@@ -575,7 +583,7 @@ class VectorDB {
|
|
|
575
583
|
}
|
|
576
584
|
withExclusiveTableMutation(mutation) {
|
|
577
585
|
return __awaiter(this, void 0, void 0, function* () {
|
|
578
|
-
|
|
586
|
+
this.assertMutationAllowed();
|
|
579
587
|
this.ensureDiskOk();
|
|
580
588
|
if (this.closed)
|
|
581
589
|
throw new Error("VectorDB connection is closed");
|
|
@@ -602,7 +610,7 @@ class VectorDB {
|
|
|
602
610
|
});
|
|
603
611
|
}
|
|
604
612
|
yield Promise.all([this.drainWrites(), this.drainCompactions()]);
|
|
605
|
-
|
|
613
|
+
this.assertMutationAllowed();
|
|
606
614
|
this.ensureDiskOk();
|
|
607
615
|
const db = yield this.getDb();
|
|
608
616
|
const result = yield mutation(db);
|
|
@@ -773,7 +781,8 @@ class VectorDB {
|
|
|
773
781
|
}
|
|
774
782
|
ensureTable() {
|
|
775
783
|
return __awaiter(this, void 0, void 0, function* () {
|
|
776
|
-
if (
|
|
784
|
+
if (this.options.readOnly ||
|
|
785
|
+
(0, maintenance_policy_1.storeMutationDeniedReason)() !== null ||
|
|
777
786
|
this.checkDiskPressure(true) === "critical") {
|
|
778
787
|
const existing = yield this.openExistingTableUnsafe();
|
|
779
788
|
if (!existing)
|
|
@@ -794,7 +803,7 @@ class VectorDB {
|
|
|
794
803
|
catch (err) {
|
|
795
804
|
if (!isMissingTableError(err))
|
|
796
805
|
throw err;
|
|
797
|
-
|
|
806
|
+
this.assertMutationAllowed();
|
|
798
807
|
(0, logger_1.log)("db", `Creating table (${this.vectorDim}d)`);
|
|
799
808
|
const schema = this.buildSchema();
|
|
800
809
|
table = yield db.createTable(TABLE_NAME, [this.seedRow()], {
|
|
@@ -805,7 +814,7 @@ class VectorDB {
|
|
|
805
814
|
return table;
|
|
806
815
|
}
|
|
807
816
|
yield this.validateSchema(table);
|
|
808
|
-
|
|
817
|
+
this.assertMutationAllowed();
|
|
809
818
|
yield this.evolveSchema(table);
|
|
810
819
|
return table;
|
|
811
820
|
});
|
|
@@ -944,7 +953,7 @@ class VectorDB {
|
|
|
944
953
|
}
|
|
945
954
|
/** Whether this instance may create or rebuild shared indexes. */
|
|
946
955
|
canBuildIndexes() {
|
|
947
|
-
return this.indexOwner;
|
|
956
|
+
return this.indexOwner && !this.options.readOnly;
|
|
948
957
|
}
|
|
949
958
|
/**
|
|
950
959
|
* Adopt the FTS index if one already exists, without ever building it.
|
|
@@ -92,14 +92,19 @@ function spawnDaemon() {
|
|
|
92
92
|
* spawn fails.
|
|
93
93
|
*/
|
|
94
94
|
function spawnDaemonProcess() {
|
|
95
|
-
return __awaiter(this,
|
|
95
|
+
return __awaiter(this, arguments, void 0, function* (options = {}) {
|
|
96
96
|
const denied = (0, autostart_1.daemonStartDeniedReason)();
|
|
97
|
-
if (denied !== null)
|
|
97
|
+
if (denied !== null && !options.readOnly)
|
|
98
98
|
throw new Error(`gmax: ${denied}`);
|
|
99
99
|
const logFile = path.join(config_1.PATHS.logsDir, "daemon.log");
|
|
100
100
|
const out = (0, log_rotate_1.openRotatedLog)(logFile);
|
|
101
101
|
try {
|
|
102
|
-
const child = (0, node_child_process_1.spawn)(process.argv[0], [
|
|
102
|
+
const child = (0, node_child_process_1.spawn)(process.argv[0], [
|
|
103
|
+
process.argv[1],
|
|
104
|
+
"watch",
|
|
105
|
+
"--daemon",
|
|
106
|
+
...(options.readOnly ? ["--read-only"] : []),
|
|
107
|
+
], {
|
|
103
108
|
detached: true,
|
|
104
109
|
stdio: ["ignore", out, out],
|
|
105
110
|
cwd: process.cwd(),
|
|
@@ -122,6 +122,12 @@ class OperationCoordinator {
|
|
|
122
122
|
void task.then(cleanup, cleanup);
|
|
123
123
|
return task;
|
|
124
124
|
}
|
|
125
|
+
/** Cancel existing work without closing admission for subsequent bounded reads. */
|
|
126
|
+
abortAndDrain(reason) {
|
|
127
|
+
for (const controller of this.controllers)
|
|
128
|
+
controller.abort(reason);
|
|
129
|
+
return Promise.allSettled([...this.activeTasks]).then(() => { });
|
|
130
|
+
}
|
|
125
131
|
close(reason = new OperationClosedError()) {
|
|
126
132
|
if (this.closePromise)
|
|
127
133
|
return this.closePromise;
|
package/package.json
CHANGED