UNPKG

vibetunnel

Version:

Terminal sharing server with web interface - supports macOS, Linux, and headless environments

130 lines 14.2 kB
"use strict"; /** * Fish Shell Handler * * Provides fish shell tab completion support. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.fishHandler = exports.FishHandler = void 0; const child_process_1 = require("child_process"); const path_1 = __importDefault(require("path")); /** * FishHandler - Provides intelligent tab completion support for the Fish shell * * This class integrates with Fish shell's built-in completion system to provide * context-aware command and argument suggestions. It handles the complexity of * spawning Fish processes, managing timeouts, and parsing completion results. * * Key features: * - Leverages Fish's powerful built-in completion engine * - Handles process timeouts to prevent hanging * - Safely escapes input to prevent injection attacks * - Parses Fish's tab-separated completion format * - Provides shell detection and version checking utilities * * @example * ```typescript * import { fishHandler } from './fish-handler'; * * // Get completions for a partial command * const completions = await fishHandler.getCompletions('git co', '/home/user/project'); * // Returns: ['commit', 'config', 'checkout', ...] * * // Check if a shell path is Fish * if (FishHandler.isFishShell('/usr/local/bin/fish')) { * // Use Fish-specific features * const version = await FishHandler.getFishVersion(); * console.log(`Fish version: ${version}`); * } * ``` */ class FishHandler { /** * Get completion suggestions for a partial command */ async getCompletions(partial, cwd = process.cwd()) { return new Promise((resolve) => { try { // Use fish's built-in completion system with proper escaping const fishProcess = (0, child_process_1.spawn)('fish', ['-c', `complete -C ${JSON.stringify(partial)}`], { cwd, stdio: ['ignore', 'pipe', 'ignore'], }); let stdout = ''; const timeout = setTimeout(() => { fishProcess.kill('SIGTERM'); resolve([]); }, 2000); fishProcess.stdout?.on('data', (data) => { stdout += data.toString(); }); fishProcess.on('close', (code) => { clearTimeout(timeout); if (code !== 0 || !stdout.trim()) { resolve([]); return; } const completions = stdout .split('\n') .filter((line) => line.trim()) .map((line) => line.split('\t')[0]) // Fish completions are tab-separated .filter((completion) => completion && completion !== partial); resolve(completions); }); fishProcess.on('error', () => { clearTimeout(timeout); resolve([]); }); } catch (_error) { resolve([]); } }); } /** * Check if the current shell is fish */ static isFishShell(shellPath) { const basename = path_1.default.basename(shellPath); // Exact match for fish or fish with version suffix (e.g., fish3) return basename === 'fish' || /^fish\d*$/.test(basename); } /** * Get fish shell version */ static async getFishVersion() { return new Promise((resolve) => { try { const fishProcess = (0, child_process_1.spawn)('fish', ['--version'], { stdio: ['ignore', 'pipe', 'ignore'], }); let stdout = ''; const timeout = setTimeout(() => { fishProcess.kill('SIGTERM'); resolve(null); }, 1000); fishProcess.stdout?.on('data', (data) => { stdout += data.toString(); }); fishProcess.on('close', (code) => { clearTimeout(timeout); resolve(code === 0 && stdout.trim() ? stdout.trim() : null); }); fishProcess.on('error', () => { clearTimeout(timeout); resolve(null); }); } catch { resolve(null); } }); } } exports.FishHandler = FishHandler; // Export singleton instance exports.fishHandler = new FishHandler(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlzaC1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZlci9wdHkvZmlzaC1oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7OztHQUlHOzs7Ozs7QUFFSCxpREFBc0M7QUFDdEMsZ0RBQXdCO0FBRXhCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTZCRztBQUNILE1BQWEsV0FBVztJQUN0Qjs7T0FFRztJQUNILEtBQUssQ0FBQyxjQUFjLENBQUMsT0FBZSxFQUFFLE1BQWMsT0FBTyxDQUFDLEdBQUcsRUFBRTtRQUMvRCxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDN0IsSUFBSSxDQUFDO2dCQUNILDZEQUE2RDtnQkFDN0QsTUFBTSxXQUFXLEdBQUcsSUFBQSxxQkFBSyxFQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxlQUFlLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFO29CQUNsRixHQUFHO29CQUNILEtBQUssRUFBRSxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsUUFBUSxDQUFDO2lCQUNwQyxDQUFDLENBQUM7Z0JBRUgsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFDO2dCQUNoQixNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO29CQUM5QixXQUFXLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUM1QixPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQ2QsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUVULFdBQVcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFO29CQUN0QyxNQUFNLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUM1QixDQUFDLENBQUMsQ0FBQztnQkFFSCxXQUFXLENBQUMsRUFBRSxD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WUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO29CQUN0QixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2hCLENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUFDLE1BQU0sQ0FBQztnQkFDUCxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDaEIsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBN0ZELGtDQTZGQztBQUVELDRCQUE0QjtBQUNmLFFBQUEsV0FBVyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEZpc2ggU2hlbGwgSGFuZGxlclxuICpcbiAqIFByb3ZpZGVzIGZpc2ggc2hlbGwgdGFiIGNvbXBsZXRpb24gc3VwcG9ydC5cbiAqL1xuXG5pbXBvcnQgeyBzcGF3biB9IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5cbi8qKlxuICogRmlzaEhhbmRsZXIgLSBQcm92aWRlcyBpbnRlbGxpZ2VudCB0YWIgY29tcGxldGlvbiBzdXBwb3J0IGZvciB0aGUgRmlzaCBzaGVsbFxuICpcbiAqIFRoaXMgY2xhc3MgaW50ZWdyYXRlcyB3aXRoIEZpc2ggc2hlbGwncyBidWlsdC1pbiBjb21wbGV0aW9uIHN5c3RlbSB0byBwcm92aWRlXG4gKiBjb250ZXh0LWF3YXJlIGNvbW1hbmQgYW5kIGFyZ3VtZW50IHN1Z2dlc3Rpb25zLiBJdCBoYW5kbGVzIHRoZSBjb21wbGV4aXR5IG9mXG4gKiBzcGF3bmluZyBGaXNoIHByb2Nlc3NlcywgbWFuYWdpbmcgdGltZW91dHMsIGFuZCBwYXJzaW5nIGNvbXBsZXRpb24gcmVzdWx0cy5cbiAqXG4gKiBLZXkgZmVhdHVyZXM6XG4gKiAtIExldmVyYWdlcyBGaXNoJ3MgcG93ZXJmdWwgYnVpbHQtaW4gY29tcGxldGlvbiBlbmdpbmVcbiAqIC0gSGFuZGxlcyBwcm9jZXNzIHRpbWVvdXRzIHRvIHByZXZlbnQgaGFuZ2luZ1xuICogLSBTYWZlbHkgZXNjYXBlcyBpbnB1dCB0byBwcmV2ZW50IGluamVjdGlvbiBhdHRhY2tzXG4gKiAtIFBhcnNlcyBGaXNoJ3MgdGFiLXNlcGFyYXRlZCBjb21wbGV0aW9uIGZvcm1hdFxuICogLSBQcm92aWRlcyBzaGVsbCBkZXRlY3Rpb24gYW5kIHZlcnNpb24gY2hlY2tpbmcgdXRpbGl0aWVzXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGZpc2hIYW5kbGVyIH0gZnJvbSAnLi9maXNoLWhhbmRsZXInO1xuICpcbiAqIC8vIEdldCBjb21wbGV0aW9ucyBmb3IgYSBwYXJ0aWFsIGNvbW1hbmRcbiAqIGNvbnN0IGNvbXBsZXRpb25zID0gYXdhaXQgZmlzaEhhbmRsZXIuZ2V0Q29tcGxldGlvbnMoJ2dpdCBjbycsICcvaG9tZS91c2VyL3Byb2plY3QnKTtcbiAqIC8vIFJldHVybnM6IFsnY29tbWl0JywgJ2NvbmZpZycsICdjaGVja291dCcsIC4uLl1cbiAqXG4gKiAvLyBDaGVjayBpZiBhIHNoZWxsIHBhdGggaXMgRmlzaFxuICogaWYgKEZpc2hIYW5kbGVyLmlzRmlzaFNoZWxsKCcvdXNyL2xvY2FsL2Jpbi9maXNoJykpIHtcbiAqICAgLy8gVXNlIEZpc2gtc3BlY2lmaWMgZmVhdHVyZXNcbiAqICAgY29uc3QgdmVyc2lvbiA9IGF3YWl0IEZpc2hIYW5kbGVyLmdldEZpc2hWZXJzaW9uKCk7XG4gKiAgIGNvbnNvbGUubG9nKGBGaXNoIHZlcnNpb246ICR7dmVyc2lvbn1gKTtcbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgRmlzaEhhbmRsZXIge1xuICAvKipcbiAgICogR2V0IGNvbXBsZXRpb24gc3VnZ2VzdGlvbnMgZm9yIGEgcGFydGlhbCBjb21tYW5kXG4gICAqL1xuICBhc3luYyBnZXRDb21wbGV0aW9ucyhwYXJ0aWFsOiBzdHJpbmcsIGN3ZDogc3RyaW5nID0gcHJvY2Vzcy5jd2QoKSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIFVzZSBmaXNoJ3MgYnVpbHQtaW4gY29tcGxldGlvbiBzeXN0ZW0gd2l0aCBwcm9wZXIgZXNjYXBpbmdcbiAgICAgICAgY29uc3QgZmlzaFByb2Nlc3MgPSBzcGF3bignZmlzaCcsIFsnLWMnLCBgY29tcGxldGUgLUMgJHtKU09OLnN0cmluZ2lmeShwYXJ0aWFsKX1gXSwge1xuICAgICAgICAgIGN3ZCxcbiAgICAgICAgICBzdGRpbzogWydpZ25vcmUnLCAncGlwZScsICdpZ25vcmUnXSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgbGV0IHN0ZG91dCA9ICcnO1xuICAgICAgICBjb25zdCB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgZmlzaFByb2Nlc3Mua2lsbCgnU0lHVEVSTScpO1xuICAgICAgICAgIHJlc29sdmUoW10pO1xuICAgICAgICB9LCAyMDAwKTtcblxuICAgICAgICBmaXNoUHJvY2Vzcy5zdGRvdXQ/Lm9uKCdkYXRhJywgKGRhdGEpID0+IHtcbiAgICAgICAgICBzdGRvdXQgKz0gZGF0YS50b1N0cmluZygpO1xuICAgICAgICB9KTtcblxuICAgICAgICBmaXNoUHJvY2Vzcy5vbignY2xvc2UnLCAoY29kZSkgPT4ge1xuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcblxuICAgICAgICAgIGlmIChjb2RlICE9PSAwIHx8ICFzdGRvdXQudHJpbSgpKSB7XG4gICAgICAgICAgICByZXNvbHZlKFtdKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBjb21wbGV0aW9ucyA9IHN0ZG91dFxuICAgICAgICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgICAgICAgLmZpbHRlcigobGluZSkgPT4gbGluZS50cmltKCkpXG4gICAgICAgICAgICAubWFwKChsaW5lKSA9PiBsaW5lLnNwbGl0KCdcXHQnKVswXSkgLy8gRmlzaCBjb21wbGV0aW9ucyBhcmUgdGFiLXNlcGFyYXRlZFxuICAgICAgICAgICAgLmZpbHRlcigoY29tcGxldGlvbikgPT4gY29tcGxldGlvbiAmJiBjb21wbGV0aW9uICE9PSBwYXJ0aWFsKTtcblxuICAgICAgICAgIHJlc29sdmUoY29tcGxldGlvbnMpO1xuICAgICAgICB9KTtcblxuICAgICAgICBmaXNoUHJvY2Vzcy5vbignZXJyb3InLCAoKSA9PiB7XG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICAgIHJlc29sdmUoW10pO1xuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKF9lcnJvcikge1xuICAgICAgICByZXNvbHZlKFtdKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiB0aGUgY3VycmVudCBzaGVsbCBpcyBmaXNoXG4gICAqL1xuICBzdGF0aWMgaXNGaXNoU2hlbGwoc2hlbGxQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBiYXNlbmFtZSA9IHBhdGguYmFzZW5hbWUoc2hlbGxQYXRoKTtcbiAgICAvLyBFeGFjdCBtYXRjaCBmb3IgZmlzaCBvciBmaXNoIHdpdGggdmVyc2lvbiBzdWZmaXggKGUuZy4sIGZpc2gzKVxuICAgIHJldHVybiBiYXNlbmFtZSA9PT0gJ2Zpc2gnIHx8IC9eZmlzaFxcZCokLy50ZXN0KGJhc2VuYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZmlzaCBzaGVsbCB2ZXJzaW9uXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0RmlzaFZlcnNpb24oKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBmaXNoUHJvY2VzcyA9IHNwYXduKCdmaXNoJywgWyctLXZlcnNpb24nXSwge1xuICAgICAgICAgIHN0ZGlvOiBbJ2lnbm9yZScsICdwaXBlJywgJ2lnbm9yZSddLFxuICAgICAgICB9KTtcblxuICAgICAgICBsZXQgc3Rkb3V0ID0gJyc7XG4gICAgICAgIGNvbnN0IHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICBmaXNoUHJvY2Vzcy5raWxsKCdTSUdURVJNJyk7XG4gICAgICAgICAgcmVzb2x2ZShudWxsKTtcbiAgICAgICAgfSwgMTAwMCk7XG5cbiAgICAgICAgZmlzaFByb2Nlc3Muc3Rkb3V0Py5vbignZGF0YScsIChkYXRhKSA9PiB7XG4gICAgICAgICAgc3Rkb3V0ICs9IGRhdGEudG9TdHJpbmcoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZmlzaFByb2Nlc3Mub24oJ2Nsb3NlJywgKGNvZGUpID0+IHtcbiAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgICAgcmVzb2x2ZShjb2RlID09PSAwICYmIHN0ZG91dC50cmltKCkgPyBzdGRvdXQudHJpbSgpIDogbnVsbCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGZpc2hQcm9jZXNzLm9uKCdlcnJvcicsICgpID0+IHtcbiAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgICAgcmVzb2x2ZShudWxsKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmVzb2x2ZShudWxsKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxufVxuXG4vLyBFeHBvcnQgc2luZ2xldG9uIGluc3RhbmNlXG5leHBvcnQgY29uc3QgZmlzaEhhbmRsZXIgPSBuZXcgRmlzaEhhbmRsZXIoKTtcbiJdfQ==