grepmax 0.8.2 → 0.9.1
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/add.js +1 -1
- package/dist/commands/index.js +24 -20
- package/dist/commands/mcp.js +11 -4
- package/dist/commands/remove.js +13 -6
- package/dist/commands/search.js +1 -1
- package/dist/commands/watch.js +85 -12
- package/dist/config.js +1 -0
- package/dist/lib/daemon/daemon.js +314 -0
- package/dist/lib/daemon/ipc-handler.js +53 -0
- package/dist/lib/index/batch-processor.js +286 -0
- package/dist/lib/index/watcher.js +8 -228
- package/dist/lib/utils/daemon-client.js +108 -0
- package/dist/lib/utils/daemon-launcher.js +59 -0
- package/dist/lib/utils/watcher-launcher.js +78 -36
- package/dist/lib/utils/watcher-store.js +42 -0
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/hooks/start.js +7 -2
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.spawnDaemon = spawnDaemon;
|
|
37
|
+
const node_child_process_1 = require("node:child_process");
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const config_1 = require("../../config");
|
|
40
|
+
const log_rotate_1 = require("./log-rotate");
|
|
41
|
+
/**
|
|
42
|
+
* Spawn the daemon in background mode.
|
|
43
|
+
* Returns the child PID, or null on failure.
|
|
44
|
+
*/
|
|
45
|
+
function spawnDaemon() {
|
|
46
|
+
var _a;
|
|
47
|
+
try {
|
|
48
|
+
const logFile = path.join(config_1.PATHS.logsDir, "daemon.log");
|
|
49
|
+
const out = (0, log_rotate_1.openRotatedLog)(logFile);
|
|
50
|
+
const child = (0, node_child_process_1.spawn)(process.argv[0], [process.argv[1], "watch", "--daemon", "-b"], { detached: true, stdio: ["ignore", out, out] });
|
|
51
|
+
child.unref();
|
|
52
|
+
return (_a = child.pid) !== null && _a !== void 0 ? _a : null;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
56
|
+
console.error(`[daemon-launcher] Failed to spawn daemon: ${msg}`);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -2,47 +2,89 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Centralized watcher launch logic.
|
|
4
4
|
* Single function that all code paths use to spawn a watcher.
|
|
5
|
+
* Tries daemon IPC first, falls back to per-project spawn.
|
|
5
6
|
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
6
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
17
|
exports.launchWatcher = launchWatcher;
|
|
8
18
|
const node_child_process_1 = require("node:child_process");
|
|
19
|
+
const daemon_client_1 = require("./daemon-client");
|
|
20
|
+
const daemon_launcher_1 = require("./daemon-launcher");
|
|
9
21
|
const project_registry_1 = require("./project-registry");
|
|
10
22
|
const watcher_store_1 = require("./watcher-store");
|
|
11
23
|
function launchWatcher(projectRoot) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
var _a;
|
|
26
|
+
// 1. Project must be registered
|
|
27
|
+
const project = (0, project_registry_1.getProject)(projectRoot);
|
|
28
|
+
if (!project) {
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
reason: "not-registered",
|
|
32
|
+
message: `Project not registered. Run: gmax add ${projectRoot}`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// 2. Check if watcher already running (daemon registers per-project entries)
|
|
36
|
+
const existing = (_a = (0, watcher_store_1.getWatcherForProject)(projectRoot)) !== null && _a !== void 0 ? _a : (0, watcher_store_1.getWatcherCoveringPath)(projectRoot);
|
|
37
|
+
if (existing && (0, watcher_store_1.isProcessRunning)(existing.pid)) {
|
|
38
|
+
return { ok: true, pid: existing.pid, reused: true };
|
|
39
|
+
}
|
|
40
|
+
// 3. Try daemon IPC
|
|
41
|
+
let resp;
|
|
42
|
+
try {
|
|
43
|
+
resp = yield (0, daemon_client_1.sendDaemonCommand)({ cmd: "watch", root: projectRoot });
|
|
44
|
+
}
|
|
45
|
+
catch (_b) {
|
|
46
|
+
resp = { ok: false, error: "request-failed" };
|
|
47
|
+
}
|
|
48
|
+
if (resp.ok && typeof resp.pid === "number") {
|
|
49
|
+
return { ok: true, pid: resp.pid, reused: true };
|
|
50
|
+
}
|
|
51
|
+
// 4. Daemon not running — try to start it, poll until ready
|
|
52
|
+
const error = resp.error;
|
|
53
|
+
if (error === "ENOENT" || error === "ECONNREFUSED") {
|
|
54
|
+
const daemonPid = (0, daemon_launcher_1.spawnDaemon)();
|
|
55
|
+
if (daemonPid) {
|
|
56
|
+
for (let i = 0; i < 25; i++) {
|
|
57
|
+
yield new Promise((r) => setTimeout(r, 200));
|
|
58
|
+
try {
|
|
59
|
+
const retry = yield (0, daemon_client_1.sendDaemonCommand)({ cmd: "watch", root: projectRoot });
|
|
60
|
+
if (retry.ok && typeof retry.pid === "number") {
|
|
61
|
+
return { ok: true, pid: retry.pid, reused: false };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (_c) { }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// 5. Fall back to per-project spawn
|
|
69
|
+
try {
|
|
70
|
+
const child = (0, node_child_process_1.spawn)(process.argv[0], [process.argv[1], "watch", "--path", projectRoot, "-b"], { detached: true, stdio: "ignore" });
|
|
71
|
+
child.unref();
|
|
72
|
+
if (child.pid) {
|
|
73
|
+
return { ok: true, pid: child.pid, reused: false };
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
reason: "spawn-failed",
|
|
78
|
+
message: `Spawn returned no PID for ${projectRoot}`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
83
|
+
return {
|
|
84
|
+
ok: false,
|
|
85
|
+
reason: "spawn-failed",
|
|
86
|
+
message: `Failed to start watcher for ${projectRoot}: ${msg}`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
});
|
|
48
90
|
}
|
|
@@ -41,6 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
};
|
|
42
42
|
})();
|
|
43
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.DAEMON_KEY = void 0;
|
|
44
45
|
exports.registerWatcher = registerWatcher;
|
|
45
46
|
exports.updateWatcherStatus = updateWatcherStatus;
|
|
46
47
|
exports.heartbeat = heartbeat;
|
|
@@ -49,6 +50,10 @@ exports.getWatcherForProject = getWatcherForProject;
|
|
|
49
50
|
exports.getWatcherCoveringPath = getWatcherCoveringPath;
|
|
50
51
|
exports.listWatchers = listWatchers;
|
|
51
52
|
exports.migrateFromJson = migrateFromJson;
|
|
53
|
+
exports.registerDaemon = registerDaemon;
|
|
54
|
+
exports.unregisterDaemon = unregisterDaemon;
|
|
55
|
+
exports.getDaemonInfo = getDaemonInfo;
|
|
56
|
+
exports.unregisterWatcherByRoot = unregisterWatcherByRoot;
|
|
52
57
|
exports.isProcessRunning = isProcessRunning;
|
|
53
58
|
const fs = __importStar(require("node:fs"));
|
|
54
59
|
const path = __importStar(require("node:path"));
|
|
@@ -154,6 +159,8 @@ function listWatchers() {
|
|
|
154
159
|
for (const { key, value } of db.getRange()) {
|
|
155
160
|
if (!value)
|
|
156
161
|
continue;
|
|
162
|
+
if (String(key) === exports.DAEMON_KEY)
|
|
163
|
+
continue;
|
|
157
164
|
if (isAlive(value)) {
|
|
158
165
|
alive.push(value);
|
|
159
166
|
}
|
|
@@ -191,3 +198,38 @@ function migrateFromJson() {
|
|
|
191
198
|
// Best effort — ignore
|
|
192
199
|
}
|
|
193
200
|
}
|
|
201
|
+
// --- Daemon registry ---
|
|
202
|
+
exports.DAEMON_KEY = "__daemon__";
|
|
203
|
+
function registerDaemon(pid) {
|
|
204
|
+
getDb().put(exports.DAEMON_KEY, {
|
|
205
|
+
pid,
|
|
206
|
+
projectRoot: exports.DAEMON_KEY,
|
|
207
|
+
startTime: Date.now(),
|
|
208
|
+
status: "watching",
|
|
209
|
+
lastHeartbeat: Date.now(),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function unregisterDaemon() {
|
|
213
|
+
try {
|
|
214
|
+
getDb().remove(exports.DAEMON_KEY);
|
|
215
|
+
}
|
|
216
|
+
catch (_a) { }
|
|
217
|
+
}
|
|
218
|
+
function getDaemonInfo() {
|
|
219
|
+
const info = getDb().get(exports.DAEMON_KEY);
|
|
220
|
+
if (info && isAlive(info))
|
|
221
|
+
return info;
|
|
222
|
+
if (info) {
|
|
223
|
+
try {
|
|
224
|
+
getDb().remove(exports.DAEMON_KEY);
|
|
225
|
+
}
|
|
226
|
+
catch (_a) { }
|
|
227
|
+
}
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
function unregisterWatcherByRoot(projectRoot) {
|
|
231
|
+
try {
|
|
232
|
+
getDb().remove(projectRoot);
|
|
233
|
+
}
|
|
234
|
+
catch (_a) { }
|
|
235
|
+
}
|
package/package.json
CHANGED
|
@@ -86,9 +86,14 @@ function isProjectRegistered() {
|
|
|
86
86
|
function startWatcher() {
|
|
87
87
|
if (!isProjectRegistered()) return;
|
|
88
88
|
try {
|
|
89
|
-
execFileSync("gmax", ["watch", "-b"], { timeout: 5000, stdio: "ignore" });
|
|
89
|
+
execFileSync("gmax", ["watch", "--daemon", "-b"], { timeout: 5000, stdio: "ignore" });
|
|
90
90
|
} catch {
|
|
91
|
-
//
|
|
91
|
+
// Fallback to per-project mode (older gmax without --daemon)
|
|
92
|
+
try {
|
|
93
|
+
execFileSync("gmax", ["watch", "-b"], { timeout: 5000, stdio: "ignore" });
|
|
94
|
+
} catch {
|
|
95
|
+
// Watcher may already be running or gmax not in PATH — ignore
|
|
96
|
+
}
|
|
92
97
|
}
|
|
93
98
|
}
|
|
94
99
|
|