@cardstack/boxel-cli 0.1.3 → 0.2.0-unstable.294

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.
@@ -17,7 +17,7 @@ function lockPath(localDir: string): string {
17
17
  return path.join(localDir, LOCK_FILE);
18
18
  }
19
19
 
20
- function isProcessAlive(pid: number): boolean {
20
+ export function isProcessAlive(pid: number): boolean {
21
21
  try {
22
22
  process.kill(pid, 0);
23
23
  return true;
@@ -0,0 +1,85 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+ import { isProcessAlive } from './watch-lock';
5
+
6
+ export interface RegisteredProcess {
7
+ pid: number;
8
+ workspace: string;
9
+ startedAt: string;
10
+ }
11
+
12
+ interface Registry {
13
+ processes: RegisteredProcess[];
14
+ }
15
+
16
+ function registryDir(): string {
17
+ return path.join(os.homedir(), '.boxel-cli');
18
+ }
19
+
20
+ function registryFile(): string {
21
+ return path.join(registryDir(), 'watch-processes.json');
22
+ }
23
+
24
+ async function readRegistry(): Promise<Registry> {
25
+ try {
26
+ const raw = await fs.readFile(registryFile(), 'utf8');
27
+ const parsed = JSON.parse(raw) as Partial<Registry>;
28
+ if (!Array.isArray(parsed?.processes)) {
29
+ return { processes: [] };
30
+ }
31
+ const processes = parsed.processes.filter(
32
+ (entry): entry is RegisteredProcess =>
33
+ typeof entry?.pid === 'number' &&
34
+ typeof entry?.workspace === 'string' &&
35
+ typeof entry?.startedAt === 'string',
36
+ );
37
+ return { processes };
38
+ } catch {
39
+ return { processes: [] };
40
+ }
41
+ }
42
+
43
+ async function writeRegistry(registry: Registry): Promise<void> {
44
+ await fs.mkdir(registryDir(), { recursive: true });
45
+ const target = registryFile();
46
+ const tmp = `${target}.${process.pid}.tmp`;
47
+ await fs.writeFile(tmp, JSON.stringify(registry, null, 2) + '\n');
48
+ await fs.rename(tmp, target);
49
+ }
50
+
51
+ async function pruneDead(): Promise<Registry> {
52
+ const registry = await readRegistry();
53
+ const alive = registry.processes.filter((entry) => isProcessAlive(entry.pid));
54
+ if (alive.length !== registry.processes.length) {
55
+ await writeRegistry({ processes: alive });
56
+ }
57
+ return { processes: alive };
58
+ }
59
+
60
+ export async function registerProcess(workspace: string): Promise<void> {
61
+ const registry = await pruneDead();
62
+ const withoutCurrent = registry.processes.filter(
63
+ (entry) => entry.pid !== process.pid,
64
+ );
65
+ withoutCurrent.push({
66
+ pid: process.pid,
67
+ workspace,
68
+ startedAt: new Date().toISOString(),
69
+ });
70
+ await writeRegistry({ processes: withoutCurrent });
71
+ }
72
+
73
+ export async function unregisterCurrentProcess(): Promise<void> {
74
+ const registry = await readRegistry();
75
+ const next = registry.processes.filter((entry) => entry.pid !== process.pid);
76
+ if (next.length === registry.processes.length) {
77
+ return;
78
+ }
79
+ await writeRegistry({ processes: next });
80
+ }
81
+
82
+ export async function listRegisteredProcesses(): Promise<RegisteredProcess[]> {
83
+ const registry = await pruneDead();
84
+ return registry.processes;
85
+ }