debughub 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/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # DebugHub
2
+
3
+ A cross-platform CLI tool providing a Cursor-like "Debug Mode" loop for any coding agent (Codex, Claude, etc.), without requiring MCP or complex remote execution setups.
4
+
5
+ ## Features
6
+ - **Runtime Setup Guide**: See `docs/RUNTIME_PREREQS.md` for installing Java/Go/Python/Rust/PHP/.NET required by helper E2E tests.
7
+ - **Agent-Agnostic**: Works with any coding assistant capable of modifying files and running basic OS commands.
8
+ - **Vendored Runtime Helpers**: Small, standalone helpers for TypeScript/Node, Browser TS/JS, Java, Python, Rust, PHP, Go, and C# are installed in `.debughub/vendor`.
9
+ - **Shared HTTP Contract**: All helpers follow one event contract (`.debughub/vendor/<version>/http/EVENT_CONTRACT.md` after `debughub install`) and submit best-effort HTTP events to the local collector.
10
+ - **Deterministic**: A `MANIFEST.json` and strict integrity verification ensures files are not tampered with.
11
+ - **Safe and Local**: By default, the collector server only binds to `127.0.0.1`.
12
+
13
+ ## Quick Start
14
+
15
+ 1. Install inside any repository:
16
+ ```bash
17
+ npx debughub install
18
+ ```
19
+ 2. Start the local collector:
20
+ ```bash
21
+ npx debughub start
22
+ ```
23
+ 3. Read the given `sessionId` and endpoint. Follow the instructions to configure your environment variables:
24
+ - `DEBUGHUB_ENABLED=1`
25
+ - `DEBUGHUB_SESSION=<sessionId>`
26
+ - `DEBUGHUB_ENDPOINT=http://127.0.0.1:<port>`
27
+
28
+ 4. Use the helper inside your app code (see `.debughub/vendor/<version>`).
29
+ 5. Run your app and reproduce the issue.
30
+ 6. Check logs:
31
+ ```bash
32
+ npx debughub tail --n 50
33
+ ```
34
+
35
+ ## Security Model
36
+ - No network traffic leaves your local machine.
37
+ - No remote code is downloaded at runtime.
38
+ - No `eval` or shell spawning in helpers.
39
+ - The `debughub verify` command validates the helper code matches the official SHA-256 signatures.
40
+
41
+ ## Commands
42
+ - `debughub install`: Installs support files to `.debughub/`.
43
+ - `debughub start`: Starts the collector server in the background.
44
+ - `debughub stop`: Stops the background collector.
45
+ - `debughub tail`: Print the latest recorded events.
46
+ - `debughub search "<query>"`: Search events by text or label.
47
+ - `debughub clear`: Clears the output log file.
48
+ - `debughub verify`: Verifies integrity of the vendor code in `.debughub/`.
49
+ - `debughub doctor`: Checks installation and system status.
package/dist/cli.js ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const install_1 = require("./commands/install");
6
+ const start_1 = require("./commands/start");
7
+ const stop_1 = require("./commands/stop");
8
+ const tail_1 = require("./commands/tail");
9
+ const search_1 = require("./commands/search");
10
+ const clear_1 = require("./commands/clear");
11
+ const verify_1 = require("./commands/verify");
12
+ const doctor_1 = require("./commands/doctor");
13
+ const server_1 = require("./commands/server");
14
+ const program = new commander_1.Command();
15
+ const pkg = require('../package.json');
16
+ program
17
+ .name('debughub')
18
+ .description('DebugHub: Agent-agnostic local debug loop')
19
+ .version(pkg.version);
20
+ program.command('install')
21
+ .description('Installs vendored DebugHub runtime helpers into the current repo')
22
+ .action(install_1.install);
23
+ program.command('start')
24
+ .description('Starts the local collector server')
25
+ .action(start_1.start);
26
+ program.command('stop')
27
+ .description('Stops the local collector server')
28
+ .action(stop_1.stop);
29
+ program.command('tail')
30
+ .description('Tails the last N events')
31
+ .option('-n, --n <number>', 'Number of events', '200')
32
+ .option('--session <id>', 'Session ID')
33
+ .option('--json', 'Print raw JSON instead of pretty output', false)
34
+ .action(tail_1.tail);
35
+ program.command('search <query>')
36
+ .description('Searches the JSONL file for substring matches')
37
+ .option('--label <label>', 'Filter by label')
38
+ .option('--hypothesis <id>', 'Filter by hypothesisId')
39
+ .option('--level <level>', 'Filter by level')
40
+ .option('--session <id>', 'Session ID')
41
+ .action(search_1.search);
42
+ program.command('clear')
43
+ .description('Clears the current session output file')
44
+ .option('--session <id>', 'Session ID')
45
+ .action(clear_1.clear);
46
+ program.command('verify')
47
+ .description('Verifies integrity of installed vendor files')
48
+ .action(verify_1.verify);
49
+ program.command('doctor')
50
+ .description('Prints quick diagnostics')
51
+ .action(doctor_1.doctor);
52
+ program.command('_server <sessionId> <port>', { hidden: true })
53
+ .action(server_1._server);
54
+ program.parse(process.argv);
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.clear = clear;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ function clear(options) {
40
+ const cwd = process.cwd();
41
+ const debughubDir = path.join(cwd, '.debughub');
42
+ let sessionId = options.session;
43
+ if (!sessionId) {
44
+ const stateFile = path.join(debughubDir, 'state.json');
45
+ if (fs.existsSync(stateFile)) {
46
+ try {
47
+ const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
48
+ sessionId = state.session;
49
+ }
50
+ catch (e) { }
51
+ }
52
+ }
53
+ if (!sessionId) {
54
+ console.error('Could not determine active session ID.');
55
+ process.exit(1);
56
+ }
57
+ const outFile = path.join(debughubDir, 'out', `${sessionId}.jsonl`);
58
+ if (fs.existsSync(outFile)) {
59
+ fs.truncateSync(outFile, 0);
60
+ console.log(`Cleared log file for session ${sessionId}`);
61
+ }
62
+ else {
63
+ console.log(`Session ${sessionId} has no log file yet.`);
64
+ }
65
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.doctor = doctor;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const http = __importStar(require("http"));
40
+ function doctor() {
41
+ const cwd = process.cwd();
42
+ const debughubDir = path.join(cwd, '.debughub');
43
+ const stateFile = path.join(debughubDir, 'state.json');
44
+ const currentLink = path.join(debughubDir, 'vendor', 'current');
45
+ console.log('🩺 DebugHub Doctor');
46
+ console.log('==================');
47
+ // Check 1: Installation
48
+ const installed = fs.existsSync(currentLink);
49
+ console.log(`[${installed ? 'x' : ' '}] Installation: .debughub/vendor directory exists`);
50
+ if (installed) {
51
+ const version = fs.readFileSync(currentLink, 'utf-8').trim();
52
+ console.log(` Version linked: ${version}`);
53
+ }
54
+ // Check 2: Collector status
55
+ const isRunning = fs.existsSync(stateFile);
56
+ console.log(`[${isRunning ? 'x' : ' '}] Collector : Running state found`);
57
+ if (isRunning) {
58
+ try {
59
+ const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
60
+ console.log(` Session ID: ${state.session}`);
61
+ console.log(` PID : ${state.pid}`);
62
+ console.log(` Port : ${state.port}`);
63
+ // Check writable output
64
+ const outFile = path.join(debughubDir, 'out', `${state.session}.jsonl`);
65
+ try {
66
+ fs.accessSync(path.dirname(outFile), fs.constants.W_OK);
67
+ console.log(`[x] Output Path : ${outFile} is reachable/writable`);
68
+ }
69
+ catch (e) {
70
+ console.log(`[ ] Output Path : ${outFile} is NOT writable`);
71
+ }
72
+ // Check Reachability
73
+ const req = http.request({
74
+ hostname: '127.0.0.1',
75
+ port: state.port,
76
+ path: '/event',
77
+ method: 'OPTIONS',
78
+ }, (res) => {
79
+ if (res.statusCode === 204) {
80
+ console.log(`[x] Reachability: Endpoint http://127.0.0.1:${state.port}/event is responding`);
81
+ }
82
+ else {
83
+ console.log(`[ ] Reachability: Endpoint responded with ${res.statusCode}`);
84
+ }
85
+ });
86
+ req.on('error', (e) => {
87
+ console.log(`[ ] Reachability: Error connecting to endpoint: ${e.message}`);
88
+ });
89
+ req.end();
90
+ return;
91
+ }
92
+ catch (e) {
93
+ console.log(` State file is unreadable or corrupt.`);
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.install = install;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const verify_1 = require("./verify");
40
+ function install() {
41
+ const pkg = require('../../package.json');
42
+ const version = pkg.version;
43
+ const cwd = process.cwd();
44
+ const debughubDir = path.join(cwd, '.debughub');
45
+ const targetVendorDir = path.join(debughubDir, 'vendor', version);
46
+ const currentLinkFile = path.join(debughubDir, 'vendor', 'current');
47
+ // Find source bundle
48
+ const distVendorPath = path.resolve(__dirname, '..', 'vendor', version);
49
+ if (!fs.existsSync(distVendorPath)) {
50
+ console.error(`Error: Cannot find DebugHub distribution bundle for v${version} at ${distVendorPath}`);
51
+ process.exit(1);
52
+ }
53
+ // Create target structure
54
+ fs.mkdirSync(targetVendorDir, { recursive: true });
55
+ fs.mkdirSync(path.join(debughubDir, 'out'), { recursive: true });
56
+ // Copy files
57
+ copyRecursiveSync(distVendorPath, targetVendorDir);
58
+ // Update "current" pointer (use a text file to avoid symlink issues on windows)
59
+ fs.writeFileSync(currentLinkFile, version, 'utf-8');
60
+ // Write default config
61
+ const configFile = path.join(debughubDir, 'debughub.json');
62
+ if (!fs.existsSync(configFile)) {
63
+ fs.writeFileSync(configFile, JSON.stringify({
64
+ bindHost: "127.0.0.1",
65
+ allowRemote: false
66
+ }, null, 2), 'utf-8');
67
+ }
68
+ console.log(`DebugHub v${version} vendor files installed to .debughub/vendor/${version}`);
69
+ console.log(`Verifying installation...`);
70
+ const isValid = (0, verify_1.verifyVendorFiles)(cwd);
71
+ if (!isValid) {
72
+ console.error('Verify failed immediately after install. Installation might be corrupted.');
73
+ process.exit(1);
74
+ }
75
+ console.log('Installation verified successfully ✨');
76
+ }
77
+ function copyRecursiveSync(src, dest) {
78
+ const stat = fs.statSync(src);
79
+ if (stat.isDirectory()) {
80
+ fs.mkdirSync(dest, { recursive: true });
81
+ for (const child of fs.readdirSync(src)) {
82
+ copyRecursiveSync(path.join(src, child), path.join(dest, child));
83
+ }
84
+ }
85
+ else {
86
+ fs.copyFileSync(src, dest);
87
+ }
88
+ }
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.search = search;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ function search(query, options) {
40
+ const cwd = process.cwd();
41
+ const debughubDir = path.join(cwd, '.debughub');
42
+ let sessionId = options.session;
43
+ if (!sessionId) {
44
+ const stateFile = path.join(debughubDir, 'state.json');
45
+ if (fs.existsSync(stateFile)) {
46
+ try {
47
+ const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
48
+ sessionId = state.session;
49
+ }
50
+ catch (e) { }
51
+ }
52
+ }
53
+ if (!sessionId) {
54
+ console.error('Could not determine active session ID. Provide --session or run `debughub start`.');
55
+ process.exit(1);
56
+ }
57
+ const outFile = path.join(debughubDir, 'out', `${sessionId}.jsonl`);
58
+ if (!fs.existsSync(outFile)) {
59
+ console.log(`No events yet in session ${sessionId}`);
60
+ return;
61
+ }
62
+ const content = fs.readFileSync(outFile, 'utf-8');
63
+ const lines = content.trim().split('\n').filter(Boolean);
64
+ let matches = 0;
65
+ for (const l of lines) {
66
+ try {
67
+ const parsed = JSON.parse(l);
68
+ // Filters
69
+ if (options.label && parsed.label !== options.label)
70
+ continue;
71
+ if (options.hypothesis && parsed.hypothesisId !== options.hypothesis)
72
+ continue;
73
+ if (options.level && parsed.level !== options.level)
74
+ continue;
75
+ // Substring match
76
+ if (query && !l.includes(query))
77
+ continue;
78
+ matches++;
79
+ const ts = new Date(parsed.ts).toLocaleTimeString();
80
+ const levelColorStr = parsed.level === 'error' ? '\x1b[31m[ERROR]\x1b[0m' :
81
+ parsed.level === 'warn' ? '\x1b[33m[WARN]\x1b[0m' :
82
+ '\x1b[36m[INFO]\x1b[0m';
83
+ let meta = '';
84
+ if (parsed.hypothesisId)
85
+ meta += ` [H:${parsed.hypothesisId}]`;
86
+ if (parsed.loc)
87
+ meta += ` [L:${parsed.loc}]`;
88
+ console.log(`[${ts}] ${levelColorStr} ${parsed.label}${meta}`);
89
+ if (parsed.data !== null) {
90
+ console.dir(parsed.data, { depth: 4, colors: true });
91
+ }
92
+ }
93
+ catch (e) {
94
+ if (query && l.includes(query)) {
95
+ matches++;
96
+ console.log(l);
97
+ }
98
+ }
99
+ }
100
+ if (matches === 0) {
101
+ console.log(`No matches found for query: "${query}"`);
102
+ }
103
+ else {
104
+ console.log(`\nFound ${matches} match(es).`);
105
+ }
106
+ }
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports._server = _server;
37
+ const http = __importStar(require("http"));
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ function _server(sessionId, portStr) {
41
+ const cwd = process.cwd();
42
+ const stateFile = path.join(cwd, '.debughub', 'state.json');
43
+ const outFile = path.join(cwd, '.debughub', 'out', `${sessionId}.jsonl`);
44
+ const server = http.createServer((req, res) => {
45
+ // Basic CORS
46
+ res.setHeader('Access-Control-Allow-Origin', '*');
47
+ res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
48
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
49
+ if (req.method === 'OPTIONS') {
50
+ res.writeHead(204);
51
+ res.end();
52
+ return;
53
+ }
54
+ if (req.method === 'POST' && req.url === '/event') {
55
+ let body = '';
56
+ req.on('data', chunk => {
57
+ body += chunk.toString();
58
+ });
59
+ req.on('end', () => {
60
+ try {
61
+ fs.appendFileSync(outFile, body + '\n', 'utf-8');
62
+ res.writeHead(200, { 'Content-Type': 'application/json' });
63
+ res.end(JSON.stringify({ ok: true }));
64
+ }
65
+ catch (e) {
66
+ res.writeHead(500);
67
+ res.end();
68
+ }
69
+ });
70
+ }
71
+ else {
72
+ res.writeHead(404);
73
+ res.end();
74
+ }
75
+ });
76
+ server.listen(parseInt(portStr, 10), '127.0.0.1', () => {
77
+ const address = server.address();
78
+ const port = address.port;
79
+ fs.writeFileSync(stateFile, JSON.stringify({
80
+ pid: process.pid,
81
+ session: sessionId,
82
+ port: port
83
+ }, null, 2));
84
+ // Cleanup on exit
85
+ const cleanup = () => {
86
+ if (fs.existsSync(stateFile)) {
87
+ fs.unlinkSync(stateFile);
88
+ }
89
+ process.exit();
90
+ };
91
+ process.on('SIGINT', cleanup);
92
+ process.on('SIGTERM', cleanup);
93
+ });
94
+ }
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.start = start;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const crypto = __importStar(require("crypto"));
40
+ const child_process_1 = require("child_process");
41
+ function start() {
42
+ const cwd = process.cwd();
43
+ const debughubDir = path.join(cwd, '.debughub');
44
+ const stateFile = path.join(debughubDir, 'state.json');
45
+ if (!fs.existsSync(debughubDir)) {
46
+ console.error('Error: .debughub directory not found. Did you run `debughub install`?');
47
+ process.exit(1);
48
+ }
49
+ // Check if already running
50
+ if (fs.existsSync(stateFile)) {
51
+ let state = null;
52
+ try {
53
+ state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
54
+ }
55
+ catch (e) { }
56
+ if (state?.pid) {
57
+ let isRunning = false;
58
+ try {
59
+ process.kill(state.pid, 0); // test if running
60
+ isRunning = true;
61
+ }
62
+ catch (e) {
63
+ // Process not actually running, clear state
64
+ fs.unlinkSync(stateFile);
65
+ }
66
+ if (isRunning) {
67
+ console.error(`Collector is already running with PID ${state.pid} (Session: ${state.session})`);
68
+ console.error(`Run \`debughub stop\` to stop it first.`);
69
+ process.exit(1);
70
+ }
71
+ }
72
+ }
73
+ const sessionId = crypto.randomUUID();
74
+ const outDir = path.join(debughubDir, 'out');
75
+ fs.mkdirSync(outDir, { recursive: true });
76
+ const port = process.env.DEBUGHUB_PORT ? parseInt(process.env.DEBUGHUB_PORT, 10) : 0; // 0 means pick random
77
+ // Spawn the server in detached mode
78
+ const cliPath = path.resolve(__dirname, '..', 'cli.js');
79
+ const outLog = fs.openSync(path.join(debughubDir, 'server.log'), 'a');
80
+ const errLog = fs.openSync(path.join(debughubDir, 'error.log'), 'a');
81
+ const child = (0, child_process_1.spawn)(process.execPath, [cliPath, '_server', sessionId, port.toString()], {
82
+ detached: true,
83
+ stdio: ['ignore', outLog, errLog]
84
+ });
85
+ child.unref();
86
+ // We need to wait a tiny bit to read the port from state file that the child writes,
87
+ // or the child can write it and we just tell the user to check `.debughub/state.json`.
88
+ // To be user-friendly, let's wait up to 2 seconds for state.json to appear with our sessionId
89
+ let attempts = 0;
90
+ let finalPort = port;
91
+ while (attempts < 20) {
92
+ if (fs.existsSync(stateFile)) {
93
+ try {
94
+ const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
95
+ if (state.session === sessionId && state.port) {
96
+ finalPort = state.port;
97
+ break;
98
+ }
99
+ }
100
+ catch (e) { }
101
+ }
102
+ // sleep
103
+ const startTm = Date.now();
104
+ while (Date.now() - startTm < 100) {
105
+ // intentional busy-wait to keep implementation synchronous
106
+ }
107
+ attempts++;
108
+ }
109
+ if (finalPort === 0) {
110
+ console.log("Started collector but couldn't confirm port. Check .debughub/state.json");
111
+ // Fallback display
112
+ }
113
+ else {
114
+ console.log(`\nDebugHub Collector Started!`);
115
+ console.log(`Session ID : ${sessionId}`);
116
+ console.log(`Endpoint : http://127.0.0.1:${finalPort}/event`);
117
+ console.log(`Output File : .debughub/out/${sessionId}.jsonl`);
118
+ console.log(`\nEnvironment variables to set:`);
119
+ console.log(` DEBUGHUB_ENABLED=1`);
120
+ console.log(` DEBUGHUB_SESSION=${sessionId}`);
121
+ console.log(` DEBUGHUB_ENDPOINT=http://127.0.0.1:${finalPort}\n`);
122
+ }
123
+ }