healr 1.0.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/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import { registerRunCommand } from './commands/run.js';
4
+ import { registerStatusCommand } from './commands/status.js';
5
+ import { registerLogsCommand } from './commands/logs.js';
6
+ import { registerInitCommand } from './commands/init.js';
7
+ import { registerDashboardCommand } from './commands/dashboard.js';
8
+ import { registerLinkCommand } from './commands/link.js';
9
+ program
10
+ .name('healr')
11
+ .description('Self-healing supervisor for developer applications')
12
+ .version('0.1.0');
13
+ registerRunCommand(program);
14
+ registerStatusCommand(program);
15
+ registerLogsCommand(program);
16
+ registerInitCommand(program);
17
+ registerDashboardCommand(program);
18
+ registerLinkCommand(program);
19
+ program.parse();
20
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC5B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,wBAAwB,CAAC,OAAO,CAAC,CAAC;AAClC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerDashboardCommand(program: Command): void;
3
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqD/D"}
@@ -0,0 +1,61 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { createDaemon, loadConfig } from '@healr/core';
3
+ import { TerminalNotifier } from '@healr/notifiers';
4
+ import { DashboardWsNotifier } from '@healr/notifiers';
5
+ export function registerDashboardCommand(program) {
6
+ program
7
+ .command('dashboard')
8
+ .description('Launch the Healr web dashboard and optionally supervise a command')
9
+ .option('-p, --port <number>', 'Dashboard port', '4242')
10
+ .option('--run <cmd>', 'Command to supervise while serving the dashboard')
11
+ .option('--app-port <number>', 'Port the supervised app listens on', parseInt)
12
+ .option('-n, --name <name>', 'App name')
13
+ .option('--cwd <path>', 'Working directory')
14
+ .option('-c, --config <path>', 'Path to healr.config.js')
15
+ .action(async (opts) => {
16
+ const dashPort = parseInt(opts.port, 10);
17
+ const cwd = opts.cwd ?? process.cwd();
18
+ const config = await loadConfig(opts.config, cwd);
19
+ const command = opts.run ?? config.command;
20
+ if (!command) {
21
+ console.error('No command to supervise. Use --run <cmd> or set command in healr.config.js');
22
+ process.exit(1);
23
+ }
24
+ const terminalNotifier = new TerminalNotifier();
25
+ const dashboardNotifier = new DashboardWsNotifier(dashPort, () => [daemon.getStatus()]);
26
+ await dashboardNotifier.start();
27
+ const daemon = await createDaemon(command, {
28
+ name: opts.name,
29
+ port: opts.appPort,
30
+ cwd,
31
+ configPath: opts.config,
32
+ notifiers: [terminalNotifier, dashboardNotifier],
33
+ });
34
+ daemon.bus.on('metrics:sample', ({ appName, cpu, memoryRSS }) => {
35
+ dashboardNotifier.broadcastMetrics(appName, cpu, memoryRSS / 1024 / 1024);
36
+ });
37
+ daemon.start();
38
+ // Open browser
39
+ const url = `http://127.0.0.1:${dashPort}`;
40
+ console.log(`\nDashboard: ${url}\n`);
41
+ openBrowser(url);
42
+ const shutdown = async () => {
43
+ await daemon.stop();
44
+ await dashboardNotifier.stop();
45
+ process.exit(0);
46
+ };
47
+ process.on('SIGINT', shutdown);
48
+ process.on('SIGTERM', shutdown);
49
+ });
50
+ }
51
+ function openBrowser(url) {
52
+ const platform = process.platform;
53
+ const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';
54
+ try {
55
+ execFile(cmd, [url], { shell: platform === 'win32' });
56
+ }
57
+ catch {
58
+ // Non-critical
59
+ }
60
+ }
61
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,UAAU,wBAAwB,CAAC,OAAgB;IACvD,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,mEAAmE,CAAC;SAChF,MAAM,CAAC,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,CAAC;SACvD,MAAM,CAAC,aAAa,EAAE,kDAAkD,CAAC;SACzE,MAAM,CAAC,qBAAqB,EAAE,oCAAoC,EAAE,QAAQ,CAAC;SAC7E,MAAM,CAAC,mBAAmB,EAAE,UAAU,CAAC;SACvC,MAAM,CAAC,cAAc,EAAE,mBAAmB,CAAC;SAC3C,MAAM,CAAC,qBAAqB,EAAE,yBAAyB,CAAC;SACxD,MAAM,CAAC,KAAK,EAAE,IAAoG,EAAE,EAAE;QACrH,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAElD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,4EAA4E,CAAC,CAAC;YAC5F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC;QAChD,MAAM,iBAAiB,GAAG,IAAI,mBAAmB,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAExF,MAAM,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE;YACzC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,GAAG;YACH,UAAU,EAAE,IAAI,CAAC,MAAM;YACvB,SAAS,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;SACjD,CAAC,CAAC;QAEH,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE;YAC9D,iBAAiB,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,eAAe;QACf,MAAM,GAAG,GAAG,oBAAoB,QAAQ,EAAE,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;QACrC,WAAW,CAAC,GAAG,CAAC,CAAC;QAEjB,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;YAC1B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,MAAM,iBAAiB,CAAC,IAAI,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC;QACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,GAAG,GAAG,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IACzF,IAAI,CAAC;QACH,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerInitCommand(program: Command): void;
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsE1D"}
@@ -0,0 +1,79 @@
1
+ import * as clack from '@clack/prompts';
2
+ import { writeFileSync, existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ export function registerInitCommand(program) {
5
+ program
6
+ .command('init')
7
+ .description('Create a healr.config.js interactively')
8
+ .action(async () => {
9
+ clack.intro('healr init');
10
+ const configPath = join(process.cwd(), 'healr.config.js');
11
+ if (existsSync(configPath)) {
12
+ const overwrite = await clack.confirm({
13
+ message: 'healr.config.js already exists. Overwrite?',
14
+ initialValue: false,
15
+ });
16
+ if (clack.isCancel(overwrite) || !overwrite) {
17
+ clack.outro('Aborted.');
18
+ return;
19
+ }
20
+ }
21
+ const name = await clack.text({
22
+ message: 'App name',
23
+ defaultValue: 'my-app',
24
+ validate: (v) => (v.trim() ? undefined : 'Name is required'),
25
+ });
26
+ if (clack.isCancel(name)) {
27
+ clack.outro('Aborted.');
28
+ return;
29
+ }
30
+ const command = await clack.text({
31
+ message: 'Start command',
32
+ defaultValue: 'npm run dev',
33
+ });
34
+ if (clack.isCancel(command)) {
35
+ clack.outro('Aborted.');
36
+ return;
37
+ }
38
+ const portStr = await clack.text({
39
+ message: 'Port (leave blank if none)',
40
+ defaultValue: '',
41
+ });
42
+ if (clack.isCancel(portStr)) {
43
+ clack.outro('Aborted.');
44
+ return;
45
+ }
46
+ const autoHealCrash = await clack.confirm({
47
+ message: 'Auto-restart on crash (no prompt)?',
48
+ initialValue: false,
49
+ });
50
+ if (clack.isCancel(autoHealCrash)) {
51
+ clack.outro('Aborted.');
52
+ return;
53
+ }
54
+ const port = portStr ? parseInt(portStr, 10) : undefined;
55
+ const content = `export default {
56
+ name: ${JSON.stringify(name)},
57
+ command: ${JSON.stringify(command)},${port ? `\n port: ${port},` : ''}
58
+ restarts: { max: 5, backoffBaseMs: 1000, backoffCapMs: 60000 },
59
+ autoHeal: {
60
+ crash: ${autoHealCrash},
61
+ portConflict: false,
62
+ memory: false,
63
+ cpu: false,
64
+ dependency: false,
65
+ env: false,
66
+ },
67
+ notifiers: {
68
+ terminal: true,
69
+ // dashboard: { port: 4242 },
70
+ // slack: { webhookUrl: process.env.HEALR_SLACK_URL },
71
+ },
72
+ };
73
+ `;
74
+ writeFileSync(configPath, content);
75
+ clack.log.success(`Created healr.config.js`);
76
+ clack.outro(`Run: healr run "${command}"`);
77
+ });
78
+ }
79
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerLinkCommand(program: Command): void;
3
+ //# sourceMappingURL=link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/commands/link.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyC1D"}
@@ -0,0 +1,47 @@
1
+ import * as clack from '@clack/prompts';
2
+ import { writeFileSync, existsSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ const API_URL = process.env.HEALR_API_URL ?? 'https://api.healr.dev';
5
+ export function registerLinkCommand(program) {
6
+ program
7
+ .command('link')
8
+ .description('Link this project directory to a Healr cloud project (writes API key to healr.config.js / .env)')
9
+ .option('--key <apiKey>', 'API key (skips prompt)')
10
+ .option('--cwd <path>', 'Working directory')
11
+ .action(async (opts) => {
12
+ clack.intro('healr link');
13
+ const cwd = opts.cwd ?? process.cwd();
14
+ let apiKey = opts.key;
15
+ if (!apiKey) {
16
+ const input = await clack.text({
17
+ message: 'Paste your API key (from app.healr.dev):',
18
+ validate: (v) => v.startsWith('hlr_') ? undefined : 'Key must start with hlr_',
19
+ });
20
+ if (clack.isCancel(input)) {
21
+ clack.cancel('Cancelled');
22
+ return;
23
+ }
24
+ apiKey = input;
25
+ }
26
+ // Write to .env file
27
+ const envPath = join(cwd, '.env');
28
+ const envLine = `HEALR_API_KEY=${apiKey}`;
29
+ if (existsSync(envPath)) {
30
+ const content = readFileSync(envPath, 'utf8');
31
+ if (content.includes('HEALR_API_KEY=')) {
32
+ writeFileSync(envPath, content.replace(/^HEALR_API_KEY=.*/m, envLine));
33
+ }
34
+ else {
35
+ writeFileSync(envPath, content + `\n${envLine}\n`);
36
+ }
37
+ }
38
+ else {
39
+ writeFileSync(envPath, `${envLine}\n`);
40
+ }
41
+ clack.log.success(`API key saved to .env`);
42
+ clack.log.info(`Run: healr run "npm run dev" --port 3000`);
43
+ clack.log.info(`Dashboard: ${API_URL.replace('api.', 'app.')}`);
44
+ clack.outro('Linked!');
45
+ });
46
+ }
47
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/commands/link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,uBAAuB,CAAC;AAErE,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,iGAAiG,CAAC;SAC9G,MAAM,CAAC,gBAAgB,EAAE,wBAAwB,CAAC;SAClD,MAAM,CAAC,cAAc,EAAE,mBAAmB,CAAC;SAC3C,MAAM,CAAC,KAAK,EAAE,IAAoC,EAAE,EAAE;QACrD,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAE1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACtC,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC;QAEtB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC;gBAC7B,OAAO,EAAE,0CAA0C;gBACnD,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,0BAA0B;aAC/E,CAAC,CAAC;YACH,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;gBAAC,OAAO;YAAC,CAAC;YACjE,MAAM,GAAG,KAAK,CAAC;QACjB,CAAC;QAED,qBAAqB;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,iBAAiB,MAAM,EAAE,CAAC;QAE1C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC9C,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACvC,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAAC;YACzE,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,OAAO,EAAE,GAAG,OAAO,IAAI,CAAC,CAAC;QACzC,CAAC;QAED,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;QAC3C,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QAC3D,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAChE,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerLogsCommand(program: Command): void;
3
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2B1D"}
@@ -0,0 +1,26 @@
1
+ import { Store } from '@healr/core';
2
+ export function registerLogsCommand(program) {
3
+ program
4
+ .command('logs [name]')
5
+ .description('Show audit log events for an app (default: all)')
6
+ .option('-n, --lines <number>', 'Number of events to show', '50')
7
+ .action((name, opts) => {
8
+ const store = new Store();
9
+ const limit = parseInt(opts.lines, 10);
10
+ const appName = name ?? '*';
11
+ const events = store.getRecentEvents(appName, limit);
12
+ if (events.length === 0) {
13
+ console.log(`No events found${name ? ` for ${name}` : ''}.`);
14
+ store.close();
15
+ return;
16
+ }
17
+ console.log(`\nAudit log${name ? ` for ${name}` : ''}:\n`);
18
+ for (const ev of [...events].reverse()) {
19
+ const time = new Date(ev.ts).toLocaleTimeString();
20
+ const payload = JSON.stringify(ev.payload);
21
+ console.log(`${time} [${ev.app}] ${ev.kind} ${payload.slice(0, 120)}`);
22
+ }
23
+ store.close();
24
+ });
25
+ }
26
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,iDAAiD,CAAC;SAC9D,MAAM,CAAC,sBAAsB,EAAE,0BAA0B,EAAE,IAAI,CAAC;SAChE,MAAM,CAAC,CAAC,IAAwB,EAAE,IAAuB,EAAE,EAAE;QAC5D,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,IAAI,GAAG,CAAC;QAE5B,MAAM,MAAM,GAAG,KAAK,CAAC,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAErD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC7D,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC3D,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,kBAAkB,EAAE,CAAC;YAClD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerRunCommand(program: Command): void;
3
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkFzD"}
@@ -0,0 +1,78 @@
1
+ import * as clack from '@clack/prompts';
2
+ import { createDaemon, loadConfig } from '@healr/core';
3
+ import { TerminalNotifier, SlackNotifier, DiscordNotifier, EmailNotifier, CloudNotifier } from '@healr/notifiers';
4
+ import { hostname } from 'node:os';
5
+ export function registerRunCommand(program) {
6
+ program
7
+ .command('run <cmd>')
8
+ .description('Supervise a command with self-healing')
9
+ .option('-p, --port <number>', 'Port the app listens on', parseInt)
10
+ .option('-n, --name <name>', 'App name for logs and notifications')
11
+ .option('-c, --config <path>', 'Path to healr.config.js')
12
+ .option('--cwd <path>', 'Working directory for the command')
13
+ .action(async (cmd, opts) => {
14
+ clack.intro('healr');
15
+ const cwd = opts.cwd ?? process.cwd();
16
+ const config = await loadConfig(opts.config, cwd);
17
+ const notifiers = [new TerminalNotifier()];
18
+ // Cloud relay — wired when HEALR_API_KEY is set
19
+ const apiKey = process.env.HEALR_API_KEY;
20
+ let cloudNotifier = null;
21
+ if (apiKey) {
22
+ const wsUrl = (process.env.HEALR_API_URL ?? 'https://api.healr.dev').replace(/^http/, 'ws') + '/agent';
23
+ cloudNotifier = new CloudNotifier(apiKey, wsUrl, hostname());
24
+ notifiers.push(cloudNotifier);
25
+ clack.log.info('Cloud relay active — visit app.healr.dev');
26
+ }
27
+ // Load remote notifiers from config
28
+ const nc = config.notifiers;
29
+ if (nc.slack?.webhookUrl) {
30
+ notifiers.push(new SlackNotifier(nc.slack.webhookUrl));
31
+ }
32
+ if (nc.discord?.webhookUrl) {
33
+ notifiers.push(new DiscordNotifier(nc.discord.webhookUrl));
34
+ }
35
+ if (nc.email?.smtp && nc.email.to) {
36
+ const emailConfig = {
37
+ smtp: nc.email.smtp,
38
+ to: nc.email.to,
39
+ };
40
+ notifiers.push(new EmailNotifier(emailConfig));
41
+ }
42
+ const daemon = await createDaemon(cmd, {
43
+ name: opts.name,
44
+ port: opts.port,
45
+ cwd,
46
+ configPath: opts.config,
47
+ notifiers,
48
+ });
49
+ clack.log.step(`Supervising: ${cmd}`);
50
+ if (opts.port ?? config.port)
51
+ clack.log.info(`Watching port :${opts.port ?? config.port}`);
52
+ daemon.start();
53
+ daemon.bus.on('process:stdout', ({ line }) => process.stdout.write(line + '\n'));
54
+ daemon.bus.on('process:stderr', ({ line }) => process.stderr.write(line + '\n'));
55
+ daemon.bus.on('process:spawned', ({ pid }) => {
56
+ clack.log.step(`Process started (PID ${pid})`);
57
+ });
58
+ // Forward metrics to cloud (sampled: max 1 point per 10s)
59
+ if (cloudNotifier) {
60
+ let lastCloudMetric = 0;
61
+ daemon.bus.on('metrics:sample', ({ appName, cpu, memoryRSS, timestamp }) => {
62
+ if (timestamp - lastCloudMetric < 10_000)
63
+ return;
64
+ lastCloudMetric = timestamp;
65
+ cloudNotifier.sendMetrics({ appName, cpu, memoryRSS, timestamp });
66
+ });
67
+ }
68
+ const shutdown = async () => {
69
+ clack.log.step('Shutting down...');
70
+ await daemon.stop();
71
+ clack.outro('Stopped');
72
+ process.exit(0);
73
+ };
74
+ process.on('SIGINT', shutdown);
75
+ process.on('SIGTERM', shutdown);
76
+ });
77
+ }
78
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerStatusCommand(program: Command): void;
3
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkC5D"}
@@ -0,0 +1,28 @@
1
+ import { Store } from '@healr/core';
2
+ export function registerStatusCommand(program) {
3
+ program
4
+ .command('status')
5
+ .description('Show recent issues from the audit log')
6
+ .action(() => {
7
+ const store = new Store();
8
+ // Status shows the most recent issues for all apps
9
+ // In a multi-daemon setup this would query all running daemons;
10
+ // for v1 we read the sqlite history
11
+ const issues = store.getIssues('*', 20);
12
+ if (issues.length === 0) {
13
+ console.log('No recorded issues. Run `healr run <cmd>` to start supervising.');
14
+ store.close();
15
+ return;
16
+ }
17
+ console.log('\nRecent issues:\n');
18
+ const pad = (s, n) => s.padEnd(n);
19
+ console.log(`${pad('TIME', 10)} ${pad('APP', 16)} ${pad('TYPE', 14)} ${pad('STATE', 12)} SUMMARY`);
20
+ console.log('─'.repeat(100));
21
+ for (const issue of issues) {
22
+ const time = new Date(issue.detectedAt).toLocaleTimeString();
23
+ console.log(`${pad(time, 10)} ${pad(issue.appName, 16)} ${pad(issue.type, 14)} ${pad(issue.state, 12)} ${issue.summary}`);
24
+ }
25
+ store.close();
26
+ });
27
+ }
28
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAC1B,mDAAmD;QACnD,gEAAgE;QAChE,oCAAoC;QACpC,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAExC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;YAC/E,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAElD,OAAO,CAAC,GAAG,CACT,GAAG,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAC1F,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAE7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,kBAAkB,EAAE,CAAC;YAC7D,OAAO,CAAC,GAAG,CACT,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CACjH,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { registerRunCommand } from './commands/run.js';
2
+ export { registerStatusCommand } from './commands/status.js';
3
+ export { registerLogsCommand } from './commands/logs.js';
4
+ export { registerInitCommand } from './commands/init.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { registerRunCommand } from './commands/run.js';
2
+ export { registerStatusCommand } from './commands/status.js';
3
+ export { registerLogsCommand } from './commands/logs.js';
4
+ export { registerInitCommand } from './commands/init.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "healr",
3
+ "version": "1.0.0",
4
+ "description": "Self-healing supervisor for developer apps. Detects crashes, port conflicts, memory leaks — and fixes them.",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/aadesh0706/healr#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/aadesh0706/healr.git"
10
+ },
11
+ "keywords": [
12
+ "healr", "self-healing", "supervisor", "process-manager",
13
+ "crash-recovery", "monitoring", "devtools", "cli"
14
+ ],
15
+ "files": ["dist"],
16
+ "type": "module",
17
+ "main": "./dist/index.js",
18
+ "bin": {
19
+ "healr": "./dist/bin.js"
20
+ },
21
+ "engines": {
22
+ "node": ">=18"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "typecheck": "tsc --noEmit",
27
+ "dev": "tsc --watch",
28
+ "start": "node dist/bin.js"
29
+ },
30
+ "dependencies": {
31
+ "@clack/prompts": "^0.8.2",
32
+ "@healr/core": "^1.0.0",
33
+ "@healr/notifiers": "^1.0.0",
34
+ "commander": "^12.1.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.14.0"
38
+ }
39
+ }