import{n as e,t}from"./defineProperty-80gRi2ZW.js";import{Jt as n,on as r}from"./paths-Ci1iwL5Y.js";import{D as i,E as a,O as o,l as s,p as c}from"./debug-otxXY3j-.js";import{l,u}from"./oauth-CdZEzMww.js";import{i as d,t as f}from"./cliLaunch-Citfs01Q.js";import{resolve as p}from"path";import{existsSync as m,unlinkSync as h}from"fs";import{randomUUID as g}from"crypto";s(),a(),e();function _(e){return typeof e==`object`&&!!e&&`type`in e&&typeof e.type==`string`}var v=2e3,y=15e3,b=3,x=class{constructor(e,n){t(this,`proc`,void 0),t(this,`options`,void 0),t(this,`connected`,!1),t(this,`disconnected`,!1),t(this,`readLoopAbort`,null),t(this,`reconnectAttempt`,0),t(this,`maxReconnectAttempts`,void 0),t(this,`userInitiatedDisconnect`,!1),t(this,`reconnecting`,!1),this.proc=e,this.options=n,this.maxReconnectAttempts=n.maxReconnectAttempts??b}connect(){this.connected||(this.readLoopAbort=new AbortController,this.startReadLoop(),this.monitorExit(),this.connected=!0,this.options.onConnected())}async startReadLoop(){let e=this.proc.stdout;if(!e){this.options.onError(Error(`SSH process stdout is not available`));return}let t=e.getReader(),n=new TextDecoder,r=``;try{for(;!this.disconnected;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.split(`
`);r=a.pop()??``;for(let e of a){let t=e.trim();t&&this.processLine(t)}}}catch(e){this.disconnected||this.options.onError(e instanceof Error?e:Error(String(e)))}finally{t.releaseLock(),!this.disconnected&&!this.userInitiatedDisconnect&&this.handleProcessExit()}}monitorExit(){if(this.proc.exitCode!==null){this.userInitiatedDisconnect||this.handleProcessExit();return}this.proc.exited.then(()=>{!this.disconnected&&!this.userInitiatedDisconnect&&this.handleProcessExit()}).catch(()=>{!this.disconnected&&!this.userInitiatedDisconnect&&this.handleProcessExit()})}async handleProcessExit(){if(!(this.disconnected||this.reconnecting)){if(this.connected=!1,!this.options.reconnect){this.disconnected=!0,this.options.onDisconnected();return}if(this.reconnectAttempt>=this.maxReconnectAttempts){this.disconnected=!0,this.options.onDisconnected();return}this.reconnecting=!0;try{await this.attemptReconnect()}finally{this.reconnecting=!1}}}async attemptReconnect(){let e=this.options.reconnect;for(;this.reconnectAttempt<this.maxReconnectAttempts;){this.reconnectAttempt++,this.options.onReconnecting(this.reconnectAttempt,this.maxReconnectAttempts);let t=Math.min(v*2**(this.reconnectAttempt-1),y);if(await new Promise(e=>setTimeout(e,t)),this.userInitiatedDisconnect)return;try{this.proc=await e(),this.reconnectAttempt=0,this.connected=!0,this.startReadLoop(),this.monitorExit(),this.options.onConnected();return}catch(e){c(`[SSH] reconnect attempt ${this.reconnectAttempt} failed: ${e instanceof Error?e.message:String(e)}`)}}this.disconnected=!0,this.options.onDisconnected()}processLine(e){let t;try{t=i(e)}catch{return}if(!_(t))return;let n=t;if(n.type===`control_request`){let e=n;e.request.subtype===`can_use_tool`?this.options.onPermissionRequest(e.request,e.request_id):(c(`[SSH] Unsupported control request subtype: ${e.request.subtype}`),this.sendErrorResponse(e.request_id,`Unsupported control request subtype: ${e.request.subtype}`));return}n.type!==`control_response`&&n.type!==`keep_alive`&&n.type!==`control_cancel_request`&&n.type!==`streamlined_text`&&n.type!==`streamlined_tool_use_summary`&&!(n.type===`system`&&n.subtype===`post_turn_summary`)&&this.options.onMessage(n)}writeToStdin(e){try{let t=this.proc.stdin;if(!t||typeof t==`number`||this.disconnected)return!1;let n=new TextEncoder().encode(e+`
`);return t.write(n),t.flush?.(),!0}catch{return!1}}async sendMessage(e){let t=o({type:`user`,message:{role:`user`,content:e},parent_tool_use_id:null,session_id:``});return this.writeToStdin(t)}sendInterrupt(){let e=o({type:`control_request`,request_id:crypto.randomUUID(),request:{subtype:`interrupt`}});this.writeToStdin(e)}respondToPermissionRequest(e,t){let n=o({type:`control_response`,response:{subtype:`success`,request_id:e,response:{behavior:t.behavior,...t.behavior===`allow`?{updatedInput:t.updatedInput}:{message:t.message}}}});this.writeToStdin(n)}sendErrorResponse(e,t){let n=o({type:`control_response`,response:{subtype:`error`,request_id:e,error:t}});this.writeToStdin(n)}disconnect(){if(!this.disconnected){this.userInitiatedDisconnect=!0,this.disconnected=!0,this.connected=!1,this.readLoopAbort?.abort();try{let e=this.proc.stdin;e&&typeof e!=`number`&&e.end?.()}catch{}try{this.proc.kill()}catch{}}}isConnected(){return this.connected&&!this.disconnected}};r(),u(),s();var S=process.platform===`win32`;function C(){let e=process.env.ANTHROPIC_API_KEY;if(e)return{"x-api-key":e};let t=n();return t?.accessToken?{Authorization:`Bearer ${t.accessToken}`}:{}}function w(){return process.env.ANTHROPIC_BASE_URL||l().BASE_API_URL}async function T(e,t){if(t&&e.headers.get(`x-auth-nonce`)!==t)return new Response(`Forbidden`,{status:403});let n=w(),r=new URL(e.url),i=`${n}${r.pathname}${r.search}`,a=C();if(Object.keys(a).length===0)return new Response(JSON.stringify({error:`No API credentials available on local machine`}),{status:401,headers:{"content-type":`application/json`}});let o=new Headers(e.headers);for(let[e,t]of Object.entries(a))o.set(e,t);o.delete(`host`),o.delete(`x-auth-nonce`),c(`[SSHAuthProxy] ${e.method} ${r.pathname} -> ${i}`);try{let t=await fetch(i,{method:e.method,headers:o,body:e.body,duplex:`half`}),n=new Headers(t.headers);return n.delete(`content-encoding`),n.delete(`content-length`),new Response(t.body,{status:t.status,statusText:t.statusText,headers:n})}catch(e){let t=e instanceof Error?e.message:String(e);return c(`[SSHAuthProxy] upstream error: ${t}`),new Response(JSON.stringify({error:`Proxy upstream error: ${t}`}),{status:502,headers:{"content-type":`application/json`}})}}async function E(){let e=g();return S?O(e):D(e)}async function D(e){let t=`/tmp/claude-ssh-auth-${e}.sock`,n=Bun.serve({unix:t,fetch:e=>T(e,null)});return c(`[SSHAuthProxy] listening on unix:${t}`),{proxy:{stop(){n.stop(!0);try{h(t)}catch{}}},localAddress:t,authEnv:{ANTHROPIC_AUTH_SOCKET:t}}}async function O(e){let t=g(),n=Bun.serve({port:0,hostname:`127.0.0.1`,fetch:e=>T(e,t)}),r=n.port;return c(`[SSHAuthProxy] listening on TCP 127.0.0.1:${r} (nonce-protected)`),{proxy:{stop(){n.stop(!0)}},localAddress:`127.0.0.1:${r}`,authEnv:{ANTHROPIC_BASE_URL:`http://127.0.0.1:${r}`,ANTHROPIC_AUTH_NONCE:t}}}s();var k=15e3,A=class extends Error{constructor(e){super(e),this.name=`SSHProbeError`}};async function j(e,t){t?.(`Probing remote host…`);let n=Bun.spawn([`ssh`,`-o`,`BatchMode=yes`,`-o`,`ConnectTimeout=10`,e,`CLAUDE_BIN=$(test -x "$HOME/.local/bin/claude" && echo "$HOME/.local/bin/claude" || command -v claude 2>/dev/null); echo "$CLAUDE_BIN"; $CLAUDE_BIN --version 2>/dev/null; uname -sm; pwd`],{stdin:`ignore`,stdout:`pipe`,stderr:`pipe`}),r=await Promise.race([n.exited,new Promise((e,t)=>setTimeout(()=>t(new A(`SSH probe timed out after ${k/1e3}s`)),k))]),i=await new Response(n.stdout).text(),a=await new Response(n.stderr).text();if(r!==0)throw new A(`SSH probe failed: ${a.trim()||`exit code ${r}`}`);let o=i.split(`
`).map(e=>e.trim()).filter(Boolean);c(`[SSHProbe] raw lines: ${JSON.stringify(o)}`);let s=o.findIndex(e=>/^(Linux|Darwin)\s/.test(e));if(s===-1)throw new A(`Could not detect remote platform (uname output missing)`);let l=s>=2&&o[s-2]||null,u=s>=1&&o[s-1]||null,d=u&&/^\d+\.\d+/.test(u)?u:null,f=l!==null&&l.startsWith(`/`),p=o[s+1]||`/`,[m,h]=o[s].split(/\s+/),g=m===`Darwin`?`darwin`:`linux`,_=h===`aarch64`||h===`arm64`?`arm64`:`x64`;return t?.(`Detected ${g}/${_}`),{hasBinary:f&&d!==null,remoteVersion:d,remotePlatform:g,remoteArch:_,defaultCwd:p,binaryPath:f?l:null}}s();var M=6e4,N=`~/.local/bin`,P=`claude-code-cli.js`,F=`claude`;async function I(e,t,n=M){let r=Bun.spawn([`ssh`,`-o`,`ConnectTimeout=10`,e,t],{stdout:`pipe`,stderr:`pipe`}),i=setTimeout(()=>r.kill(),n);try{let[e,t]=await Promise.all([new Response(r.stdout).text(),new Response(r.stderr).text()]),n=await r.exited;return{stdout:e.trim(),stderr:t.trim(),exitCode:n}}finally{clearTimeout(i)}}function L(){let e=p(import.meta.dir,`../..`),t=p(e,`dist/cli.js`);if(m(t))return t;let n=p(e,`src/entrypoints/cli.tsx`);if(m(n))return n;throw Error("Cannot find local CLI binary to deploy. Run `bun run build` first.")}async function R(e){let{host:t,remotePlatform:n,remoteArch:r,localVersion:i,onProgress:a}=e;if(n!==`linux`&&n!==`darwin`)throw Error(`Remote platform "${n}" is not supported. Only linux and darwin are supported.`);c(`[SSHDeploy] deploying to ${t} (${n}/${r}, v${i})`);let o=L();c(`[SSHDeploy] local binary: ${o}`),a?.(`Creating remote directory...`);let s=await I(t,`mkdir -p ${N}`);if(s.exitCode!==0)throw Error(`Failed to create remote directory: ${s.stderr}`);a?.(`Uploading binary...`);let l=`${N}/${P}`,u=Bun.spawn([`scp`,`-o`,`ConnectTimeout=10`,o,`${t}:${l}`],{stdout:`pipe`,stderr:`pipe`}),d=setTimeout(()=>u.kill(),M),f=await new Response(u.stderr).text(),p=await u.exited;if(clearTimeout(d),p!==0)throw Error(`SCP upload failed (exit ${p}): ${f.trim()}`);a?.(`Installing wrapper script...`);let m=await I(t,[`cat > ${N}/${F} << 'WRAPPER'`,`#!/bin/sh`,`exec bun ${N}/${P} "$@"`,`WRAPPER`,`chmod +x ${N}/${F}`].join(`
`));if(m.exitCode!==0)throw Error(`Failed to install wrapper script: ${m.stderr}`);a?.(`Verifying installation...`);let h=await I(t,`${N}/${F} --version`);if(h.exitCode!==0)throw Error(`Binary deployed but verification failed (exit ${h.exitCode}): ${h.stderr}`);return c(`[SSHDeploy] deployed successfully, remote version: ${h.stdout}`),a?.(`Deployed v${h.stdout}`),`${N}/${F}`}d(),s(),a();var z=3e4,B=20,V=class extends Error{constructor(e){super(e),this.name=`SSHSessionError`}};async function H(e,t){let{host:n,localVersion:r,extraCliArgs:i,remoteBin:a}=e,o=t?.onProgress,s,l=`/`;if(a){o?.(`Using custom remote binary, skipping probe/deploy…`),s=a,c(`[SSH] custom remoteBin: ${a}`);try{let e=Bun.spawn([`ssh`,`-o`,`BatchMode=yes`,`-o`,`ConnectTimeout=5`,n,`pwd`],{stdin:`ignore`,stdout:`pipe`,stderr:`ignore`});await e.exited;let t=(await new Response(e.stdout).text()).trim();t.startsWith(`/`)&&(l=t)}catch{}}else{let e=await j(n,o);c(`[SSH] probe result: ${JSON.stringify(e)}`),l=e.defaultCwd,s=e.binaryPath??`~/.local/bin/claude`,(!e.hasBinary||e.remoteVersion!==r)&&(o?.(e.hasBinary?`Updating remote binary (${e.remoteVersion} → ${r})…`:`Deploying binary to remote…`),s=await R({host:n,remotePlatform:e.remotePlatform,remoteArch:e.remoteArch,localVersion:r,onProgress:o}))}let{proxy:u,localAddress:d,authEnv:f}=await E();c(`[SSH] auth proxy listening on ${d}`);let p=g().slice(0,8),m=process.platform===`win32`,h=[];for(let[e,t]of Object.entries(f))h.push(`${e}=${t}`);h.push(s,`--output-format`,`stream-json`,`--input-format`,`stream-json`,`--verbose`,`-p`),e.cwd&&h.push(`--cwd`,e.cwd),e.permissionMode&&h.push(`--permission-mode`,e.permissionMode),e.dangerouslySkipPermissions&&h.push(`--dangerously-skip-permissions`),h.push(...i);let _=[`ssh`];if(m){let e=d.split(`:`)[1],t=1e4+Math.floor(Math.random()*5e4);_.push(`-R`,`${t}:127.0.0.1:${e}`);let n=h.findIndex(e=>e.startsWith(`ANTHROPIC_BASE_URL=`));n!==-1&&(h[n]=`ANTHROPIC_BASE_URL=http://127.0.0.1:${t}`)}else{let e=`/tmp/claude-ssh-auth-${p}.sock`;_.push(`-R`,`${e}:${d}`),_.push(`-o`,`StreamLocalBindUnlink=yes`);let t=h.indexOf(`ANTHROPIC_AUTH_SOCKET=${f.ANTHROPIC_AUTH_SOCKET}`);t!==-1&&(h[t]=`ANTHROPIC_AUTH_SOCKET=${e}`)}_.push(n,h.join(` `)),o?.(`Starting remote session…`),c(`[SSH] spawning: ${_.join(` `)}`);let v;try{v=Bun.spawn(_,{stdin:`pipe`,stdout:`pipe`,stderr:`pipe`})}catch(e){throw u.stop(),new V(`Failed to spawn SSH process: ${e instanceof Error?e.message:String(e)}`)}let y=[];G(v,y);let b;if(a){let t=await Promise.race([v.exited.then(e=>e),new Promise(e=>setTimeout(()=>e(null),3e3))]);if(t!==null){u.stop();let e=y.join(``).trim();throw new V(`Remote process exited immediately (code ${t})${e?`: ${e}`:``}`)}b=e.cwd||l||`/`}else try{b=await W(v,e.cwd||l)}catch(e){throw u.stop(),v.kill(),e}c(`[SSH] remote session initialized, remoteCwd=${b}`);let S=v,C=async()=>{c(`[SSH] reconnect: re-spawning SSH process with --continue`);let e=[..._],t=e.length-1,n=e[t];n.includes(`--continue`)||(e[t]=n.replace(/ -p(?:\s|$)/,` -p --continue `));let r=Bun.spawn(e,{stdin:`pipe`,stdout:`pipe`,stderr:`pipe`}),i=[];return G(r,i),await W(r,b),S=r,y.length=0,y.push(...i),r};return{remoteCwd:b,get proc(){return S},proxy:u,createManager(e){return new x(S,{...e,reconnect:C})},getStderrTail(){return y.slice(-B).join(``)}}}async function U(e){let{proxy:t,authEnv:n}=await E(),r=[`--output-format`,`stream-json`,`--input-format`,`stream-json`,`-p`];e.cwd&&r.push(`--cwd`,e.cwd),e.permissionMode&&r.push(`--permission-mode`,e.permissionMode),e.dangerouslySkipPermissions&&r.push(`--dangerously-skip-permissions`);let i=f(r),a;try{a=Bun.spawn([i.execPath,...i.args],{stdin:`pipe`,stdout:`pipe`,stderr:`pipe`,env:{...i.env,...n}})}catch(e){throw t.stop(),new V(`Failed to spawn local CLI process: ${e instanceof Error?e.message:String(e)}`)}c(`[SSH] local session spawned, waiting for init message...`);let o=[];G(a,o);let s;try{s=await W(a,e.cwd)}catch(e){throw t.stop(),a.kill(),e}c(`[SSH] local session initialized, remoteCwd=${s}`);let l=a,u=async()=>{c(`[SSH] local reconnect: re-spawning CLI with --continue`);let e=[...r];e.includes(`--continue`)||e.push(`--continue`);let t=f(e),i=Bun.spawn([t.execPath,...t.args],{stdin:`pipe`,stdout:`pipe`,stderr:`pipe`,env:{...t.env,...n}}),a=[];return G(i,a),await W(i,s),l=i,o.length=0,o.push(...a),i};return{remoteCwd:s,get proc(){return l},proxy:t,createManager(e){return new x(l,{...e,reconnect:u})},getStderrTail(){return o.slice(-B).join(``)}}}async function W(e,t){let n=e.stdout;if(!n)throw new V(`Child process stdout is not readable`);let r=n.getReader(),a=new TextDecoder,o=``,s=Date.now()+z;try{for(;Date.now()<s;){let e=s-Date.now(),n=await Promise.race([r.read(),new Promise((t,n)=>setTimeout(()=>n(new V(`Remote CLI did not initialize within 30 seconds. Check SSH connectivity and remote binary.`)),e))]);if(n.done)throw new V(`Child process exited before sending init message`);o+=a.decode(n.value,{stream:!0});let c=o.split(`
`);o=c.pop()??``;for(let e of c){let n=e.trim();if(n)try{let e=i(n);if(e.type===`system`&&e.subtype===`init`)return r.releaseLock(),e.cwd||t||process.cwd()}catch{}}}}catch(e){throw r.releaseLock(),e instanceof V?e:new V(`Error reading init message: ${e instanceof Error?e.message:String(e)}`)}throw r.releaseLock(),new V(`Remote CLI did not initialize within 30 seconds. Check SSH connectivity and remote binary.`)}function G(e,t){let n=e.stderr;if(!n)return;let r=n.getReader(),i=new TextDecoder;(async()=>{try{for(;;){let{done:e,value:n}=await r.read();if(e)break;t.push(i.decode(n,{stream:!0})),t.length>B*2&&t.splice(0,t.length-B)}}catch{}})()}export{V as SSHSessionError,U as createLocalSSHSession,H as createSSHSession};