bgrun 3.12.1 → 3.12.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.
@@ -12,20 +12,20 @@ export default function DashboardPage() {
12
12
  <div className="toast-container" id="toast-container"></div>
13
13
 
14
14
  {/* Stats Grid */}
15
- <div className="stats-grid">
16
- <div className="stat-card">
15
+ <div className="stats-grid" id="stats-grid">
16
+ <div className="stat-card stat-clickable" data-stat-filter="all">
17
17
  <div className="stat-label">Total Processes</div>
18
18
  <div className="stat-value" id="total-count">–</div>
19
19
  </div>
20
- <div className="stat-card running">
20
+ <div className="stat-card running stat-clickable" data-stat-filter="running">
21
21
  <div className="stat-label">Running</div>
22
22
  <div className="stat-value" id="running-count">–</div>
23
23
  </div>
24
- <div className="stat-card stopped">
24
+ <div className="stat-card stopped stat-clickable" data-stat-filter="stopped">
25
25
  <div className="stat-label">Stopped</div>
26
26
  <div className="stat-value" id="stopped-count">–</div>
27
27
  </div>
28
- <div className="stat-card guarded">
28
+ <div className="stat-card guarded stat-clickable" data-stat-filter="guarded">
29
29
  <div className="stat-label">Guarded</div>
30
30
  <div className="stat-value" id="guarded-count">–</div>
31
31
  </div>
@@ -37,6 +37,14 @@ export default function DashboardPage() {
37
37
  <div className="stat-label">Guard Restarts</div>
38
38
  <div className="stat-value" id="restarts-count">0</div>
39
39
  </div>
40
+ <div className="stat-card uptime">
41
+ <div className="stat-label">Longest Uptime</div>
42
+ <div className="stat-value" id="uptime-longest">–</div>
43
+ </div>
44
+ <div className="stat-card uptime-total">
45
+ <div className="stat-label">Total Uptime</div>
46
+ <div className="stat-value" id="uptime-total">–</div>
47
+ </div>
40
48
  </div>
41
49
 
42
50
  {/* Guard Activity Feed */}
@@ -65,9 +73,14 @@ export default function DashboardPage() {
65
73
  <span className="search-count" id="search-count" style={{ display: 'none' }}></span>
66
74
  <span className="search-shortcut">/</span>
67
75
  </div>
76
+ <span className="stat-filter-badge" id="stat-filter-badge" style={{ display: 'none' }}>
77
+ <span id="stat-filter-badge-label"></span>
78
+ <button className="stat-filter-badge-clear" id="stat-filter-badge-clear" type="button" title="Clear status filter">✕</button>
79
+ </span>
68
80
  <select className="group-filter" id="group-filter">
69
81
  <option value="">All Groups</option>
70
82
  </select>
83
+ <div className="deploy-preset-scopes" id="deploy-preset-scopes"></div>
71
84
  </div>
72
85
  <div className="toolbar-right">
73
86
  <button className="btn btn-ghost btn-icon" id="refresh-btn" title="Refresh">
@@ -82,10 +95,40 @@ export default function DashboardPage() {
82
95
  </svg>
83
96
  <span id="guard-all-label">Guard All</span>
84
97
  </button>
98
+ <button className="btn btn-ghost" id="deploy-all-btn" title="Git pull + restart all deployable processes">
99
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
100
+ <path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z" />
101
+ <path d="M12 15l-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z" />
102
+ <path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0" />
103
+ <path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5" />
104
+ </svg>
105
+ <span id="deploy-all-label">Deploy All</span>
106
+ </button>
107
+ <div className="deploy-controls">
108
+ <label className="deploy-concurrency-wrap" title="Bulk deploy concurrency (saved per group)">
109
+ <span className="deploy-concurrency-label">Deploy</span>
110
+ <select className="deploy-concurrency-select" id="deploy-concurrency-select">
111
+ <option value="1">1×</option>
112
+ <option value="2">2×</option>
113
+ <option value="3">3×</option>
114
+ <option value="4">4×</option>
115
+ </select>
116
+ </label>
117
+ <span className="deploy-preset-source" id="deploy-preset-source" title="Current deploy preset source">default</span>
118
+ <button className="btn btn-ghost btn-icon" id="deploy-preset-reset-btn" title="Reset saved deploy preset for current group">
119
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
120
+ <polyline points="1 4 1 10 7 10" />
121
+ <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10" />
122
+ </svg>
123
+ </button>
124
+ </div>
85
125
  <span className="guard-sentinel-pill" id="guard-sentinel-pill" title="Standalone guard process status">
86
126
  <span className="guard-sentinel-dot" id="guard-sentinel-dot" />
87
127
  <span id="guard-sentinel-label">Guard: –</span>
88
128
  </span>
129
+ <button className="btn btn-ghost btn-icon" id="theme-toggle-btn" title="Toggle light/dark theme">
130
+ <span id="theme-toggle-icon" style={{ fontSize: '0.85rem' }}>🌙</span>
131
+ </button>
89
132
  <button className="btn btn-ghost btn-icon" id="shortcuts-btn" title="Keyboard Shortcuts (?)">
90
133
  <span style={{ fontSize: '0.85rem', fontWeight: '700' }}>?</span>
91
134
  </button>
@@ -96,6 +139,17 @@ export default function DashboardPage() {
96
139
  </svg>
97
140
  Templates
98
141
  </button>
142
+ <button className="btn btn-ghost" id="deps-btn" title="Process Dependencies">
143
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
144
+ <circle cx="6" cy="6" r="3" />
145
+ <circle cx="18" cy="6" r="3" />
146
+ <circle cx="18" cy="18" r="3" />
147
+ <line x1="9" y1="6" x2="15" y2="6" />
148
+ <path d="M18 9v6" />
149
+ <path d="M9 6l6 9" />
150
+ </svg>
151
+ Deps
152
+ </button>
99
153
  <button className="btn btn-ghost" id="history-btn">
100
154
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
101
155
  <circle cx="12" cy="12" r="10" />
@@ -244,6 +298,19 @@ export default function DashboardPage() {
244
298
  <label htmlFor="process-directory-input">Working Directory</label>
245
299
  <input type="text" id="process-directory-input" placeholder="/path/to/project" />
246
300
  </div>
301
+ <div className="form-group">
302
+ <label htmlFor="process-port-input">Port <span style={{ fontWeight: 400, color: 'var(--text-muted)' }}>(optional)</span></label>
303
+ <div className="port-input-wrap">
304
+ <input type="number" id="process-port-input" placeholder="auto" min="1" max="65535" />
305
+ <button className="btn btn-ghost btn-sm" id="suggest-port-btn" type="button" title="Auto-assign next available port">Suggest</button>
306
+ </div>
307
+ <div className="port-range-wrap">
308
+ <span className="port-range-label">Range</span>
309
+ <input type="number" id="port-range-min" className="port-range-input" placeholder="3001" min="1" max="65535" />
310
+ <span className="port-range-sep">–</span>
311
+ <input type="number" id="port-range-max" className="port-range-input" placeholder="4000" min="1" max="65535" />
312
+ </div>
313
+ </div>
247
314
  </div>
248
315
  <div className="modal-footer">
249
316
  <button className="btn btn-ghost" id="modal-cancel-btn">Cancel</button>
@@ -253,6 +320,33 @@ export default function DashboardPage() {
253
320
  </div>
254
321
 
255
322
  {/* History Modal */}
323
+ {/* Dependencies Modal */}
324
+ <div className="modal-overlay" id="deps-modal">
325
+ <div className="modal modal-wide">
326
+ <div className="modal-header">
327
+ <h3>🔗 Process Dependencies</h3>
328
+ <button className="modal-close" id="deps-modal-close">✕</button>
329
+ </div>
330
+ <div className="modal-body">
331
+ <div className="deps-controls">
332
+ <select id="deps-process-select" className="history-select">
333
+ <option value="">Select process...</option>
334
+ </select>
335
+ <span className="deps-arrow">depends on →</span>
336
+ <select id="deps-target-select" className="history-select">
337
+ <option value="">Select dependency...</option>
338
+ </select>
339
+ <button className="btn btn-primary btn-sm" id="deps-add-btn">Add</button>
340
+ </div>
341
+ <div className="deps-graph-container" id="deps-graph-container">
342
+ <svg id="deps-graph-svg" width="100%" height="400"></svg>
343
+ </div>
344
+ <div className="deps-list" id="deps-list"></div>
345
+ <div className="deps-start-order" id="deps-start-order"></div>
346
+ </div>
347
+ </div>
348
+ </div>
349
+
256
350
  <div className="modal-overlay" id="history-modal">
257
351
  <div className="modal modal-wide">
258
352
  <div className="modal-header">
@@ -269,9 +363,85 @@ export default function DashboardPage() {
269
363
  <option value="start">Start</option>
270
364
  <option value="stop">Stop</option>
271
365
  <option value="restart">Restart</option>
366
+ <option value="deploy">Deploy</option>
272
367
  <option value="guard_on">Guard On</option>
273
368
  <option value="guard_off">Guard Off</option>
274
369
  </select>
370
+ <input id="history-metadata-filter" className="history-select history-search" type="text" placeholder="Filter metadata (comma-separated)..." />
371
+ <label className="history-density-wrap" title="History row density">
372
+ <span className="history-density-label">Density</span>
373
+ <select id="history-density-select" className="history-select history-density-select">
374
+ <option value="cozy">Cozy</option>
375
+ <option value="compact">Compact</option>
376
+ </select>
377
+ </label>
378
+ <label className="history-shortcuts-toggle" title="Show quick-action affordances in History rows">
379
+ <input id="history-shortcuts-toggle" type="checkbox" />
380
+ <span>Shortcuts</span>
381
+ </label>
382
+ <label className="history-density-wrap" title="Default History details state">
383
+ <span className="history-density-label">Details</span>
384
+ <select id="history-details-default-select" className="history-select history-density-select">
385
+ <option value="collapsed">Collapsed</option>
386
+ <option value="expanded">Expanded</option>
387
+ </select>
388
+ </label>
389
+ <button className="btn btn-ghost btn-sm" id="history-clear-filters-btn" title="Clear all history filters">Clear</button>
390
+ </div>
391
+ <div className="history-hints-bar">
392
+ <div className="history-hints-bar-left">
393
+ <span className="history-hints-title">Keyboard shortcuts</span>
394
+ <div className="history-focus-controls">
395
+ <button className="history-focus-jump" id="history-focus-prev" type="button" title="Focus previous History row">←</button>
396
+ <span className="history-focus-status" id="history-focus-status">No row selected</span>
397
+ <button className="history-focus-jump" id="history-focus-next" type="button" title="Focus next History row">→</button>
398
+ </div>
399
+ <label className="history-auto-open-toggle" title="Automatically sync the process drawer while stepping through History rows">
400
+ <input id="history-auto-open-toggle" type="checkbox" />
401
+ <span>Auto-open</span>
402
+ </label>
403
+ <label className="history-hint-density-wrap" title="Auto-open behavior while stepping through History rows">
404
+ <span className="history-density-label">Scope</span>
405
+ <select id="history-focus-scope-select" className="history-select history-hint-density-select">
406
+ <option value="sync">Sync drawer</option>
407
+ <option value="inspect">Inspect</option>
408
+ </select>
409
+ </label>
410
+ </div>
411
+ <div className="history-hints-actions">
412
+ <label className="history-hint-density-wrap" title="Keyboard hint density">
413
+ <span className="history-density-label">Hints</span>
414
+ <select id="history-hint-density-select" className="history-select history-hint-density-select">
415
+ <option value="full">Full</option>
416
+ <option value="compact">Compact</option>
417
+ </select>
418
+ </label>
419
+ <details className="history-hint-groups-menu">
420
+ <summary className="history-hints-toggle" title="Choose which History hint groups to show">Groups</summary>
421
+ <div className="history-hint-groups-panel">
422
+ <div className="history-hint-presets">
423
+ <button className="history-hint-preset" type="button" data-history-hint-preset="minimal">Minimal</button>
424
+ <button className="history-hint-preset" type="button" data-history-hint-preset="navigation">Navigation</button>
425
+ <button className="history-hint-preset" type="button" data-history-hint-preset="all">All</button>
426
+ <span className="history-hint-preset-state" id="history-hint-preset-state">Custom</span>
427
+ </div>
428
+ <label className="history-hint-group-option"><input id="history-hint-group-nav" type="checkbox" /> <span>Navigation</span></label>
429
+ <label className="history-hint-group-option"><input id="history-hint-group-open" type="checkbox" /> <span>Open</span></label>
430
+ <label className="history-hint-group-option"><input id="history-hint-group-filter" type="checkbox" /> <span>Filters</span></label>
431
+ <label className="history-hint-group-option"><input id="history-hint-group-details" type="checkbox" /> <span>Details</span></label>
432
+ <label className="history-hint-group-option"><input id="history-hint-group-close" type="checkbox" /> <span>Close</span></label>
433
+ </div>
434
+ </details>
435
+ <button className="history-hints-toggle" id="history-hints-toggle" type="button" title="Hide keyboard shortcut hints">Hide</button>
436
+ </div>
437
+ </div>
438
+ <div className="history-keyboard-hints" id="history-keyboard-hints" aria-label="History keyboard shortcuts">
439
+ <span className="history-keyboard-hint" data-hint-group="nav"><kbd>↑</kbd><kbd>↓</kbd><span>Move</span></span>
440
+ <span className="history-keyboard-hint" data-hint-group="open"><kbd>Enter</kbd><span>Open</span></span>
441
+ <span className="history-keyboard-hint" data-hint-group="filter"><kbd>F</kbd><span>Process filter</span></span>
442
+ <span className="history-keyboard-hint" data-hint-group="filter"><kbd>E</kbd><span>Event filter</span></span>
443
+ <span className="history-keyboard-hint" data-hint-group="details"><kbd>Space</kbd><span>Toggle details</span></span>
444
+ <span className="history-keyboard-hint" data-hint-group="close"><kbd>Esc</kbd><span>Close</span></span>
275
445
  </div>
276
446
  <div className="history-list" id="history-list">
277
447
  <div className="history-empty">No history yet</div>
@@ -324,6 +494,24 @@ export default function DashboardPage() {
324
494
  </div>
325
495
  </div>
326
496
 
497
+ {/* Deploy Results Modal */}
498
+ <div className="modal-overlay" id="deploy-results-modal">
499
+ <div className="modal modal-wide">
500
+ <div className="modal-header">
501
+ <h3>🚀 Deploy Results</h3>
502
+ <button className="modal-close" id="deploy-results-modal-close">✕</button>
503
+ </div>
504
+ <div className="modal-body">
505
+ <div className="deploy-results-summary" id="deploy-results-summary">
506
+ No deploy results yet
507
+ </div>
508
+ <div className="deploy-results-list" id="deploy-results-list">
509
+ <div className="history-empty">Run a bulk deploy to see detailed results</div>
510
+ </div>
511
+ </div>
512
+ </div>
513
+ </div>
514
+
327
515
  {/* Keyboard Shortcuts Overlay */}
328
516
  <div className="shortcuts-overlay" id="shortcuts-overlay">
329
517
  <div className="shortcuts-panel">
@@ -346,6 +534,7 @@ export default function DashboardPage() {
346
534
  <div className="shortcut-row"><kbd>G</kbd><span>Toggle guard</span></div>
347
535
  <div className="shortcut-row"><kbd>D</kbd><span>Delete process</span></div>
348
536
  <div className="shortcut-row"><kbd>N</kbd><span>New process</span></div>
537
+ <div className="shortcut-row"><kbd>T</kbd><span>Cycle stat filter</span></div>
349
538
  <div className="shortcut-row"><kbd>?</kbd><span>This help</span></div>
350
539
  </div>
351
540
  </div>
package/dist/index.js CHANGED
@@ -80,7 +80,8 @@ async function isProcessRunning(pid, command) {
80
80
  process.kill(pid, 0);
81
81
  return true;
82
82
  } catch {
83
- return false;
83
+ const output = psExec(`Get-Process -Id ${pid} -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id`).trim();
84
+ return output === String(pid);
84
85
  }
85
86
  } else {
86
87
  const result = await $`ps -p ${pid}`.nothrow().text();
@@ -485,15 +486,13 @@ async function getProcessPorts(pid) {
485
486
  if (ports2.size > 0)
486
487
  return Array.from(ports2);
487
488
  } catch {}
488
- const result = await $`lsof -i -P -n -p ${pid}`.nothrow().quiet().text();
489
+ const result = await $`lsof -Pan -p ${pid} -iTCP -sTCP:LISTEN`.nothrow().quiet().text();
489
490
  const ports = new Set;
490
491
  for (const line of result.split(`
491
492
  `)) {
492
- if (line.includes("LISTEN")) {
493
- const portMatch = line.match(/:(\d+)\s+\(LISTEN\)/);
494
- if (portMatch) {
495
- ports.add(parseInt(portMatch[1]));
496
- }
493
+ const portMatch = line.match(/:(\d+)\s+\(LISTEN\)/);
494
+ if (portMatch) {
495
+ ports.add(parseInt(portMatch[1]));
497
496
  }
498
497
  }
499
498
  return Array.from(ports);
@@ -595,12 +594,18 @@ __export(exports_db, {
595
594
  retryDatabaseOperation: () => retryDatabaseOperation,
596
595
  removeProcessByName: () => removeProcessByName,
597
596
  removeProcess: () => removeProcess,
597
+ removeDependency: () => removeDependency,
598
598
  removeAllProcesses: () => removeAllProcesses,
599
+ removeAllDependencies: () => removeAllDependencies,
599
600
  insertProcess: () => insertProcess,
600
601
  getTemplate: () => getTemplate,
602
+ getStartOrder: () => getStartOrder,
601
603
  getRecentHistory: () => getRecentHistory,
602
604
  getProcessHistory: () => getProcessHistory,
603
605
  getProcess: () => getProcess,
606
+ getDependents: () => getDependents,
607
+ getDependencyGraph: () => getDependencyGraph,
608
+ getDependencies: () => getDependencies,
604
609
  getDbInfo: () => getDbInfo,
605
610
  getAllTemplates: () => getAllTemplates,
606
611
  getAllProcesses: () => getAllProcesses,
@@ -610,9 +615,11 @@ __export(exports_db, {
610
615
  clearOldHistory: () => clearOldHistory,
611
616
  bgrHome: () => bgrHome,
612
617
  addHistoryEntry: () => addHistoryEntry,
618
+ addDependency: () => addDependency,
613
619
  TemplateSchema: () => TemplateSchema,
614
620
  ProcessSchema: () => ProcessSchema,
615
- HistorySchema: () => HistorySchema
621
+ HistorySchema: () => HistorySchema,
622
+ DependencySchema: () => DependencySchema
616
623
  });
617
624
  import { Database, z } from "sqlite-zod-orm";
618
625
  import { join as join2 } from "path";
@@ -715,6 +722,99 @@ function clearOldHistory(daysToKeep = 30) {
715
722
  }
716
723
  return oldEntries.length;
717
724
  }
725
+ function getDependencies(processName) {
726
+ return db.dependency.select().where({ process_name: processName }).all().map((d) => d.depends_on);
727
+ }
728
+ function getDependents(processName) {
729
+ return db.dependency.select().where({ depends_on: processName }).all().map((d) => d.process_name);
730
+ }
731
+ function getDependencyGraph() {
732
+ const all = db.dependency.select().all();
733
+ const graph = {};
734
+ for (const dep of all) {
735
+ if (!graph[dep.process_name])
736
+ graph[dep.process_name] = [];
737
+ graph[dep.process_name].push(dep.depends_on);
738
+ }
739
+ return graph;
740
+ }
741
+ function addDependency(processName, dependsOn) {
742
+ if (processName === dependsOn)
743
+ return false;
744
+ const existing = db.dependency.select().where({ process_name: processName, depends_on: dependsOn }).limit(1).get();
745
+ if (existing)
746
+ return false;
747
+ if (wouldCreateCycle(processName, dependsOn))
748
+ return false;
749
+ db.dependency.insert({ process_name: processName, depends_on: dependsOn });
750
+ return true;
751
+ }
752
+ function removeDependency(processName, dependsOn) {
753
+ const matches = db.dependency.select().where({ process_name: processName, depends_on: dependsOn }).all();
754
+ for (const dep of matches) {
755
+ db.dependency.delete(dep.id);
756
+ }
757
+ }
758
+ function removeAllDependencies(processName) {
759
+ const matches = db.dependency.select().where({ process_name: processName }).all();
760
+ for (const dep of matches) {
761
+ db.dependency.delete(dep.id);
762
+ }
763
+ }
764
+ function wouldCreateCycle(processName, dependsOn) {
765
+ const graph = getDependencyGraph();
766
+ if (!graph[processName])
767
+ graph[processName] = [];
768
+ graph[processName].push(dependsOn);
769
+ const visited = new Set;
770
+ const stack = [dependsOn];
771
+ while (stack.length > 0) {
772
+ const current = stack.pop();
773
+ if (current === processName)
774
+ return true;
775
+ if (visited.has(current))
776
+ continue;
777
+ visited.add(current);
778
+ for (const dep of graph[current] || []) {
779
+ stack.push(dep);
780
+ }
781
+ }
782
+ return false;
783
+ }
784
+ function getStartOrder() {
785
+ const graph = getDependencyGraph();
786
+ const allProcesses = getAllProcesses().map((p) => p.name);
787
+ const allNames = new Set(allProcesses);
788
+ const inDegree = {};
789
+ for (const name of allNames)
790
+ inDegree[name] = 0;
791
+ for (const [proc, deps] of Object.entries(graph)) {
792
+ for (const dep of deps) {
793
+ if (allNames.has(dep)) {
794
+ inDegree[proc] = (inDegree[proc] || 0) + 1;
795
+ }
796
+ }
797
+ }
798
+ const queue = [];
799
+ for (const name of allNames) {
800
+ if ((inDegree[name] || 0) === 0)
801
+ queue.push(name);
802
+ }
803
+ const order = [];
804
+ while (queue.length > 0) {
805
+ queue.sort();
806
+ const current = queue.shift();
807
+ order.push(current);
808
+ for (const [proc, deps] of Object.entries(graph)) {
809
+ if (deps.includes(current) && allNames.has(proc)) {
810
+ inDegree[proc]--;
811
+ if (inDegree[proc] === 0)
812
+ queue.push(proc);
813
+ }
814
+ }
815
+ }
816
+ return order;
817
+ }
718
818
  function getDbInfo() {
719
819
  return {
720
820
  dbPath,
@@ -737,7 +837,7 @@ async function retryDatabaseOperation(operation, maxRetries = 5, delay = 100) {
737
837
  }
738
838
  throw new Error("Max retries reached for database operation");
739
839
  }
740
- var ProcessSchema, TemplateSchema, HistorySchema, homePath, bgrDir, dbFilename, dbPath, bgrHome, legacyDbPath, db;
840
+ var ProcessSchema, TemplateSchema, HistorySchema, DependencySchema, homePath, bgrDir, dbFilename, dbPath, bgrHome, legacyDbPath, db;
741
841
  var init_db = __esm(() => {
742
842
  init_platform();
743
843
  ProcessSchema = z.object({
@@ -767,6 +867,11 @@ var init_db = __esm(() => {
767
867
  timestamp: z.string().default(() => new Date().toISOString()),
768
868
  metadata: z.string().default("")
769
869
  });
870
+ DependencySchema = z.object({
871
+ process_name: z.string(),
872
+ depends_on: z.string(),
873
+ created_at: z.string().default(() => new Date().toISOString())
874
+ });
770
875
  homePath = getHomeDir();
771
876
  bgrDir = join2(homePath, ".bgr");
772
877
  ensureDir(bgrDir);
@@ -783,12 +888,14 @@ var init_db = __esm(() => {
783
888
  db = new Database(dbPath, {
784
889
  process: ProcessSchema,
785
890
  template: TemplateSchema,
786
- history: HistorySchema
891
+ history: HistorySchema,
892
+ dependency: DependencySchema
787
893
  }, {
788
894
  indexes: {
789
895
  process: ["name", "timestamp", "pid"],
790
896
  template: ["name"],
791
- history: ["process_name", "timestamp"]
897
+ history: ["process_name", "timestamp"],
898
+ dependency: ["process_name", "depends_on"]
792
899
  }
793
900
  });
794
901
  });
@@ -863,10 +970,10 @@ async function parseConfigFile(configPath) {
863
970
  var exports_deps = {};
864
971
  __export(exports_deps, {
865
972
  getUnmetDeps: () => getUnmetDeps,
866
- getDependencies: () => getDependencies,
973
+ getDependencies: () => getDependencies2,
867
974
  buildDepGraph: () => buildDepGraph
868
975
  });
869
- function getDependencies(envStr) {
976
+ function getDependencies2(envStr) {
870
977
  const env = parseEnvString(envStr);
871
978
  const raw = env.BGR_DEPENDS_ON || "";
872
979
  return raw.split(",").map((s) => s.trim()).filter(Boolean);
@@ -875,7 +982,7 @@ async function buildDepGraph() {
875
982
  const processes = getAllProcesses();
876
983
  const nodeMap = new Map;
877
984
  for (const proc of processes) {
878
- const deps = getDependencies(proc.env);
985
+ const deps = getDependencies2(proc.env);
879
986
  const alive = await isProcessRunning(proc.pid, proc.command);
880
987
  nodeMap.set(proc.name, {
881
988
  name: proc.name,
@@ -927,7 +1034,7 @@ async function getUnmetDeps(name) {
927
1034
  const proc = getProcess(name);
928
1035
  if (!proc)
929
1036
  return [];
930
- const deps = getDependencies(proc.env);
1037
+ const deps = getDependencies2(proc.env);
931
1038
  const unmet = [];
932
1039
  for (const depName of deps) {
933
1040
  const depProc = getProcess(depName);
@@ -2677,6 +2784,13 @@ async function run2() {
2677
2784
  });
2678
2785
  return;
2679
2786
  }
2787
+ if (name === "list") {
2788
+ await showAll({
2789
+ json: values.json,
2790
+ filter: values.filter
2791
+ });
2792
+ return;
2793
+ }
2680
2794
  if (name) {
2681
2795
  if (!values.command && !values.directory) {
2682
2796
  await showDetails(name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bgrun",
3
- "version": "3.12.1",
3
+ "version": "3.12.2",
4
4
  "description": "bgrun — A lightweight process manager for Bun",
5
5
  "type": "module",
6
6
  "main": "./src/api.ts",