grepmax 0.9.0 → 0.9.2
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/dist/commands/serve.js
CHANGED
|
@@ -208,7 +208,7 @@ exports.serve = new commander_1.Command("serve")
|
|
|
208
208
|
const metaCache = new meta_cache_1.MetaCache(paths.lmdbPath);
|
|
209
209
|
const searcher = new searcher_1.Searcher(vectorDb);
|
|
210
210
|
// Start live file watcher
|
|
211
|
-
let fileWatcher = (0, watcher_1.startWatcher)({
|
|
211
|
+
let fileWatcher = yield (0, watcher_1.startWatcher)({
|
|
212
212
|
projectRoot,
|
|
213
213
|
vectorDb,
|
|
214
214
|
metaCache,
|
package/dist/commands/watch.js
CHANGED
|
@@ -190,7 +190,7 @@ exports.watch = new commander_1.Command("watch")
|
|
|
190
190
|
// Open resources for watcher
|
|
191
191
|
const metaCache = new meta_cache_1.MetaCache(paths.lmdbPath);
|
|
192
192
|
// Start watching
|
|
193
|
-
const watcher = (0, watcher_1.startWatcher)({
|
|
193
|
+
const watcher = yield (0, watcher_1.startWatcher)({
|
|
194
194
|
projectRoot,
|
|
195
195
|
vectorDb,
|
|
196
196
|
metaCache,
|
|
@@ -46,7 +46,7 @@ exports.Daemon = void 0;
|
|
|
46
46
|
const fs = __importStar(require("node:fs"));
|
|
47
47
|
const net = __importStar(require("node:net"));
|
|
48
48
|
const path = __importStar(require("node:path"));
|
|
49
|
-
const
|
|
49
|
+
const watcher = __importStar(require("@parcel/watcher"));
|
|
50
50
|
const config_1 = require("../../config");
|
|
51
51
|
const batch_processor_1 = require("../index/batch-processor");
|
|
52
52
|
const watcher_1 = require("../index/watcher");
|
|
@@ -60,8 +60,8 @@ const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
|
60
60
|
const HEARTBEAT_INTERVAL_MS = 60 * 1000;
|
|
61
61
|
class Daemon {
|
|
62
62
|
constructor() {
|
|
63
|
-
this.watcher = null;
|
|
64
63
|
this.processors = new Map();
|
|
64
|
+
this.subscriptions = new Map();
|
|
65
65
|
this.vectorDb = null;
|
|
66
66
|
this.metaCache = null;
|
|
67
67
|
this.server = null;
|
|
@@ -70,9 +70,6 @@ class Daemon {
|
|
|
70
70
|
this.heartbeatInterval = null;
|
|
71
71
|
this.idleInterval = null;
|
|
72
72
|
this.shuttingDown = false;
|
|
73
|
-
// Sorted longest-first for prefix matching
|
|
74
|
-
this.sortedRoots = [];
|
|
75
|
-
// Guard against concurrent watchProject/unwatchProject
|
|
76
73
|
this.pendingOps = new Set();
|
|
77
74
|
}
|
|
78
75
|
start() {
|
|
@@ -100,37 +97,25 @@ class Daemon {
|
|
|
100
97
|
console.error("[daemon] Failed to open shared resources:", err);
|
|
101
98
|
throw err;
|
|
102
99
|
}
|
|
103
|
-
// 4.
|
|
104
|
-
const forcePoll = process.env.GMAX_WATCH_POLL === "1";
|
|
105
|
-
const usePoll = forcePoll || process.platform !== "darwin";
|
|
106
|
-
this.watcher = (0, chokidar_1.watch)([], Object.assign({ ignored: watcher_1.WATCHER_IGNORE_PATTERNS, ignoreInitial: true, persistent: true }, (usePoll
|
|
107
|
-
? { usePolling: true, interval: 5000, binaryInterval: 10000 }
|
|
108
|
-
: {})));
|
|
109
|
-
this.watcher.on("add", (p) => this.routeEvent("change", p));
|
|
110
|
-
this.watcher.on("change", (p) => this.routeEvent("change", p));
|
|
111
|
-
this.watcher.on("unlink", (p) => this.routeEvent("unlink", p));
|
|
112
|
-
this.watcher.on("error", (err) => {
|
|
113
|
-
console.error("[daemon] Watcher error:", err);
|
|
114
|
-
});
|
|
115
|
-
// 5. Register daemon (only after resources are open)
|
|
100
|
+
// 4. Register daemon (only after resources are open)
|
|
116
101
|
(0, watcher_store_1.registerDaemon)(process.pid);
|
|
117
|
-
//
|
|
102
|
+
// 5. Subscribe to all registered projects
|
|
118
103
|
const projects = (0, project_registry_1.listProjects)().filter((p) => p.status === "indexed");
|
|
119
104
|
for (const p of projects) {
|
|
120
105
|
yield this.watchProject(p.root);
|
|
121
106
|
}
|
|
122
|
-
//
|
|
107
|
+
// 6. Heartbeat
|
|
123
108
|
this.heartbeatInterval = setInterval(() => {
|
|
124
109
|
(0, watcher_store_1.heartbeat)(process.pid);
|
|
125
110
|
}, HEARTBEAT_INTERVAL_MS);
|
|
126
|
-
//
|
|
111
|
+
// 7. Idle timeout
|
|
127
112
|
this.idleInterval = setInterval(() => {
|
|
128
113
|
if (Date.now() - this.lastActivity > IDLE_TIMEOUT_MS) {
|
|
129
114
|
console.log("[daemon] Idle for 30 minutes, shutting down");
|
|
130
115
|
this.shutdown();
|
|
131
116
|
}
|
|
132
117
|
}, HEARTBEAT_INTERVAL_MS);
|
|
133
|
-
//
|
|
118
|
+
// 8. Socket server
|
|
134
119
|
this.server = net.createServer((conn) => {
|
|
135
120
|
let buf = "";
|
|
136
121
|
conn.on("data", (chunk) => {
|
|
@@ -154,7 +139,7 @@ class Daemon {
|
|
|
154
139
|
conn.end();
|
|
155
140
|
});
|
|
156
141
|
});
|
|
157
|
-
conn.on("error", () => { });
|
|
142
|
+
conn.on("error", () => { });
|
|
158
143
|
});
|
|
159
144
|
yield new Promise((resolve, reject) => {
|
|
160
145
|
this.server.on("error", (err) => {
|
|
@@ -181,7 +166,7 @@ class Daemon {
|
|
|
181
166
|
return __awaiter(this, void 0, void 0, function* () {
|
|
182
167
|
if (this.processors.has(root) || this.pendingOps.has(root))
|
|
183
168
|
return;
|
|
184
|
-
if (!this.vectorDb || !this.metaCache
|
|
169
|
+
if (!this.vectorDb || !this.metaCache)
|
|
185
170
|
return;
|
|
186
171
|
this.pendingOps.add(root);
|
|
187
172
|
const processor = new batch_processor_1.ProjectBatchProcessor({
|
|
@@ -196,9 +181,19 @@ class Daemon {
|
|
|
196
181
|
this.lastActivity = Date.now();
|
|
197
182
|
},
|
|
198
183
|
});
|
|
199
|
-
this.watcher.add(root);
|
|
200
184
|
this.processors.set(root, processor);
|
|
201
|
-
|
|
185
|
+
// Subscribe with @parcel/watcher — native backend, no polling
|
|
186
|
+
const sub = yield watcher.subscribe(root, (err, events) => {
|
|
187
|
+
if (err) {
|
|
188
|
+
console.error(`[daemon:${path.basename(root)}] Watcher error:`, err);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
for (const event of events) {
|
|
192
|
+
processor.handleFileEvent(event.type === "delete" ? "unlink" : "change", event.path);
|
|
193
|
+
}
|
|
194
|
+
this.lastActivity = Date.now();
|
|
195
|
+
}, { ignore: watcher_1.WATCHER_IGNORE_GLOBS });
|
|
196
|
+
this.subscriptions.set(root, sub);
|
|
202
197
|
(0, watcher_store_1.registerWatcher)({
|
|
203
198
|
pid: process.pid,
|
|
204
199
|
projectRoot: root,
|
|
@@ -212,14 +207,16 @@ class Daemon {
|
|
|
212
207
|
}
|
|
213
208
|
unwatchProject(root) {
|
|
214
209
|
return __awaiter(this, void 0, void 0, function* () {
|
|
215
|
-
var _a;
|
|
216
210
|
const processor = this.processors.get(root);
|
|
217
211
|
if (!processor)
|
|
218
212
|
return;
|
|
219
213
|
yield processor.close();
|
|
220
|
-
|
|
214
|
+
const sub = this.subscriptions.get(root);
|
|
215
|
+
if (sub) {
|
|
216
|
+
yield sub.unsubscribe();
|
|
217
|
+
this.subscriptions.delete(root);
|
|
218
|
+
}
|
|
221
219
|
this.processors.delete(root);
|
|
222
|
-
this.rebuildSortedRoots();
|
|
223
220
|
(0, watcher_store_1.unregisterWatcherByRoot)(root);
|
|
224
221
|
console.log(`[daemon] Unwatched ${root}`);
|
|
225
222
|
});
|
|
@@ -235,7 +232,7 @@ class Daemon {
|
|
|
235
232
|
}
|
|
236
233
|
shutdown() {
|
|
237
234
|
return __awaiter(this, void 0, void 0, function* () {
|
|
238
|
-
var _a, _b, _c
|
|
235
|
+
var _a, _b, _c;
|
|
239
236
|
if (this.shuttingDown)
|
|
240
237
|
return;
|
|
241
238
|
this.shuttingDown = true;
|
|
@@ -248,17 +245,20 @@ class Daemon {
|
|
|
248
245
|
for (const processor of this.processors.values()) {
|
|
249
246
|
yield processor.close();
|
|
250
247
|
}
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
248
|
+
// Unsubscribe all watchers
|
|
249
|
+
for (const sub of this.subscriptions.values()) {
|
|
250
|
+
try {
|
|
251
|
+
yield sub.unsubscribe();
|
|
252
|
+
}
|
|
253
|
+
catch (_d) { }
|
|
254
254
|
}
|
|
255
|
-
|
|
255
|
+
this.subscriptions.clear();
|
|
256
256
|
// Close server + socket
|
|
257
|
-
(
|
|
257
|
+
(_a = this.server) === null || _a === void 0 ? void 0 : _a.close();
|
|
258
258
|
try {
|
|
259
259
|
fs.unlinkSync(config_1.PATHS.daemonSocket);
|
|
260
260
|
}
|
|
261
|
-
catch (
|
|
261
|
+
catch (_e) { }
|
|
262
262
|
// Unregister all
|
|
263
263
|
for (const root of this.processors.keys()) {
|
|
264
264
|
(0, watcher_store_1.unregisterWatcherByRoot)(root);
|
|
@@ -267,33 +267,15 @@ class Daemon {
|
|
|
267
267
|
this.processors.clear();
|
|
268
268
|
// Close shared resources
|
|
269
269
|
try {
|
|
270
|
-
yield ((
|
|
270
|
+
yield ((_b = this.metaCache) === null || _b === void 0 ? void 0 : _b.close());
|
|
271
271
|
}
|
|
272
|
-
catch (
|
|
272
|
+
catch (_f) { }
|
|
273
273
|
try {
|
|
274
|
-
yield ((
|
|
274
|
+
yield ((_c = this.vectorDb) === null || _c === void 0 ? void 0 : _c.close());
|
|
275
275
|
}
|
|
276
|
-
catch (
|
|
276
|
+
catch (_g) { }
|
|
277
277
|
console.log("[daemon] Shutdown complete");
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
|
-
routeEvent(event, absPath) {
|
|
281
|
-
const processor = this.findProcessor(absPath);
|
|
282
|
-
if (processor) {
|
|
283
|
-
processor.handleFileEvent(event, absPath);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
findProcessor(absPath) {
|
|
287
|
-
// sortedRoots is longest-first, so first match is the most specific
|
|
288
|
-
for (const root of this.sortedRoots) {
|
|
289
|
-
if (absPath.startsWith(root) && (absPath.length === root.length || absPath[root.length] === "/")) {
|
|
290
|
-
return this.processors.get(root);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return undefined;
|
|
294
|
-
}
|
|
295
|
-
rebuildSortedRoots() {
|
|
296
|
-
this.sortedRoots = [...this.processors.keys()].sort((a, b) => b.length - a.length);
|
|
297
|
-
}
|
|
298
280
|
}
|
|
299
281
|
exports.Daemon = Daemon;
|
|
@@ -42,52 +42,46 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.
|
|
45
|
+
exports.WATCHER_IGNORE_GLOBS = void 0;
|
|
46
46
|
exports.startWatcher = startWatcher;
|
|
47
|
-
const
|
|
48
|
-
const chokidar_1 = require("chokidar");
|
|
47
|
+
const watcher = __importStar(require("@parcel/watcher"));
|
|
49
48
|
const batch_processor_1 = require("./batch-processor");
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
/(^|[/\\])\../, // dotfiles
|
|
49
|
+
// Ignore patterns for @parcel/watcher (micromatch globs + directory names).
|
|
50
|
+
// Directory names are matched at any depth automatically.
|
|
51
|
+
exports.WATCHER_IGNORE_GLOBS = [
|
|
52
|
+
"node_modules",
|
|
53
|
+
".git",
|
|
54
|
+
".gmax",
|
|
55
|
+
"dist",
|
|
56
|
+
"build",
|
|
57
|
+
"out",
|
|
58
|
+
"target",
|
|
59
|
+
"__pycache__",
|
|
60
|
+
"coverage",
|
|
61
|
+
"venv",
|
|
62
|
+
".next",
|
|
63
|
+
"lancedb",
|
|
64
|
+
".*", // dotfiles
|
|
67
65
|
];
|
|
68
66
|
function startWatcher(opts) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
const { projectRoot } = opts;
|
|
69
|
+
const wtag = `watch:${projectRoot.split("/").pop()}`;
|
|
70
|
+
const processor = new batch_processor_1.ProjectBatchProcessor(opts);
|
|
71
|
+
const subscription = yield watcher.subscribe(projectRoot, (err, events) => {
|
|
72
|
+
if (err) {
|
|
73
|
+
console.error(`[${wtag}] Watcher error:`, err);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
for (const event of events) {
|
|
77
|
+
processor.handleFileEvent(event.type === "delete" ? "unlink" : "change", event.path);
|
|
78
|
+
}
|
|
79
|
+
}, { ignore: exports.WATCHER_IGNORE_GLOBS });
|
|
80
|
+
return {
|
|
81
|
+
close: () => __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
yield processor.close();
|
|
83
|
+
yield subscription.unsubscribe();
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
83
86
|
});
|
|
84
|
-
watcher.on("add", (p) => processor.handleFileEvent("change", p));
|
|
85
|
-
watcher.on("change", (p) => processor.handleFileEvent("change", p));
|
|
86
|
-
watcher.on("unlink", (p) => processor.handleFileEvent("unlink", p));
|
|
87
|
-
return {
|
|
88
|
-
close: () => __awaiter(this, void 0, void 0, function* () {
|
|
89
|
-
yield processor.close();
|
|
90
|
-
yield watcher.close();
|
|
91
|
-
}),
|
|
92
|
-
};
|
|
93
87
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grepmax",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"author": "Robert Owens <robowens@me.com>",
|
|
5
5
|
"homepage": "https://github.com/reowens/grepmax",
|
|
6
6
|
"bugs": {
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"@huggingface/transformers": "^4.0.0",
|
|
37
37
|
"@lancedb/lancedb": "^0.27.1",
|
|
38
38
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
39
|
+
"@parcel/watcher": "^2.5.6",
|
|
39
40
|
"apache-arrow": "^18.1.0",
|
|
40
41
|
"chalk": "^5.6.2",
|
|
41
|
-
"chokidar": "^5.0.0",
|
|
42
42
|
"cli-highlight": "^2.1.11",
|
|
43
43
|
"commander": "^14.0.2",
|
|
44
44
|
"dotenv": "^17.2.3",
|