metwatch 0.1.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +336 -0
  3. package/bin/mw.ts +20 -0
  4. package/index.ts +174 -0
  5. package/metwatch.config.json +9 -0
  6. package/package.json +50 -0
  7. package/src/cli/args.ts +115 -0
  8. package/src/cli/commands/list.ts +77 -0
  9. package/src/cli/commands/logs.ts +69 -0
  10. package/src/cli/commands/monitor.ts +12 -0
  11. package/src/cli/commands/start.ts +124 -0
  12. package/src/cli/commands/stop.ts +33 -0
  13. package/src/cli/help.ts +96 -0
  14. package/src/core/event-bus.ts +113 -0
  15. package/src/core/launcher.ts +280 -0
  16. package/src/core/log-manager.ts +116 -0
  17. package/src/core/metrics-manager.ts +115 -0
  18. package/src/core/process-manager.ts +79 -0
  19. package/src/core/runtime-manager.ts +299 -0
  20. package/src/core/state-manager.ts +88 -0
  21. package/src/services/disk.service.ts +76 -0
  22. package/src/services/network.service.ts +131 -0
  23. package/src/services/process.service.ts +49 -0
  24. package/src/services/system.service.ts +63 -0
  25. package/src/types/blessed.d.ts +332 -0
  26. package/src/types/config.types.ts +77 -0
  27. package/src/types/managed-process.types.ts +55 -0
  28. package/src/types/metrics.types.ts +182 -0
  29. package/src/types/process.types.ts +49 -0
  30. package/src/ui/layout.ts +318 -0
  31. package/src/ui/screen.ts +45 -0
  32. package/src/ui/widgets/cpu.widget.ts +98 -0
  33. package/src/ui/widgets/disk.widget.ts +134 -0
  34. package/src/ui/widgets/logs.widget.ts +168 -0
  35. package/src/ui/widgets/memory.widget.ts +94 -0
  36. package/src/ui/widgets/network.widget.ts +185 -0
  37. package/src/ui/widgets/process-table.widget.ts +293 -0
  38. package/src/ui/widgets/runtime.widget.ts +119 -0
  39. package/src/utils/formatters.ts +74 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 elhuguito
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,336 @@
1
+ # MetWatch
2
+
3
+ [![npm version](https://img.shields.io/npm/v/metwatch?color=green&label=npm)](https://www.npmjs.com/package/metwatch)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
5
+ [![Bun >=1.0.0](https://img.shields.io/badge/bun-%3E%3D1.0.0-f9f1e1?logo=bun)](https://bun.sh)
6
+ [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey)](#requirements)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/victorhhh/metwatch/pulls)
8
+
9
+ **MetWatch** is a terminal-based (TUI) process monitoring and management tool — like `htop` and PM2 combined in a single dashboard. It gives you realtime CPU, memory, disk, and network metrics alongside a full process table and managed process lifecycle (start / restart / stop / logs) without leaving your terminal.
10
+
11
+ ![MetWatch dashboard screenshot](./assets/screenshot.png)
12
+
13
+ ---
14
+
15
+ ## Features
16
+
17
+ - **CPU panel** — overall usage percentage + per-core bars, color-coded by load
18
+ - **Memory panel** — RAM used / free / cached / total with visual gauge
19
+ - **Disk panel** — per-mount usage bars with read/write IO rates
20
+ - **Network panel** — realtime RX/TX throughput graph (last 30 s) + per-interface stats
21
+ - **Process table** — all system processes sorted by CPU or memory; dual-mode (All / Watched)
22
+ - **Managed processes** — launch scripts with `mw start`, get auto-restart with exponential back-off
23
+ - **Runtime metrics** — Node.js / Bun heap, RSS, event-loop lag and GC stats via Chrome DevTools Protocol
24
+ - **Log streaming** — stdout/stderr of managed processes buffered and displayed in the Logs panel
25
+ - **Collapsible panels** — toggle any panel on/off with a single key to reclaim screen space
26
+ - **Config file** — define watched processes and refresh interval in `metwatch.config.json`
27
+
28
+ ---
29
+
30
+ ## Requirements
31
+
32
+ | Requirement | Version |
33
+ |---|---|
34
+ | [Bun](https://bun.sh) | ≥ 1.0.0 |
35
+ | Terminal | Real TTY required (does not work piped) |
36
+ | OS | macOS, Linux, Windows |
37
+
38
+ Install Bun if you haven't already:
39
+
40
+ ```bash
41
+ curl -fsSL https://bun.sh/install | bash
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Installation
47
+
48
+ ### Global install (recommended)
49
+
50
+ ```bash
51
+ bun add -g metwatch
52
+ ```
53
+
54
+ Then run from anywhere:
55
+
56
+ ```bash
57
+ mw
58
+ ```
59
+
60
+ ### Run without installing
61
+
62
+ ```bash
63
+ bunx metwatch
64
+ ```
65
+
66
+ ### From source
67
+
68
+ ```bash
69
+ git clone https://github.com/victorhhh/metwatch.git
70
+ cd metwatch
71
+ bun install
72
+ bun run start
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Quick Start
78
+
79
+ ```bash
80
+ # Open the live dashboard (monitor all system processes)
81
+ mw
82
+
83
+ # Launch a TypeScript server and watch it in the dashboard
84
+ mw start server.ts
85
+
86
+ # Launch a Python script, give it a name, and disable auto-restart
87
+ mw start app.py --name api --no-restart
88
+
89
+ # Launch a Node.js worker with a custom env variable
90
+ mw start worker.js --env PORT=4000
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Usage
96
+
97
+ ### `mw monitor`
98
+
99
+ Open the TUI dashboard without launching any managed process. Useful when you just want to observe system metrics.
100
+
101
+ ```bash
102
+ mw monitor
103
+ mw # same — monitor is the default command
104
+ ```
105
+
106
+ ---
107
+
108
+ ### `mw start <file>`
109
+
110
+ Launch a script as a MetWatch-managed process and open the TUI dashboard. The runtime is inferred from the file extension:
111
+
112
+ | Extension | Runtime |
113
+ |---|---|
114
+ | `.ts` / `.tsx` | `bun` |
115
+ | `.js` / `.mjs` / `.cjs` | `node` |
116
+ | `.py` | `python` |
117
+ | other | executed directly |
118
+
119
+ ```bash
120
+ mw start <file> [options]
121
+ ```
122
+
123
+ **Options:**
124
+
125
+ | Flag | Description | Default |
126
+ |---|---|---|
127
+ | `--name <label>` | Display name in the TUI | basename of `<file>` |
128
+ | `--runtime <cmd>` | Override the inferred runtime | auto-detected |
129
+ | `--no-restart` | Disable auto-restart on crash | auto-restart enabled |
130
+ | `--cwd <dir>` | Working directory for the child process | `process.cwd()` |
131
+ | `--env KEY=VALUE` | Set an environment variable (repeatable) | — |
132
+
133
+ **Examples:**
134
+
135
+ ```bash
136
+ # Run a Bun TypeScript server
137
+ mw start server.ts
138
+
139
+ # Run a Python API with a custom name
140
+ mw start app.py --name api
141
+
142
+ # Run a Node.js worker in a subdirectory with an env var
143
+ mw start worker.js --cwd ./workers --env PORT=4000 --env NODE_ENV=production
144
+
145
+ # Run a binary directly without auto-restart
146
+ mw start ./dist/server --no-restart
147
+
148
+ # Override the runtime explicitly
149
+ mw start main.ts --runtime tsx
150
+ ```
151
+
152
+ ---
153
+
154
+ ### `mw list`
155
+
156
+ Print the current state of all managed processes to stdout.
157
+
158
+ ```bash
159
+ mw list
160
+ ```
161
+
162
+ **Example output:**
163
+
164
+ ```
165
+ NAME PID STATUS RESTARTS UPTIME
166
+ api 12345 running 0 2m 34s
167
+ worker 12346 stopped 2 —
168
+ ```
169
+
170
+ ---
171
+
172
+ ### `mw logs <name>`
173
+
174
+ Print buffered stdout/stderr for a managed process.
175
+
176
+ ```bash
177
+ mw logs <name> [options]
178
+ ```
179
+
180
+ **Options:**
181
+
182
+ | Flag | Description | Default |
183
+ |---|---|---|
184
+ | `--follow`, `-f` | Tail live output (Ctrl+C to exit) | off |
185
+ | `--lines <n>` | Number of lines to show | 50 |
186
+
187
+ **Examples:**
188
+
189
+ ```bash
190
+ # Show last 50 lines of logs for "api"
191
+ mw logs api
192
+
193
+ # Tail live logs
194
+ mw logs api --follow
195
+
196
+ # Show last 200 lines
197
+ mw logs api --lines 200
198
+ ```
199
+
200
+ ---
201
+
202
+ ### `mw stop <name|all>`
203
+
204
+ Gracefully stop a managed process with `SIGTERM`.
205
+
206
+ ```bash
207
+ mw stop <name> # stop a specific process
208
+ mw stop all # stop every managed process
209
+ ```
210
+
211
+ **Examples:**
212
+
213
+ ```bash
214
+ mw stop api
215
+ mw stop all
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Configuration
221
+
222
+ MetWatch reads `metwatch.config.json` from the current working directory at startup. If the file is not found, built-in defaults are used. Bad JSON falls back to defaults without crashing.
223
+
224
+ ```json
225
+ {
226
+ "watchedProcesses": [
227
+ { "name": "node", "label": "Node Apps" },
228
+ { "name": "bun", "label": "Bun Apps" },
229
+ { "name": "python", "label": "Python" }
230
+ ],
231
+ "refreshInterval": 1000,
232
+ "maxProcesses": 50
233
+ }
234
+ ```
235
+
236
+ **Fields:**
237
+
238
+ | Field | Type | Default | Description |
239
+ |---|---|---|---|
240
+ | `watchedProcesses` | `array` | `[]` | Processes to highlight in Watched mode |
241
+ | `watchedProcesses[].name` | `string` | — | Substring matched against process name (case-insensitive) |
242
+ | `watchedProcesses[].label` | `string` | same as `name` | Display label in the Watched view |
243
+ | `refreshInterval` | `number` (ms) | `1000` | Poll interval — minimum `250` ms |
244
+ | `maxProcesses` | `number` | `50` | Max processes shown in the All view (sorted by CPU desc) |
245
+
246
+ ---
247
+
248
+ ## Dashboard Panels
249
+
250
+ | Panel | Toggle key | What it shows |
251
+ |---|---|---|
252
+ | **CPU** | always on | Overall CPU% + per-core bars colored by load |
253
+ | **Memory** | always on | RAM used / free / cached / total with gauge |
254
+ | **Disk** | `d` | Per-mount usage bars + read/write IO rates (MB/s) |
255
+ | **Network** | `n` | Per-interface RX/TX rates + 30-second throughput graph |
256
+ | **Runtime** | `R` | Heap, RSS, event-loop lag, GC stats for managed processes |
257
+ | **Processes** | `p` | Scrollable process table — All or Watched mode |
258
+ | **Logs** | `l` (focus) | Buffered stdout/stderr of managed processes |
259
+
260
+ ---
261
+
262
+ ## Keyboard Shortcuts
263
+
264
+ ### Global
265
+
266
+ | Key | Action |
267
+ |---|---|
268
+ | `q` / `Ctrl+C` | Quit MetWatch |
269
+ | `?` | Toggle keybindings help overlay |
270
+
271
+ ### Panel toggles
272
+
273
+ | Key | Action |
274
+ |---|---|
275
+ | `d` | Toggle Disk panel |
276
+ | `n` | Toggle Network panel |
277
+ | `R` | Toggle Runtime panel |
278
+ | `p` | Toggle Process panel |
279
+ | `l` | Focus / toggle Logs panel |
280
+
281
+ ### Process table
282
+
283
+ | Key | Action |
284
+ |---|---|
285
+ | `a` | All processes mode |
286
+ | `f` | Watched processes mode (from config) |
287
+ | `c` | Sort by CPU usage |
288
+ | `m` | Sort by memory usage |
289
+ | `↑` / `k` | Move selection up |
290
+ | `↓` / `j` | Move selection down |
291
+ | `K` (Shift+k) | Kill selected process (confirm dialog) |
292
+ | `r` | Restart selected managed process |
293
+ | `s` | Stop selected managed process |
294
+
295
+ ---
296
+
297
+ ## Contributing
298
+
299
+ Contributions are welcome! Here is how to get started:
300
+
301
+ 1. **Fork** the repository on GitHub
302
+ 2. **Clone** your fork: `git clone https://github.com/<your-username>/metwatch.git`
303
+ 3. **Create a branch**: `git checkout -b feat/my-feature`
304
+ 4. **Install dependencies**: `bun install`
305
+ 5. **Make your changes** following the conventions below
306
+ 6. **Typecheck**: `bun run typecheck` — must exit with 0 errors before opening a PR
307
+ 7. **Open a Pull Request** against `main` on [victorhhh/metwatch](https://github.com/victorhhh/metwatch/pulls)
308
+
309
+ > **Note:** All pull requests are reviewed and merged exclusively by the maintainer ([@elhuguito](https://github.com/victorhhh)). Submitting a PR does not guarantee acceptance, but all contributions are genuinely appreciated and reviewed.
310
+
311
+ ### Code conventions (summary)
312
+
313
+ - **TypeScript strict mode** — no `any`, no `@ts-ignore` without a comment
314
+ - **Factory functions** over classes — use `create*()` returning plain objects
315
+ - **Event bus** — every `bus.on()` must store and call its unsubscribe in `destroy()`
316
+ - **Widgets are stateless renderers** — no domain data, only UI state
317
+ - **Layer rules** — widgets never import from `services/` directly; all data via bus + state
318
+ - **No `.then()` chains** — use `async/await` everywhere
319
+
320
+ For a full architecture guide, see [AGENTS.md](./AGENTS.md).
321
+
322
+ ### Reporting issues
323
+
324
+ Please open an issue at [github.com/victorhhh/metwatch/issues](https://github.com/victorhhh/metwatch/issues) with:
325
+ - OS and terminal emulator
326
+ - Bun version (`bun --version`)
327
+ - Steps to reproduce
328
+ - Screenshot or error output if applicable
329
+
330
+ ---
331
+
332
+ ## License
333
+
334
+ MIT © 2026 [elhuguito](https://github.com/victorhhh)
335
+
336
+ See [LICENSE](./LICENSE) for the full text.
package/bin/mw.ts ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env bun
2
+ // ---------------------------------------------------------------------------
3
+ // bin/mw.ts — MetWatch CLI entry point
4
+ //
5
+ // This file is the binary registered in package.json under "bin.mw".
6
+ // It simply delegates to the args router which handles all subcommands.
7
+ //
8
+ // Install globally:
9
+ // bun add -g metwatch (from npm)
10
+ // bun link (from local checkout, for development)
11
+ //
12
+ // Then use:
13
+ // mw Open the TUI
14
+ // mw start server.ts Run + watch a script
15
+ // mw list Print managed process states
16
+ // mw logs api --follow Tail logs
17
+ // mw stop all Stop everything
18
+ // ---------------------------------------------------------------------------
19
+
20
+ import '../src/cli/args.ts';
package/index.ts ADDED
@@ -0,0 +1,174 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Bootstrap — MetWatch entry point
3
+ //
4
+ // Initialization order:
5
+ // 1. Load config
6
+ // 2. Create blessed screen
7
+ // 3. Create launcher + log-manager + runtime-manager (if managed procs)
8
+ // 4. Wire launcher → runtime-manager (register inspector on start)
9
+ // 5. Build layout (widgets register bus subscriptions)
10
+ // 6. Start metrics + process managers
11
+ // 7. Launcher starts all managed processes
12
+ // 8. Register global keybindings + signal handlers
13
+ // 9. First screen render
14
+ //
15
+ // Teardown (quit):
16
+ // 1. Stop polling managers + runtime-manager
17
+ // 2. Stop all managed processes
18
+ // 3. Destroy layout (widgets unsubscribe)
19
+ // 4. Destroy screen (restore terminal)
20
+ // 5. process.exit(0)
21
+ // ---------------------------------------------------------------------------
22
+
23
+ import { readFileSync, existsSync } from 'fs';
24
+ import { resolve } from 'path';
25
+
26
+ import { createScreen, destroyScreen } from './src/ui/screen.ts';
27
+ import { buildLayout } from './src/ui/layout.ts';
28
+ import { createMetricsManager } from './src/core/metrics-manager.ts';
29
+ import { createProcessManager } from './src/core/process-manager.ts';
30
+ import { createLauncher } from './src/core/launcher.ts';
31
+ import { createLogManager } from './src/core/log-manager.ts';
32
+ import { createRuntimeManager } from './src/core/runtime-manager.ts';
33
+ import { bus } from './src/core/event-bus.ts';
34
+ import {
35
+ DEFAULT_CONFIG,
36
+ type MetWatchConfig,
37
+ type ResolvedConfig,
38
+ } from './src/types/config.types.ts';
39
+ import type { ManagedProcessDef } from './src/types/managed-process.types.ts';
40
+
41
+ // ── Config loading ──────────────────────────────────────────────────────────
42
+
43
+ function loadConfig(): ResolvedConfig {
44
+ const configPath = resolve(process.cwd(), 'metwatch.config.json');
45
+
46
+ if (!existsSync(configPath)) return { ...DEFAULT_CONFIG };
47
+
48
+ try {
49
+ const raw = readFileSync(configPath, 'utf-8');
50
+ const parsed = JSON.parse(raw) as Partial<MetWatchConfig>;
51
+ return {
52
+ watchedProcesses: parsed.watchedProcesses ?? DEFAULT_CONFIG.watchedProcesses,
53
+ managedProcesses: parsed.managedProcesses ?? DEFAULT_CONFIG.managedProcesses,
54
+ refreshInterval: Math.max(250, parsed.refreshInterval ?? DEFAULT_CONFIG.refreshInterval),
55
+ maxProcesses: parsed.maxProcesses ?? DEFAULT_CONFIG.maxProcesses,
56
+ logScrollback: parsed.logScrollback ?? DEFAULT_CONFIG.logScrollback,
57
+ panels: {
58
+ ...DEFAULT_CONFIG.panels,
59
+ ...(parsed.panels ?? {}),
60
+ },
61
+ };
62
+ } catch (err) {
63
+ console.error(`[MetWatch] Failed to parse metwatch.config.json: ${String(err)}`);
64
+ return { ...DEFAULT_CONFIG };
65
+ }
66
+ }
67
+
68
+ // ── Main ────────────────────────────────────────────────────────────────────
69
+
70
+ export async function main(extraDefs: ManagedProcessDef[] = []): Promise<void> {
71
+ const config = loadConfig();
72
+
73
+ // Merge managed process defs: config-defined + CLI-supplied
74
+ const configDefs: ManagedProcessDef[] = config.managedProcesses ?? [];
75
+ const cliNames = new Set(extraDefs.map(d => d.name));
76
+ const mergedDefs = [
77
+ ...configDefs.filter(d => !cliNames.has(d.name)),
78
+ ...extraDefs,
79
+ ];
80
+
81
+ const hasManaged = mergedDefs.length > 0;
82
+
83
+ const launcher = hasManaged ? createLauncher(mergedDefs) : null;
84
+ const logManager = hasManaged ? createLogManager(config.logScrollback ?? 500) : null;
85
+ const runtimeManager = hasManaged ? createRuntimeManager(config.refreshInterval) : null;
86
+
87
+ // Wire launcher events to runtime-manager so we get inspector connections
88
+ // automatically whenever a managed process starts or stops.
89
+ const unsubStarted = hasManaged ? bus.on('managed:started', ({ id, pid }) => {
90
+ // The launcher appends --inspect=0; the WS URL is reported on stderr.
91
+ // We receive it via the log:line event below.
92
+ void id; void pid;
93
+ }) : () => undefined;
94
+
95
+ // Parse inspector URL from log lines (Node/Bun print it to stderr on start)
96
+ const inspectorUrls = new Map<string, string>();
97
+ const unsubLogLine = hasManaged ? bus.on('log:line', ({ id, stream, line }) => {
98
+ if (stream !== 'stderr') return;
99
+ // e.g.: "Debugger listening on ws://127.0.0.1:9229/uuid"
100
+ const m = line.match(/Debugger listening on (ws:\/\/[^\s]+)/);
101
+ if (m && m[1] && !inspectorUrls.has(id)) {
102
+ inspectorUrls.set(id, m[1]);
103
+ // Find the pid from the latest managed:started event via launcher
104
+ const proc = launcher?.get(id);
105
+ if (proc?.pid) {
106
+ runtimeManager?.register(id, proc.pid, m[1]);
107
+ }
108
+ }
109
+ }) : () => undefined;
110
+
111
+ const unsubStopped = hasManaged ? bus.on('managed:stopped', ({ id }) => {
112
+ runtimeManager?.unregister(id);
113
+ inspectorUrls.delete(id);
114
+ }) : () => undefined;
115
+
116
+ const unsubCrashed = hasManaged ? bus.on('managed:crashed', ({ id }) => {
117
+ runtimeManager?.unregister(id);
118
+ inspectorUrls.delete(id);
119
+ }) : () => undefined;
120
+
121
+ const screen = createScreen();
122
+ const layout = buildLayout({ screen, config, launcher, logManager });
123
+
124
+ const metricsManager = createMetricsManager({ intervalMs: config.refreshInterval });
125
+ const processManager = createProcessManager(config);
126
+
127
+ metricsManager.start();
128
+ processManager.start();
129
+
130
+ // Start managed processes after widgets are ready
131
+ launcher?.startAll();
132
+
133
+ // ── Global keybindings ────────────────────────────────────────────────────
134
+
135
+ function quit(): void {
136
+ bus.emit('ui:quit', undefined);
137
+ metricsManager.stop();
138
+ processManager.stop();
139
+ runtimeManager?.stop();
140
+ launcher?.stopAll();
141
+ logManager?.destroy();
142
+ unsubStarted();
143
+ unsubLogLine();
144
+ unsubStopped();
145
+ unsubCrashed();
146
+ layout.destroy();
147
+ destroyScreen();
148
+ process.exit(0);
149
+ }
150
+
151
+ screen.key(['q', 'C-c'], quit);
152
+
153
+ // ── Error handling ────────────────────────────────────────────────────────
154
+
155
+ bus.on('app:error', ({ source, error }) => {
156
+ void source;
157
+ void error;
158
+ });
159
+
160
+ // ── First render ──────────────────────────────────────────────────────────
161
+
162
+ screen.render();
163
+
164
+ // ── Signal handling ───────────────────────────────────────────────────────
165
+
166
+ process.on('SIGTERM', quit);
167
+ process.on('uncaughtException', (err) => {
168
+ destroyScreen();
169
+ console.error('[MetWatch] Uncaught exception:', err);
170
+ process.exit(1);
171
+ });
172
+ }
173
+
174
+ await main();
@@ -0,0 +1,9 @@
1
+ {
2
+ "watchedProcesses": [
3
+ { "name": "node", "label": "Node Apps" },
4
+ { "name": "bun", "label": "Bun Apps" },
5
+ { "name": "python", "label": "Python" }
6
+ ],
7
+ "refreshInterval": 1000,
8
+ "maxProcesses": 50
9
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "metwatch",
3
+ "version": "0.1.0",
4
+ "description": "Terminal process monitoring & management tool — like htop + PM2 in your terminal",
5
+ "module": "index.ts",
6
+ "main": "index.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "mw": "./bin/mw.ts"
10
+ },
11
+ "files": [
12
+ "bin/",
13
+ "src/",
14
+ "index.ts",
15
+ "metwatch.config.json"
16
+ ],
17
+ "keywords": [
18
+ "process",
19
+ "monitor",
20
+ "tui",
21
+ "cli",
22
+ "htop",
23
+ "pm2",
24
+ "bun",
25
+ "terminal",
26
+ "dashboard"
27
+ ],
28
+ "engines": {
29
+ "bun": ">=1.0.0"
30
+ },
31
+ "scripts": {
32
+ "start": "bun run index.ts",
33
+ "dev": "bun run --watch index.ts",
34
+ "typecheck": "tsc --noEmit"
35
+ },
36
+ "devDependencies": {
37
+ "@types/bun": "latest",
38
+ "@types/node": "^25.8.0"
39
+ },
40
+ "peerDependencies": {
41
+ "typescript": "^5"
42
+ },
43
+ "dependencies": {
44
+ "blessed": "^0.1.81",
45
+ "blessed-contrib": "^4.11.0",
46
+ "chalk": "^5.6.2",
47
+ "pidusage": "^4.0.1",
48
+ "systeminformation": "^5.31.6"
49
+ }
50
+ }