@mnemonik/scanner 5.136.2 → 5.151.0
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/package.json +2 -2
- package/src/client.ts +12 -2
- package/dist/client.d.ts +0 -99
- package/dist/client.js +0 -131
- package/dist/client.js.map +0 -1
- package/dist/daemon.d.ts +0 -51
- package/dist/daemon.js +0 -550
- package/dist/daemon.js.map +0 -1
- package/dist/discovery.d.ts +0 -21
- package/dist/discovery.js +0 -107
- package/dist/discovery.js.map +0 -1
- package/dist/doctor.d.ts +0 -1
- package/dist/doctor.js +0 -233
- package/dist/doctor.js.map +0 -1
- package/dist/fileLog.d.ts +0 -17
- package/dist/fileLog.js +0 -70
- package/dist/fileLog.js.map +0 -1
- package/dist/git.d.ts +0 -31
- package/dist/git.js +0 -111
- package/dist/git.js.map +0 -1
- package/dist/index.d.ts +0 -15
- package/dist/index.js +0 -399
- package/dist/index.js.map +0 -1
- package/dist/pid.d.ts +0 -1
- package/dist/pid.js +0 -37
- package/dist/pid.js.map +0 -1
- package/dist/watcher.d.ts +0 -30
- package/dist/watcher.js +0 -214
- package/dist/watcher.js.map +0 -1
package/dist/index.js
DELETED
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { readFile, writeFile, unlink, mkdir, stat, chmod } from 'fs/promises';
|
|
3
|
-
import { existsSync } from 'fs';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
import { homedir } from 'os';
|
|
6
|
-
import { ScannerDaemon } from './daemon.js';
|
|
7
|
-
import { installFileLogging } from './fileLog.js';
|
|
8
|
-
import { runDoctor } from './doctor.js';
|
|
9
|
-
import { pidIsScanner } from './pid.js';
|
|
10
|
-
const DEFAULT_SERVER = 'https://api.mnemonik.dev';
|
|
11
|
-
const LOCAL_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
|
|
12
|
-
/**
|
|
13
|
-
* Reject plaintext http:// server URLs except when talking to a local
|
|
14
|
-
* daemon on the same machine (localhost/127.0.0.1/[::1]) — e.g. during
|
|
15
|
-
* development against a locally-run server. Everything else must be https://
|
|
16
|
-
* since the scanner pushes full file content (see O2/O8b,
|
|
17
|
-
* codebase-indexing-audit-2026-07-02.md §5) and a plaintext channel would
|
|
18
|
-
* expose that content (and the API key) to network eavesdropping.
|
|
19
|
-
* Extracted as a pure function so the guard is unit-testable without
|
|
20
|
-
* spinning up the CLI.
|
|
21
|
-
*/
|
|
22
|
-
export function validateServerUrl(url) {
|
|
23
|
-
let parsed;
|
|
24
|
-
try {
|
|
25
|
-
parsed = new URL(url);
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
return { valid: false, error: `[mnemonik] Invalid --server URL: "${url}"` };
|
|
29
|
-
}
|
|
30
|
-
if (parsed.protocol !== 'https:' && !LOCAL_HOSTS.has(parsed.hostname)) {
|
|
31
|
-
return {
|
|
32
|
-
valid: false,
|
|
33
|
-
error: `[mnemonik] Refusing insecure server URL "${url}".\n` +
|
|
34
|
-
' Only https:// is allowed for --server, except for localhost/127.0.0.1/[::1]\n' +
|
|
35
|
-
' (used for local development). Scanned file content and your API key would\n' +
|
|
36
|
-
' otherwise be sent in plaintext.',
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
return { valid: true };
|
|
40
|
-
}
|
|
41
|
-
const MNEMONIK_DIR = join(homedir(), '.mnemonik');
|
|
42
|
-
const PID_FILE = join(MNEMONIK_DIR, 'daemon.pid');
|
|
43
|
-
const LOG_FILE = join(MNEMONIK_DIR, 'scanner.log');
|
|
44
|
-
const CONFIG_FILE = join(MNEMONIK_DIR, 'scanner.json');
|
|
45
|
-
const MAX_LOG_SIZE = 5 * 1024 * 1024; // 5MB
|
|
46
|
-
function parseCliArgs() {
|
|
47
|
-
const args = process.argv.slice(2);
|
|
48
|
-
const command = (args[0] ?? 'help');
|
|
49
|
-
if (!['start', 'stop', 'status', 'log', 'doctor', 'help'].includes(command)) {
|
|
50
|
-
return { command: 'help' };
|
|
51
|
-
}
|
|
52
|
-
let key;
|
|
53
|
-
let server;
|
|
54
|
-
let roots;
|
|
55
|
-
for (let i = 1; i < args.length; i++) {
|
|
56
|
-
if (args[i] === '--key' && args[i + 1])
|
|
57
|
-
key = args[++i];
|
|
58
|
-
else if (args[i] === '--server' && args[i + 1])
|
|
59
|
-
server = args[++i];
|
|
60
|
-
else if (args[i] === '--roots' && args[i + 1]) {
|
|
61
|
-
roots = args[++i].split(',').map((r) => r.trim());
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return { command, key, server, roots };
|
|
65
|
-
}
|
|
66
|
-
async function readConfig() {
|
|
67
|
-
try {
|
|
68
|
-
const raw = await readFile(CONFIG_FILE, 'utf-8');
|
|
69
|
-
return JSON.parse(raw);
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
async function writeConfig(config) {
|
|
76
|
-
await mkdir(MNEMONIK_DIR, { recursive: true });
|
|
77
|
-
await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
78
|
-
}
|
|
79
|
-
async function checkConfigPermissions() {
|
|
80
|
-
try {
|
|
81
|
-
const s = await stat(CONFIG_FILE);
|
|
82
|
-
// Check if group or other have read/write permissions
|
|
83
|
-
const mode = s.mode & 0o077;
|
|
84
|
-
if (mode !== 0) {
|
|
85
|
-
console.warn(`[mnemonik] WARNING: ${CONFIG_FILE} has overly permissive permissions (${(s.mode & 0o777).toString(8)}).`);
|
|
86
|
-
console.warn(`[mnemonik] Fixing to 0600 (owner read/write only).`);
|
|
87
|
-
await chmod(CONFIG_FILE, 0o600);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
// Config file doesn't exist yet
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
async function acquireLock(retried = false) {
|
|
95
|
-
try {
|
|
96
|
-
const { open: fsOpen } = await import('fs/promises');
|
|
97
|
-
const { constants } = await import('fs');
|
|
98
|
-
const fd = await fsOpen(PID_FILE, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o644);
|
|
99
|
-
await fd.writeFile(String(process.pid));
|
|
100
|
-
await fd.close();
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
catch (err) {
|
|
104
|
-
if (err.code !== 'EEXIST')
|
|
105
|
-
return false;
|
|
106
|
-
const existing = await readFile(PID_FILE, 'utf-8').catch(() => null);
|
|
107
|
-
if (existing) {
|
|
108
|
-
const pid = parseInt(existing.trim(), 10);
|
|
109
|
-
try {
|
|
110
|
-
process.kill(pid, 0);
|
|
111
|
-
// Alive is not enough — after PID reuse the number can belong to an
|
|
112
|
-
// unrelated process. Only an actual scanner holds the lock.
|
|
113
|
-
if (pidIsScanner(pid)) {
|
|
114
|
-
return false; // Process alive and is the scanner — lock is valid
|
|
115
|
-
}
|
|
116
|
-
// Live but foreign PID — treat as stale and reclaim below.
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
// Holder is dead — remove stale lock and retry once
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (retried)
|
|
123
|
-
return false;
|
|
124
|
-
await unlink(PID_FILE).catch(() => { });
|
|
125
|
-
return acquireLock(true);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
async function releaseLock() {
|
|
129
|
-
await unlink(PID_FILE).catch(() => { });
|
|
130
|
-
}
|
|
131
|
-
async function readPid() {
|
|
132
|
-
try {
|
|
133
|
-
const raw = await readFile(PID_FILE, 'utf-8');
|
|
134
|
-
const pid = parseInt(raw.trim(), 10);
|
|
135
|
-
if (isNaN(pid))
|
|
136
|
-
return null;
|
|
137
|
-
// Check if process is actually alive
|
|
138
|
-
try {
|
|
139
|
-
process.kill(pid, 0);
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
return null; // Stale PID
|
|
143
|
-
}
|
|
144
|
-
// Alive but foreign (PID reuse) is just as stale — never report it as
|
|
145
|
-
// the daemon, and never let handleStop() SIGTERM it.
|
|
146
|
-
if (!pidIsScanner(pid))
|
|
147
|
-
return null;
|
|
148
|
-
return pid;
|
|
149
|
-
}
|
|
150
|
-
catch {
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
function printHelp() {
|
|
155
|
-
console.log(`
|
|
156
|
-
mnemonik-scanner - Automatic codebase indexing daemon
|
|
157
|
-
|
|
158
|
-
Usage:
|
|
159
|
-
mnemonik-scanner start [options] Start the scanner daemon
|
|
160
|
-
mnemonik-scanner stop Stop the running daemon
|
|
161
|
-
mnemonik-scanner status Show daemon status
|
|
162
|
-
mnemonik-scanner log Tail the scanner log file
|
|
163
|
-
mnemonik-scanner doctor Check install health (drift detection)
|
|
164
|
-
mnemonik-scanner help Show this help
|
|
165
|
-
|
|
166
|
-
Options (for start):
|
|
167
|
-
--key <api-key> API key (or set MNEMONIK_API_KEY env var)
|
|
168
|
-
--server <url> Server URL (default: https://api.mnemonik.dev)
|
|
169
|
-
--roots <dirs> Comma-separated directories to scan for projects
|
|
170
|
-
|
|
171
|
-
Examples:
|
|
172
|
-
mnemonik-scanner start --key mnk_... --roots ~/Projects,~/work
|
|
173
|
-
mnemonik-scanner status
|
|
174
|
-
mnemonik-scanner stop
|
|
175
|
-
|
|
176
|
-
Configuration is saved to ~/.mnemonik/scanner.json after first run.
|
|
177
|
-
Subsequent starts use saved config (CLI args override).
|
|
178
|
-
|
|
179
|
-
Environment variables:
|
|
180
|
-
MNEMONIK_API_KEY API key (takes precedence over config file)
|
|
181
|
-
`);
|
|
182
|
-
}
|
|
183
|
-
async function handleStart(cli) {
|
|
184
|
-
// Guardrail — this daemon is meant to run under the systemd user service
|
|
185
|
-
// (`systemctl --user start mnemonik-scanner`; see BUILD_AND_DEPLOY.md
|
|
186
|
-
// "Scanner daemon"). systemd sets INVOCATION_ID on processes it spawns. A
|
|
187
|
-
// manual foreground `start` attaches the daemon to the invoking shell: it
|
|
188
|
-
// dies when the shell exits and can spawn duplicate/stale daemons — the exact
|
|
189
|
-
// failure mode behind version skew and apparent "restart loops". If a unit
|
|
190
|
-
// exists but we were NOT launched by systemd, refuse (overridable).
|
|
191
|
-
if (!process.env.INVOCATION_ID && !process.env.MNEMONIK_SCANNER_FOREGROUND) {
|
|
192
|
-
const unitPath = join(homedir(), '.config/systemd/user/mnemonik-scanner.service');
|
|
193
|
-
if (existsSync(unitPath)) {
|
|
194
|
-
console.error('[mnemonik] A systemd unit already manages this scanner.\n' +
|
|
195
|
-
' Start/restart it with:\n' +
|
|
196
|
-
' systemctl --user restart mnemonik-scanner\n' +
|
|
197
|
-
' Running `mnemonik-scanner start` by hand attaches the daemon to your shell — it\n' +
|
|
198
|
-
' dies when the shell exits and can leave duplicate/stale daemons running (version\n' +
|
|
199
|
-
' skew, apparent "restart loops"). To force a foreground run, set\n' +
|
|
200
|
-
' MNEMONIK_SCANNER_FOREGROUND=1.');
|
|
201
|
-
process.exit(1);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
const config = await readConfig();
|
|
205
|
-
// Resolve API key: env var > CLI > config
|
|
206
|
-
const apiKey = process.env.MNEMONIK_API_KEY || cli.key || config?.apiKey;
|
|
207
|
-
if (!apiKey) {
|
|
208
|
-
console.error('[mnemonik] Missing API key.\n' +
|
|
209
|
-
' Use --key <api-key>, set MNEMONIK_API_KEY env var,\n' +
|
|
210
|
-
' or run once with --key to save to config.');
|
|
211
|
-
process.exit(1);
|
|
212
|
-
}
|
|
213
|
-
const roots = cli.roots || config?.roots;
|
|
214
|
-
if (!roots || roots.length === 0) {
|
|
215
|
-
console.error('[mnemonik] No roots specified.\n' +
|
|
216
|
-
' Use --roots ~/Projects,~/work to specify directories to scan.');
|
|
217
|
-
process.exit(1);
|
|
218
|
-
}
|
|
219
|
-
const server = cli.server || config?.server || DEFAULT_SERVER;
|
|
220
|
-
const serverUrlCheck = validateServerUrl(server);
|
|
221
|
-
if (!serverUrlCheck.valid) {
|
|
222
|
-
console.error(serverUrlCheck.error);
|
|
223
|
-
process.exit(1);
|
|
224
|
-
}
|
|
225
|
-
// Ensure directories exist
|
|
226
|
-
await mkdir(MNEMONIK_DIR, { recursive: true });
|
|
227
|
-
// Mirror all console output into scanner.log so `mnemonik-scanner log`
|
|
228
|
-
// reflects live activity regardless of supervisor. Under systemd, stdout is
|
|
229
|
-
// wired to the journal socket, not this file — without the tee the on-disk
|
|
230
|
-
// log goes stale and `log` shows nothing current. Install before any daemon
|
|
231
|
-
// output so the whole session is captured.
|
|
232
|
-
installFileLogging(LOG_FILE, MAX_LOG_SIZE);
|
|
233
|
-
// Save config for future runs (never save env var key to file)
|
|
234
|
-
const configToSave = {
|
|
235
|
-
roots,
|
|
236
|
-
server,
|
|
237
|
-
refreshIntervalMs: config?.refreshIntervalMs,
|
|
238
|
-
};
|
|
239
|
-
// Only save API key to config if it came from CLI (not env var)
|
|
240
|
-
if (cli.key) {
|
|
241
|
-
configToSave.apiKey = cli.key;
|
|
242
|
-
}
|
|
243
|
-
else if (config?.apiKey && !process.env.MNEMONIK_API_KEY) {
|
|
244
|
-
configToSave.apiKey = config.apiKey;
|
|
245
|
-
}
|
|
246
|
-
await writeConfig(configToSave);
|
|
247
|
-
await checkConfigPermissions();
|
|
248
|
-
const locked = await acquireLock();
|
|
249
|
-
if (!locked) {
|
|
250
|
-
const pid = await readPid();
|
|
251
|
-
console.log(`[mnemonik] Scanner daemon already running (PID ${pid}). Use 'mnemonik-scanner stop' first.`);
|
|
252
|
-
process.exit(0);
|
|
253
|
-
}
|
|
254
|
-
const daemon = new ScannerDaemon({
|
|
255
|
-
serverUrl: server,
|
|
256
|
-
apiKey,
|
|
257
|
-
roots,
|
|
258
|
-
refreshIntervalMs: config?.refreshIntervalMs,
|
|
259
|
-
});
|
|
260
|
-
const shutdown = async () => {
|
|
261
|
-
console.log('\n[mnemonik] Shutting down...');
|
|
262
|
-
await daemon.stop();
|
|
263
|
-
await releaseLock();
|
|
264
|
-
process.exit(0);
|
|
265
|
-
};
|
|
266
|
-
process.on('SIGINT', shutdown);
|
|
267
|
-
process.on('SIGTERM', shutdown);
|
|
268
|
-
process.on('SIGHUP', shutdown); // Graceful restart — external tooling sends SIGHUP then relaunches
|
|
269
|
-
try {
|
|
270
|
-
await daemon.start();
|
|
271
|
-
}
|
|
272
|
-
catch (err) {
|
|
273
|
-
console.error(`[mnemonik] ${err.message}`);
|
|
274
|
-
await releaseLock();
|
|
275
|
-
process.exit(1);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
async function handleStop() {
|
|
279
|
-
const pid = await readPid();
|
|
280
|
-
if (!pid) {
|
|
281
|
-
console.log('[mnemonik] Scanner daemon is not running.');
|
|
282
|
-
// Clean up stale PID file if it exists
|
|
283
|
-
await unlink(PID_FILE).catch(() => { });
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
try {
|
|
287
|
-
process.kill(pid, 'SIGTERM');
|
|
288
|
-
console.log(`[mnemonik] Sent SIGTERM to daemon (PID ${pid}).`);
|
|
289
|
-
// Wait for process to exit (up to 5 seconds)
|
|
290
|
-
for (let i = 0; i < 50; i++) {
|
|
291
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
292
|
-
try {
|
|
293
|
-
process.kill(pid, 0);
|
|
294
|
-
}
|
|
295
|
-
catch {
|
|
296
|
-
console.log('[mnemonik] Daemon stopped.');
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
console.warn('[mnemonik] Daemon did not exit within 5 seconds.');
|
|
301
|
-
}
|
|
302
|
-
catch {
|
|
303
|
-
console.log('[mnemonik] Daemon process not found. Cleaning up PID file.');
|
|
304
|
-
await unlink(PID_FILE).catch(() => { });
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
async function handleStatus() {
|
|
308
|
-
const pid = await readPid();
|
|
309
|
-
const config = await readConfig();
|
|
310
|
-
if (!pid) {
|
|
311
|
-
console.log('Status: not running');
|
|
312
|
-
if (config?.roots) {
|
|
313
|
-
console.log(`Configured roots: ${config.roots.join(', ')}`);
|
|
314
|
-
}
|
|
315
|
-
console.log(`\nStart with: mnemonik-scanner start`);
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
console.log(`Status: running (PID ${pid})`);
|
|
319
|
-
if (config?.roots) {
|
|
320
|
-
console.log(`Roots: ${config.roots.join(', ')}`);
|
|
321
|
-
}
|
|
322
|
-
if (config?.server) {
|
|
323
|
-
console.log(`Server: ${config.server}`);
|
|
324
|
-
}
|
|
325
|
-
// Check for old per-project daemons
|
|
326
|
-
try {
|
|
327
|
-
const { readdir: readdirAsync } = await import('fs/promises');
|
|
328
|
-
const oldDaemonsDir = join(MNEMONIK_DIR, 'daemons');
|
|
329
|
-
const oldPidFiles = await readdirAsync(oldDaemonsDir).catch(() => []);
|
|
330
|
-
const staleOldDaemons = [];
|
|
331
|
-
for (const f of oldPidFiles) {
|
|
332
|
-
if (!f.endsWith('.pid'))
|
|
333
|
-
continue;
|
|
334
|
-
const content = await readFile(join(oldDaemonsDir, f), 'utf-8').catch(() => null);
|
|
335
|
-
if (content) {
|
|
336
|
-
const oldPid = parseInt(content.trim(), 10);
|
|
337
|
-
try {
|
|
338
|
-
process.kill(oldPid, 0);
|
|
339
|
-
// Same PID-reuse guard as readPid(): only report genuinely live
|
|
340
|
-
// scanner processes, not whatever now occupies a recycled PID.
|
|
341
|
-
if (pidIsScanner(oldPid)) {
|
|
342
|
-
staleOldDaemons.push(`${f} (PID ${oldPid})`);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
catch {
|
|
346
|
-
// Dead process, just a stale file
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
if (staleOldDaemons.length > 0) {
|
|
351
|
-
console.log(`\nLegacy per-project daemons still running:`);
|
|
352
|
-
for (const d of staleOldDaemons) {
|
|
353
|
-
console.log(` ${d}`);
|
|
354
|
-
}
|
|
355
|
-
console.log(' Consider stopping these — the global daemon handles all projects.');
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
catch {
|
|
359
|
-
// Old daemons dir doesn't exist
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
async function handleLog() {
|
|
363
|
-
try {
|
|
364
|
-
const content = await readFile(LOG_FILE, 'utf-8');
|
|
365
|
-
// Show last 50 lines
|
|
366
|
-
const lines = content.split('\n');
|
|
367
|
-
const tail = lines.slice(-50).join('\n');
|
|
368
|
-
console.log(tail);
|
|
369
|
-
}
|
|
370
|
-
catch {
|
|
371
|
-
console.log('[mnemonik] No log file found at', LOG_FILE);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
async function main() {
|
|
375
|
-
const cli = parseCliArgs();
|
|
376
|
-
switch (cli.command) {
|
|
377
|
-
case 'start':
|
|
378
|
-
await handleStart(cli);
|
|
379
|
-
break;
|
|
380
|
-
case 'stop':
|
|
381
|
-
await handleStop();
|
|
382
|
-
break;
|
|
383
|
-
case 'status':
|
|
384
|
-
await handleStatus();
|
|
385
|
-
break;
|
|
386
|
-
case 'log':
|
|
387
|
-
await handleLog();
|
|
388
|
-
break;
|
|
389
|
-
case 'doctor':
|
|
390
|
-
await runDoctor();
|
|
391
|
-
break;
|
|
392
|
-
case 'help':
|
|
393
|
-
default:
|
|
394
|
-
printHelp();
|
|
395
|
-
break;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
main();
|
|
399
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/pid.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function pidIsScanner(pid: number): boolean;
|
package/dist/pid.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from 'child_process';
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
3
|
-
/**
|
|
4
|
-
* PID-reuse guard shared by the CLI lock paths (index.ts) and doctor.
|
|
5
|
-
*
|
|
6
|
-
* `process.kill(pid, 0)` only proves that *some* process is alive at that
|
|
7
|
-
* PID, not that it is ours. After a reboot or plain PID recycling the number
|
|
8
|
-
* in daemon.pid can belong to an unrelated process — SIGTERMing it from
|
|
9
|
-
* `stop`, or refusing to `start` because of it, would be wrong. So a live PID
|
|
10
|
-
* only counts as the scanner when its command line matches the daemon's
|
|
11
|
-
* signature (same pattern doctor uses to find daemon processes via `ps`).
|
|
12
|
-
*/
|
|
13
|
-
const SCANNER_CMD_PATTERN = /(mnemonik-scanner|scanner\/dist\/index\.js)/;
|
|
14
|
-
function processCmdline(pid) {
|
|
15
|
-
// Linux: /proc/<pid>/cmdline is NUL-separated argv — cheap and exact.
|
|
16
|
-
try {
|
|
17
|
-
return readFileSync(`/proc/${pid}/cmdline`, 'utf-8').replace(/\0/g, ' ');
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
// /proc unavailable (macOS) or unreadable — fall back to ps below.
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
return execFileSync('ps', ['-o', 'args=', '-p', String(pid)], {
|
|
24
|
-
encoding: 'utf-8',
|
|
25
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
26
|
-
timeout: 5000,
|
|
27
|
-
}).trim();
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return null; // No such process, or ps unavailable — cannot confirm identity.
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
export function pidIsScanner(pid) {
|
|
34
|
-
const cmdline = processCmdline(pid);
|
|
35
|
-
return cmdline !== null && SCANNER_CMD_PATTERN.test(cmdline);
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=pid.js.map
|
package/dist/pid.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pid.js","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAElC;;;;;;;;;GASG;AACH,MAAM,mBAAmB,GAAG,6CAA6C,CAAC;AAE1E,SAAS,cAAc,CAAC,GAAW;IACjC,sEAAsE;IACtE,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,SAAS,GAAG,UAAU,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;IACrE,CAAC;IACD,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;YAC5D,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,OAAO,EAAE,IAAI;SACd,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,gEAAgE;IAC/E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,OAAO,KAAK,IAAI,IAAI,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC/D,CAAC"}
|
package/dist/watcher.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export type ChangeHandler = (changedFiles: string[]) => void;
|
|
2
|
-
export type ErrorHandler = (err: Error) => void;
|
|
3
|
-
export declare class FileWatcher {
|
|
4
|
-
private rootPath;
|
|
5
|
-
private onChange;
|
|
6
|
-
private watchers;
|
|
7
|
-
private watchedDirs;
|
|
8
|
-
private watchedDirInodes;
|
|
9
|
-
private pendingFiles;
|
|
10
|
-
private flushTimer;
|
|
11
|
-
private debounceMs;
|
|
12
|
-
private onError;
|
|
13
|
-
constructor(rootPath: string, onChange: ChangeHandler, debounceMs?: number, onError?: ErrorHandler);
|
|
14
|
-
start(): Promise<void>;
|
|
15
|
-
stop(): void;
|
|
16
|
-
private scheduleFlush;
|
|
17
|
-
private watchDir;
|
|
18
|
-
/**
|
|
19
|
-
* Attach a watcher to a directory created after start(). Called from the
|
|
20
|
-
* per-directory change callback with every event path; stats the path and
|
|
21
|
-
* only recurses when it is a genuinely new, watchable directory.
|
|
22
|
-
*/
|
|
23
|
-
private watchNewDir;
|
|
24
|
-
/**
|
|
25
|
-
* Forget a deleted directory and everything watched beneath it. fs.watch
|
|
26
|
-
* emits no per-descendant events on a recursive delete, so the whole
|
|
27
|
-
* prefix must be purged here for a recreate to re-watch the full subtree.
|
|
28
|
-
*/
|
|
29
|
-
private unwatchSubtree;
|
|
30
|
-
}
|