@iosifnicolae22/remote-shell
Version:
Run any terminal application and control it remotely from your mobile device. Perfect for maxing out vibe coding sessions with Claude Code on the go!
2 lines (1 loc) • 3.39 kB
JavaScript
;var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s);var r=Object.getOwnPropertyDescriptor(t,s);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[s]}}),Object.defineProperty(e,n,r)}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),__importStar=this&&this.__importStar||function(){var e=function(t){return e=Object.getOwnPropertyNames||function(e){var t=[];for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&(t[t.length]=s);return t},e(t)};return function(t){if(t&&t.__esModule)return t;var s={};if(null!=t)for(var n=e(t),r=0;r<n.length;r++)"default"!==n[r]&&__createBinding(s,t,n[r]);return __setModuleDefault(s,t),s}}();Object.defineProperty(exports,"__esModule",{value:!0}),exports.WebSocketServer=void 0;const ws_1=__importStar(require("ws")),http_1=require("http");class WebSocketServer{wss=null;httpServer;sessions=new Map;authenticatedClients=new Map;port=3001;constructor(){this.httpServer=(0,http_1.createServer)((e,t)=>{"/"===e.url?(t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({status:"ok",service:"Claude Mobile Server",connected:this.authenticatedClients.size}))):(t.writeHead(404),t.end("Not Found"))})}async start(){this.wss=new ws_1.WebSocketServer({server:this.httpServer}),this.wss.on("connection",e=>{e.on("message",t=>{try{const s=JSON.parse(t.toString());this.handleMessage(e,s)}catch(t){this.sendError(e,"Invalid message format")}}),e.on("close",()=>{this.authenticatedClients.delete(e)}),e.on("error",()=>{this.authenticatedClients.delete(e)})}),this.httpServer.listen(this.port,()=>{})}handleMessage(e,t){switch(t.type){case"auth":this.handleAuth(e,t);break;case"input":this.handleInput(e,t);break;case"resize":this.handleResize(e,t);break;default:this.sendError(e,`Unknown message type: ${t.type}`)}}handleAuth(e,t){const s=this.sessions.get(t.token);if(!s||s.used)return this.sendError(e,"Invalid or expired token"),void e.close();s.used=!0,s.lastActivity=new Date,this.authenticatedClients.set(e,s),e.send(JSON.stringify({type:"auth",data:"authenticated"}))}handleInput(e,t){const s=this.authenticatedClients.get(e);s?(s.lastActivity=new Date,this.onInput?.(t.data)):this.sendError(e,"Not authenticated")}handleResize(e,t){const s=this.authenticatedClients.get(e);s?(s.lastActivity=new Date,this.onResize?.(t.cols,t.rows)):this.sendError(e,"Not authenticated")}sendError(e,t){e.send(JSON.stringify({type:"error",data:t}))}createSession(e){const t={id:this.generateSessionId(),token:e,connected:new Date,lastActivity:new Date,used:!1};return this.sessions.set(e,t),setTimeout(()=>{this.sessions.delete(e)},864e5),t}broadcastOutput(e){const t=JSON.stringify({type:"output",data:e,timestamp:Date.now()});this.authenticatedClients.forEach((e,s)=>{s.readyState===ws_1.default.OPEN&&s.send(t)})}broadcastBeep(){const e=JSON.stringify({type:"beep",timestamp:Date.now()});this.authenticatedClients.forEach((t,s)=>{s.readyState===ws_1.default.OPEN&&s.send(e)})}getConnectedDevices(){return Array.from(this.authenticatedClients.values())}generateSessionId(){return Math.random().toString(36).substring(2,15)}onInput;onResize}exports.WebSocketServer=WebSocketServer;