(opts: { prune?: boolean } = {})
| 86 | * records are deleted as a side effect (self-healing) unless `prune` is false. |
| 87 | */ |
| 88 | export function listDaemons(opts: { prune?: boolean } = {}): DaemonRecord[] { |
| 89 | const prune = opts.prune ?? true; |
| 90 | const dir = getRegistryDir(); |
| 91 | let files: string[]; |
| 92 | try { |
| 93 | files = fs.readdirSync(dir).filter((f) => f.endsWith('.json')); |
| 94 | } catch { |
| 95 | return []; // no registry dir yet |
| 96 | } |
| 97 | |
| 98 | const live: DaemonRecord[] = []; |
| 99 | for (const file of files) { |
| 100 | const full = path.join(dir, file); |
| 101 | let rec: DaemonRecord | null = null; |
| 102 | try { |
| 103 | rec = JSON.parse(fs.readFileSync(full, 'utf8')) as DaemonRecord; |
| 104 | } catch { |
| 105 | rec = null; |
| 106 | } |
| 107 | const valid = rec && typeof rec.pid === 'number' && typeof rec.root === 'string'; |
| 108 | if (valid && isProcessAlive(rec!.pid)) { |
| 109 | live.push(rec!); |
| 110 | } else if (prune) { |
| 111 | try { fs.unlinkSync(full); } catch { /* ignore */ } |
| 112 | } |
| 113 | } |
| 114 | return live.sort((a, b) => b.startedAt - a.startedAt); |
| 115 | } |
| 116 | |
| 117 | /** Remove a stopped daemon's leftover lockfile + socket + registry record. */ |
| 118 | function cleanupDaemonArtifacts(root: string): void { |
no test coverage detected