{"version":3,"sources":["/home/x/core/projects/battle/dist/Ruspty-7DYBLOSB.cjs","../src/PTY/Ruspty.ts"],"names":[],"mappings":"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","file":"/home/x/core/projects/battle/dist/Ruspty-7DYBLOSB.cjs","sourcesContent":[null,"/**\n * Rust-based PTY implementation using @akaoio/ruspty\n * Provides real PTY support for Bun runtime with ARM64 support\n * Creates actual pseudo-terminals with full terminal emulation\n */\n\nimport type { IPTY, PTYOptions } from './index.js'\nimport { SecureErrorHandler, ResourceLimiter } from '../security/index.js'\n\n// Dynamic import to avoid loading in Node.js runtime\nlet Pty: any\n\nexport class Ruspty implements IPTY {\n    private pty: any\n    private fd: number | undefined  // Store file descriptor for Bun\n    private _killed: boolean = false\n    private _pid: number | undefined\n    private dataCallbacks: Array<(data: string) => void> = []\n    private exitCallbacks: Array<(code: number) => void> = []\n    private isBun: boolean = typeof (globalThis as any).Bun !== 'undefined'\n    \n    constructor(command: string, args: string[], options: PTYOptions) {\n        // Check PTY resource limits\n        if (!ResourceLimiter.acquirePTY()) {\n            throw new Error('PTY instance limit exceeded - too many active PTYs')\n        }\n        \n        // Lazy load ruspty - intelligent platform selection\n        if (!Pty) {\n            try {\n                // Try @akaoio/ruspty first (has ARM64 support)\n                let ruspty\n                try {\n                    ruspty = this.isBun ? require('@akaoio/ruspty/index.js') : require('@akaoio/ruspty')\n                    Pty = ruspty.Pty\n                } catch (akaoError) {\n                    // Fallback to @replit/ruspty for x64 platforms\n                    try {\n                        ruspty = this.isBun ? require('@replit/ruspty/index.js') : require('@replit/ruspty')\n                        Pty = ruspty.Pty\n                    } catch (replitError) {\n                        // Both failed - throw comprehensive error\n                        throw new Error(\n                            'No compatible ruspty package found.\\n' +\n                            'Install one of:\\n' +\n                            '- npm install @akaoio/ruspty (ARM64 support)\\n' +\n                            '- npm install @replit/ruspty (x64 support)\\n' +\n                            `@akaoio error: ${akaoError.message}\\n` +\n                            `@replit error: ${replitError.message}`\n                        )\n                    }\n                }\n            } catch (err: any) {\n                ResourceLimiter.releasePTY()\n                const sanitizedError = SecureErrorHandler.sanitize(err)\n                throw new Error(\n                    'Ruspty is not installed or failed to load.\\n' +\n                    'Run: npm install @akaoio/ruspty (or @replit/ruspty for x64)\\n' +\n                    `Error: ${sanitizedError}`\n                )\n            }\n        }\n        \n        // Create real PTY with ruspty\n        try {\n            if (this.isBun) {\n                // Bun: Use raw Pty API with 'envs' instead of 'env'\n                this.pty = new Pty({\n                    command,\n                    args: args || [],\n                    envs: {  // Note: raw API uses 'envs'\n                        ...process.env,\n                        ...options.env,\n                        TERM: options.name || 'xterm-256color',\n                        FORCE_COLOR: '1',\n                        COLORTERM: 'truecolor'\n                    },\n                    size: {\n                        rows: options.rows || 24,\n                        cols: options.cols || 80\n                    },\n                    onExit: (err: any, exitCode: number) => {\n                        this._killed = true\n                        // Ensure we always have a valid exit code\n                        const code = exitCode ?? (err ? 1 : 0)\n                        this.exitCallbacks.forEach(cb => {\n                            try {\n                                cb(code)\n                            } catch (callbackError) {\n                                SecureErrorHandler.log(callbackError, 'Exit callback error')\n                            }\n                        })\n                        // Release PTY resource\n                        ResourceLimiter.releasePTY()\n                    }\n                })\n            } else {\n                // Node: Use wrapper API\n                this.pty = new Pty({\n                    command,\n                    args: args || [],\n                    env: {  // Note: wrapper API uses 'env'\n                        ...process.env,\n                        ...options.env,\n                        TERM: options.name || 'xterm-256color',\n                        FORCE_COLOR: '1',\n                        COLORTERM: 'truecolor'\n                    },\n                    size: {\n                        rows: options.rows || 24,\n                        cols: options.cols || 80\n                    },\n                    onExit: (err: any, exitCode: number) => {\n                        this._killed = true\n                        // Ensure we always have a valid exit code\n                        const code = exitCode ?? (err ? 1 : 0)\n                        this.exitCallbacks.forEach(cb => {\n                            try {\n                                cb(code)\n                            } catch (callbackError) {\n                                SecureErrorHandler.log(callbackError, 'Exit callback error')\n                            }\n                        })\n                        // Release PTY resource\n                        ResourceLimiter.releasePTY()\n                    }\n                })\n            }\n            \n            this._pid = this.pty.pid\n            \n            // Set up data streaming\n            this.setupDataStream()\n        } catch (err: any) {\n            ResourceLimiter.releasePTY()\n            const sanitizedError = SecureErrorHandler.sanitize(err)\n            throw new Error(`Failed to create PTY: ${sanitizedError}`)\n        }\n    }\n    \n    private setupDataStream() {\n        try {\n            if (this.isBun) {\n                // Bun: Use fs.readSync with raw Pty API (tty.ReadStream doesn't work)\n                this.fd = this.pty.takeFd()\n                const fs = require('fs')\n                \n                let pollTimeout: NodeJS.Timeout | null = null\n                \n                const checkOutput = () => {\n                    if (this._killed) {\n                        // Clean up on exit\n                        if (pollTimeout) {\n                            clearTimeout(pollTimeout)\n                            pollTimeout = null\n                        }\n                        // Close file descriptor if still open\n                        this.cleanupFileDescriptor()\n                        return\n                    }\n                    \n                    try {\n                        // Use fs.readSync which works in Bun\n                        const buffer = Buffer.alloc(4096)\n                        const bytesRead = fs.readSync(this.fd!, buffer, 0, 4096, null)\n                        if (bytesRead > 0) {\n                            const text = buffer.slice(0, bytesRead).toString()\n                            this.dataCallbacks.forEach(cb => {\n                                try {\n                                    cb(text)\n                                } catch (callbackError) {\n                                    // Prevent callback errors from killing the polling loop\n                                    console.error('Data callback error:', callbackError)\n                                }\n                            })\n                        }\n                    } catch (err: any) {\n                        // EAGAIN means no data available yet - that's normal\n                        if (err.code !== 'EAGAIN' && err.code !== 'EWOULDBLOCK') {\n                            // Only log real errors\n                            if (err.code === 'EBADF' || err.code === 'EIO') {\n                                // PTY closed - cleanup\n                                this._killed = true\n                                this.cleanupFileDescriptor()\n                                return\n                            } else {\n                                // Unexpected error - log and cleanup to prevent fd leak\n                                console.error('Unexpected PTY read error:', err)\n                                this._killed = true\n                                this.cleanupFileDescriptor()\n                                return\n                            }\n                        }\n                    }\n                    \n                    // Continue polling if not killed - reduced frequency for better performance\n                    if (!this._killed) {\n                        pollTimeout = setTimeout(checkOutput, 50)  // Reduced from 10ms to 50ms\n                    }\n                }\n                \n                // Start polling immediately\n                setTimeout(checkOutput, 0)\n            } else {\n                // Node: Use the wrapper's stream interface\n                const stream = this.pty.read\n                \n                if (stream && typeof stream.on === 'function') {\n                    stream.on('data', (data: Buffer) => {\n                        const text = data.toString()\n                        this.dataCallbacks.forEach(cb => cb(text))\n                    })\n                    \n                    stream.on('error', (err: any) => {\n                        if (err.code === 'EIO') {\n                            // EIO means the PTY has closed\n                            stream.emit('end')\n                        } else {\n                            console.error('PTY stream error:', err)\n                        }\n                    })\n                    \n                    stream.on('end', () => {\n                        this._killed = true\n                    })\n                } else {\n                    throw new Error('Stream interface not available')\n                }\n            }\n        } catch (err) {\n            console.error('Failed to setup data stream:', err)\n            if (!this._killed) {\n                this._killed = true\n                this.exitCallbacks.forEach(cb => cb(1))\n            }\n        }\n    }\n    \n    onData(callback: (data: string) => void): void {\n        this.dataCallbacks.push(callback)\n    }\n    \n    onExit(callback: (code: number) => void): void {\n        this.exitCallbacks.push(callback)\n        \n        // If already exited, call immediately\n        if (this._killed) {\n            callback(0)\n        }\n    }\n    \n    write(data: string): void {\n        if (!this._killed) {\n            try {\n                if (this.isBun && this.fd !== undefined) {\n                    // Bun: Write directly to file descriptor\n                    const fs = require('fs')\n                    fs.writeSync(this.fd, data)\n                } else if (this.pty) {\n                    // Node: Use wrapper's write stream\n                    this.pty.write.write(data)\n                }\n            } catch (err) {\n                // PTY might have closed\n                console.error('Write error:', err)\n            }\n        }\n    }\n    \n    resize(cols: number, rows: number): void {\n        if (!this._killed && this.pty && this.pty.resize) {\n            try {\n                this.pty.resize({ cols, rows })\n            } catch (err) {\n                // Resize might not be supported or PTY closed\n            }\n        }\n    }\n    \n    kill(signal?: string): void {\n        if (!this._killed && this.pty) {\n            try {\n                // ruspty uses kill() method\n                if (this.pty.kill) {\n                    this.pty.kill()\n                }\n                this._killed = true\n                \n                // Clean up file descriptor\n                this.cleanupFileDescriptor()\n            } catch (err) {\n                // Process might already be dead - ensure cleanup still happens\n                this._killed = true\n                this.cleanupFileDescriptor()\n            }\n        }\n    }\n    \n    /**\n     * Safely cleans up file descriptor to prevent leaks\n     */\n    private cleanupFileDescriptor(): void {\n        if (this.isBun && this.fd !== undefined) {\n            try {\n                const fs = require('fs')\n                fs.closeSync(this.fd)\n            } catch (e) {\n                // Ignore close errors - fd might already be closed\n            } finally {\n                this.fd = undefined\n            }\n        }\n    }\n    \n    get pid(): number | undefined {\n        return this._pid\n    }\n    \n    get killed(): boolean {\n        return this._killed\n    }\n}\n\nexport default Ruspty"]}