@wendongfly/myhi 1.0.59 → 1.0.60
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/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -358,7 +358,7 @@ Content-Length: `+T+`\r
|
|
|
358
358
|
`);this._buffer=d.pop()||"";for(const a of d){const n=a.replace(/\r$/,"");if(n)try{const r=JSON.parse(n);this._handleMessage(r)}catch{}}}),this._proc.stderr.on("data",u=>{const d=u.toString().trim();d&&(console.error("[agent:stderr]",d),!d.includes("Warning:")&&!d.includes("DeprecationWarning")&&this.emit("agent:error",{message:d}))}),this._proc.on("close",u=>{if(!this._interrupted&&this._buffer.trim())try{const d=JSON.parse(this._buffer.trim());this._handleMessage(d)}catch{}this._keepAliveTimer&&(clearInterval(this._keepAliveTimer),this._keepAliveTimer=null),this._proc=null,this._buffer="",console.log(`[agent] \u8FDB\u7A0B\u9000\u51FA (code ${u}), \u4F1A\u8BDD: ${this.claudeSessionId||"?"}`),this._busy&&(this._busy=!1,this._interrupted=!1,this.emit("agent:busy",!1),this._pendingReject&&(this._pendingReject(new Error(`Claude \u8FDB\u7A0B\u9000\u51FA (code ${u})`)),this._pendingResolve=null,this._pendingReject=null)),this.alive&&u!==0&&u!==null&&this.emit("agent:error",{message:`Claude \u8FDB\u7A0B\u5F02\u5E38\u9000\u51FA (code ${u})\uFF0C\u4E0B\u6B21\u67E5\u8BE2\u5C06\u81EA\u52A8\u91CD\u542F`})}),this._proc.on("error",u=>{this._keepAliveTimer&&(clearInterval(this._keepAliveTimer),this._keepAliveTimer=null),this._proc=null,this._busy=!1,this.emit("agent:busy",!1),this.emit("agent:error",{message:`\u542F\u52A8 Claude \u5931\u8D25: ${u.message}`}),this._pendingReject&&(this._pendingReject(u),this._pendingResolve=null,this._pendingReject=null)}),this._keepAliveTimer=setInterval(()=>{this._writeStdin({type:"keep_alive"})},3e4)}async query(f){if(this._busy){this.emit("agent:error",{message:"\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210"});return}return this._busy=!0,this._interrupted=!1,this.emit("agent:busy",!0),this._history.push({type:"user",content:f,timestamp:Date.now()}),this._proc||this._spawnProcess(),new Promise((c,v)=>{this._pendingResolve=c,this._pendingReject=v,this._writeStdin({type:"user",message:{role:"user",content:f}})||(this._busy=!1,this.emit("agent:busy",!1),this._pendingResolve=null,this._pendingReject=null,v(new Error("Claude \u8FDB\u7A0B\u4E0D\u53EF\u5199")))})}respondPermission(f,c){c?this._writeStdin({type:"control_response",response:{request_id:f,subtype:"success",response:{}}}):this._writeStdin({type:"control_response",response:{request_id:f,subtype:"error",error:"User denied permission"}})}_handleMessage(f){f.session_id&&!this.claudeSessionId&&(this.claudeSessionId=f.session_id),f.type==="system"&&f.subtype==="init"&&f.session_id&&(this.claudeSessionId=f.session_id),this._history.push({...f,timestamp:Date.now()});const c=500;if(this._history.length>c&&(this._history=this._history.slice(-c)),this.emit("agent:message",f),f.type==="rate_limit_event"&&f.rate_limit_info&&(this._usage.rateLimitInfo=f.rate_limit_info),f.type==="result"&&(this._usage.queryCount++,f.total_cost_usd&&(this._usage.totalCostUSD+=f.total_cost_usd),f.usage&&(this._usage.totalInputTokens+=f.usage.input_tokens||0,this._usage.totalOutputTokens+=f.usage.output_tokens||0,this._usage.totalCacheReadTokens+=f.usage.cache_read_input_tokens||0,this._usage.totalCacheCreationTokens+=f.usage.cache_creation_input_tokens||0),f.modelUsage))for(const[v,m]of Object.entries(f.modelUsage))this._usage.modelUsage[v]||(this._usage.modelUsage[v]={inputTokens:0,outputTokens:0,costUSD:0}),this._usage.modelUsage[v].inputTokens+=m.inputTokens||0,this._usage.modelUsage[v].outputTokens+=m.outputTokens||0,this._usage.modelUsage[v].costUSD+=m.costUSD||0;f.type==="result"&&(this._busy=!1,this._interrupted=!1,this.emit("agent:busy",!1),this._pendingResolve&&(this._pendingResolve(0),this._pendingResolve=null,this._pendingReject=null))}interrupt(){if(this._proc&&this._busy){this._interrupted=!0;try{this._proc.kill("SIGINT")}catch{try{this._proc.kill("SIGTERM")}catch{}}this.emit("agent:message",{type:"system",subtype:"interrupted",message:"\u67E5\u8BE2\u5DF2\u4E2D\u65AD"})}}kill(){if(this.alive=!1,this._keepAliveTimer&&(clearInterval(this._keepAliveTimer),this._keepAliveTimer=null),this._proc){try{this._proc.kill("SIGTERM")}catch{}this._proc=null}this._busy=!1}_loadResumedHistory(){try{const f=(0,external_path_.join)((0,external_os_.homedir)(),".claude","projects");if(!(0,external_fs_.existsSync)(f))return;for(const c of(0,external_fs_.readdirSync)(f,{withFileTypes:!0})){if(!c.isDirectory())continue;const v=(0,external_path_.join)(f,c.name,this.claudeSessionId+".jsonl");if(!(0,external_fs_.existsSync)(v))continue;const g=(0,external_fs_.readFileSync)(v,"utf8").split(`
|
|
359
359
|
`).filter(Boolean).slice(-20);for(const u of g)try{const d=JSON.parse(u);if(d.type==="human"&&d.message?.content){const a=typeof d.message.content=="string"?d.message.content:d.message.content.find(n=>n.type==="text")?.text||"";a&&this._history.push({type:"user",content:a,timestamp:d.timestamp})}else d.type==="assistant"&&d.message?.content?this._history.push({type:"assistant",message:d.message,timestamp:d.timestamp}):d.type==="result"&&this._history.push({type:"result",total_cost_usd:d.costUSD||d.total_cost_usd,timestamp:d.timestamp})}catch{}return}}catch(f){console.warn("[agent] \u52A0\u8F7D\u6062\u590D\u4F1A\u8BDD\u5386\u53F2\u5931\u8D25:",f.message)}}get isBusy(){return this._busy}addViewer(f){this._viewers.add(f)}removeViewer(f){this._viewers.delete(f)}get viewerCount(){return this._viewers.size}takeControl(f,c){this.controlHolder=f,this.controlHolderName=c||null,this.lastInputTime=Date.now()}releaseControl(){this.controlHolder=null,this.controlHolderName=null,this.lastInputTime=null}isController(f){return this.controlHolder===f}toJSON(){return{id:this.id,title:this.title,cwd:this.cwd,createdAt:this.createdAt,mode:"agent",alive:this.alive,viewers:this.viewerCount,controlHolder:this.controlHolder,controlHolderName:this.controlHolderName,permissionMode:this.permissionMode,owner:this.owner,claudeSessionId:this.claudeSessionId,busy:this._busy,usage:this._usage}}}function listLocalClaudeSessions(S){const f=[],c=S?(0,external_path_.resolve)((0,external_path_.normalize)(S)).replace(/[\\/]+$/,""):null;try{const v=(0,external_path_.join)((0,external_os_.homedir)(),".claude","projects");if(!(0,external_fs_.existsSync)(v))return f;for(const m of(0,external_fs_.readdirSync)(v,{withFileTypes:!0})){if(!m.isDirectory())continue;const g=(0,external_path_.join)(v,m.name);try{for(const u of(0,external_fs_.readdirSync)(g)){if(!u.endsWith(".jsonl"))continue;const d=u.replace(".jsonl",""),a=(0,external_path_.join)(g,u);try{const n=(0,external_fs_.readFileSync)(a,"utf8").split(`
|
|
360
360
|
`).filter(Boolean);let r=null,t=null,e=0,o="";for(const i of n)try{const p=JSON.parse(i);if(r||(r=p),t=p,e++,!o&&p.type==="human"&&p.message?.content){const l=p.message.content;if(typeof l=="string")o=l.slice(0,120);else if(Array.isArray(l)){const h=l.find(b=>b.type==="text");h&&(o=h.text?.slice(0,120)||"")}}}catch{}let s=m.name;if(process.platform==="win32"&&/^[A-Za-z]--/.test(s)?s=s[0]+":\\"+s.slice(3).replace(/-/g,"\\"):s.startsWith("-")&&(s=s.replace(/-/g,"/")),c&&!(0,external_path_.resolve)((0,external_path_.normalize)(s)).replace(/[\\/]+$/,"").startsWith(c))continue;f.push({sessionId:d,projectDir:m.name,projectPath:s,messageCount:e,summary:o,createdAt:r?.timestamp||null,updatedAt:t?.timestamp||null})}catch{}}}catch{}}}catch{}return f.sort((v,m)=>new Date(m.updatedAt||0).getTime()-new Date(v.updatedAt||0).getTime()),f.slice(0,20)}const DEFAULT_SHELL=process.platform==="win32"?process.env.SHELL||"powershell.exe":process.env.SHELL||"/bin/bash",CONFIG_DIR=(0,external_path_.join)((0,external_os_.homedir)(),".myhi"),SESSIONS_FILE=(0,external_path_.join)(CONFIG_DIR,"sessions.json");function loadSavedConfigs(){try{return JSON.parse((0,external_fs_.readFileSync)(SESSIONS_FILE,"utf8"))}catch{return[]}}function writeSavedConfigs(S){try{(0,external_fs_.mkdirSync)(CONFIG_DIR,{recursive:!0});const f=SESSIONS_FILE+".tmp";(0,external_fs_.writeFileSync)(f,JSON.stringify(S,null,2),{mode:384}),(0,external_fs_.renameSync)(f,SESSIONS_FILE)}catch(f){console.error("[sessions] \u6301\u4E45\u5316\u5199\u5165\u5931\u8D25:",f.message)}}class Session extends external_events_.EventEmitter{constructor(f,c={}){super(),this.id=f,this.createdAt=new Date().toISOString(),this.title=c.title||DEFAULT_SHELL,this.cwd=c.cwd||process.env.MYHI_CWD||process.cwd(),this.initCmd=c.initCmd||null,this.permissionMode=c.permissionMode||"default",this.owner=c.owner||null,this.cols=c.cols||120,this.rows=c.rows||30,this._viewers=new Set,this.controlHolder=null,this.controlHolderName=null,this.lastInputTime=null;const v={...process.env};if(delete v.CLAUDECODE,delete v.CLAUDE_CODE_ENTRYPOINT,delete v.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC,c.userDir){const g=(0,external_path_.join)(c.userDir,".gitconfig");(0,external_fs_.existsSync)(g)&&(v.GIT_CONFIG_GLOBAL=g)}this._pty=external_node_pty_namespaceObject.spawn(DEFAULT_SHELL,[],{name:"xterm-256color",cols:this.cols,rows:this.rows,cwd:this.cwd,env:v,useConpty:!1}),this._scrollback="";const m=100*1024;if(this._pty.onData(g=>{this.emit("data",g),this._scrollback+=g,this._scrollback.length>m&&(this._scrollback=this._scrollback.slice(this._scrollback.length-m))}),this._pty.onExit(({exitCode:g})=>{this.exitCode=g,this.emit("exit",g)}),c.initCmd){const g=c.initCmd;let u=!1;const d=a=>{!u&&/[$>#\]]\s*$/.test(a.trimEnd())&&(u=!0,this._pty.off("data",d),setTimeout(()=>this._pty.write(g+"\r"),120))};this._pty.onData(d),setTimeout(()=>{u||(u=!0,this._pty.write(g+"\r"))},3e3)}}write(f){f!=null&&this._pty.write(f)}resize(f,c){this.cols=f,this.rows=c,this._pty.resize(f,c)}kill(){try{this._pty.kill()}catch{}}addViewer(f){this._viewers.add(f)}removeViewer(f){this._viewers.delete(f)}get viewerCount(){return this._viewers.size}takeControl(f,c){this.controlHolder=f,this.controlHolderName=c||null,this.lastInputTime=Date.now()}releaseControl(){this.controlHolder=null,this.controlHolderName=null,this.lastInputTime=null}isController(f){return this.controlHolder===f}toJSON(){return{id:this.id,title:this.title,cwd:this.cwd,createdAt:this.createdAt,cols:this.cols,rows:this.rows,viewers:this.viewerCount,alive:this.exitCode===void 0,controlHolder:this.controlHolder,controlHolderName:this.controlHolderName,permissionMode:this.permissionMode,owner:this.owner}}}class SessionManager{constructor(){this._sessions=new Map,this._agentSessions=new Map;for(const f of loadSavedConfigs())try{this._spawn((0,external_crypto_.randomUUID)(),f,!1)}catch(c){console.warn(`[\u4F1A\u8BDD] \u6062\u590D "${f.title}" \u5931\u8D25:`,c.message)}}_spawn(f,c,v=!0){const m=new Session(f,c);return this._sessions.set(f,m),m.on("exit",()=>{setTimeout(()=>this._sessions.delete(f),300*1e3)}),v&&this._persist(),m}create(f={}){return this._spawn((0,external_crypto_.randomUUID)(),f,!0)}createAgent(f={}){const c=(0,external_crypto_.randomUUID)(),v=new AgentSession(c,f);return this._agentSessions.set(c,v),v}get(f){return this._sessions.get(f)||this._agentSessions.get(f)}list(f){let c=[...this._sessions.values()].map(m=>({...m.toJSON(),mode:"pty"})),v=[...this._agentSessions.values()].map(m=>m.toJSON());return f&&(c=c.filter(m=>!m.owner||m.owner===f),v=v.filter(m=>!m.owner||m.owner===f)),[...c,...v]}listSessions(){return[...this._sessions.values(),...this._agentSessions.values()]}kill(f){const c=this._sessions.get(f);if(c){c.kill(),this._sessions.delete(f),this._persist();return}const v=this._agentSessions.get(f);v&&(v.kill(),this._agentSessions.delete(f))}_persist(){const f=[...this._sessions.values()].filter(c=>c.exitCode===void 0).map(c=>({title:c.title,cwd:c.cwd,initCmd:c.initCmd||void 0,permissionMode:c.permissionMode||void 0,owner:c.owner||void 0}));writeSavedConfigs(f)}}const roles_CONFIG_DIR=(0,external_path_.join)((0,external_os_.homedir)(),".myhi"),ROLES_FILE=(0,external_path_.join)(roles_CONFIG_DIR,"roles.json"),USERS_FILE=(0,external_path_.join)(roles_CONFIG_DIR,"users.json"),ROLE_LEVELS={admin:3,operator:2,viewer:1};let rolesConfig=null;function loadRoles(){try{if((0,external_fs_.existsSync)(ROLES_FILE))return rolesConfig=JSON.parse((0,external_fs_.readFileSync)(ROLES_FILE,"utf8")),rolesConfig}catch(S){console.warn("[\u89D2\u8272] \u52A0\u8F7D roles.json \u5931\u8D25:",S.message)}return rolesConfig=null,null}function lookupPassword(S){if(!rolesConfig?.passwords)return null;const f=rolesConfig.passwords[S];return f?{name:f.name||"\u7528\u6237",role:f.role||"viewer"}:null}function hasPermission(S,f){return(ROLE_LEVELS[S]||0)>=(ROLE_LEVELS[f]||0)}function isMultiUserMode(){return rolesConfig!==null&&rolesConfig.passwords&&Object.keys(rolesConfig.passwords).length>0}function getDefaultRole(){return rolesConfig?.defaultRole||"admin"}let usersConfig=null;function loadUsers(){try{if((0,external_fs_.existsSync)(USERS_FILE))return usersConfig=JSON.parse((0,external_fs_.readFileSync)(USERS_FILE,"utf8")),usersConfig}catch(S){console.warn("[\u7528\u6237] \u52A0\u8F7D users.json \u5931\u8D25:",S.message)}return usersConfig=null,null}function hasUsers(){return usersConfig!==null&&usersConfig.users&&Object.keys(usersConfig.users).length>0}function isExclusiveMode(){return hasUsers()&&usersConfig.exclusive===!0}function setExclusiveMode(S){usersConfig||(usersConfig={users:{}}),usersConfig.exclusive=!!S,_writeUsers()}function lookupUser(S){if(!usersConfig?.users)return null;const f=usersConfig.users[S];return f?{name:f.name||"\u7528\u6237",dir:f.dir}:null}function listUsers(){return usersConfig?.users?Object.entries(usersConfig.users).map(([S,f])=>({password:S.slice(0,2)+"*".repeat(S.length-2),name:f.name,dir:f.dir})):[]}function addUser(S,f,c){usersConfig||(usersConfig={users:{}}),usersConfig.users||(usersConfig.users={}),usersConfig.users[S]={name:f,dir:c},_writeUsers()}function removeUser(S){return!usersConfig?.users||!usersConfig.users[S]?!1:(delete usersConfig.users[S],_writeUsers(),!0)}function _writeUsers(){mkdirSync(roles_CONFIG_DIR,{recursive:!0}),writeFileSync(USERS_FILE,JSON.stringify(usersConfig,null,2),{mode:384})}const server_dirname=(0,external_path_.dirname)((0,external_url_.fileURLToPath)(import.meta.url));let PORT=parseInt(process.env.PORT,10)||3e3;const HOST=process.env.HOST||"0.0.0.0",PORT_EXPLICIT=!!process.env.PORT,configDir=(0,external_path_.join)((0,external_os_.homedir)(),".myhi");(0,external_fs_.mkdirSync)(configDir,{recursive:!0});const pidFile=(0,external_path_.join)(configDir,"daemon.pid");(function S(){try{const f=parseInt((0,external_fs_.readFileSync)(pidFile,"utf8").trim(),10);if(f&&f!==process.pid)try{process.kill(f,0),console.log(`[myhi] \u68C0\u6D4B\u5230\u5DF2\u8FD0\u884C\u7684\u5B9E\u4F8B (PID ${f})\uFF0C\u6B63\u5728\u505C\u6B62...`),process.kill(f,"SIGTERM");const c=Date.now()+5e3;for(;Date.now()<c;){try{process.kill(f,0)}catch{break}const v=Date.now()+200;for(;Date.now()<v;);}}catch{}}catch{}(0,external_fs_.writeFileSync)(pidFile,String(process.pid))})();function cleanupPid(){try{parseInt((0,external_fs_.readFileSync)(pidFile,"utf8").trim(),10)===process.pid&&(0,external_fs_.unlinkSync)(pidFile)}catch{}}process.on("exit",cleanupPid),process.on("SIGTERM",()=>{cleanupPid(),process.exit(0)}),process.on("SIGINT",()=>{cleanupPid(),process.exit(0)});function readOrCreate(S,f){try{if((0,external_fs_.existsSync)(S))return(0,external_fs_.readFileSync)(S,"utf8").trim()}catch{}const c=f();return(0,external_fs_.writeFileSync)(S,c,{mode:384}),c}const TOKEN=readOrCreate((0,external_path_.join)(configDir,"token"),()=>(0,external_crypto_.randomBytes)(16).toString("hex")),PASSWORD=readOrCreate((0,external_path_.join)(configDir,"password"),()=>String(Math.floor(1e3+Math.random()*9e3)));loadRoles(),loadUsers();let activeUser=null;const userSessions=new Map;userSessions.set(TOKEN,{role:"admin",name:"\u7BA1\u7406\u5458",permanent:!0});const SESSION_MAX_AGE=10080*60*1e3;setInterval(()=>{const S=Date.now();for(const[f,c]of userSessions)c.permanent||(!c.lastUsed||S-c.lastUsed>SESSION_MAX_AGE)&&userSessions.delete(f)},3600*1e3);function getTailscaleIP(){try{return(0,external_child_process_namespaceObject.execSync)("tailscale ip -4",{timeout:3e3,stdio:"pipe"}).toString().trim().split(`
|
|
361
|
-
`)[0]}catch{}try{if(process.platform==="win32"){const f=(0,external_child_process_namespaceObject.execSync)("route print 0.0.0.0",{timeout:3e3,stdio:"pipe"}).toString().match(/0\.0\.0\.0\s+0\.0\.0\.0\s+\S+\s+(\d+\.\d+\.\d+\.\d+)/);if(f)return f[1]}else try{const f=(0,external_child_process_namespaceObject.execSync)("ip route get 1.1.1.1",{timeout:3e3,stdio:"pipe"}).toString().match(/src\s+(\d+\.\d+\.\d+\.\d+)/);if(f)return f[1]}catch{const S=(0,external_child_process_namespaceObject.execSync)("route -n get default 2>/dev/null || route -n 2>/dev/null",{timeout:3e3,stdio:"pipe"}).toString(),f=S.match(/interface:\s*(\S+)/i)||S.match(/0\.0\.0\.0\s+(\d+\.\d+\.\d+\.\d+)/);if(f){const c=(0,external_os_.networkInterfaces)()[f[1]];if(c){const v=c.find(m=>m.family==="IPv4"&&!m.internal);if(v)return v.address}if(/^\d+\.\d+\.\d+\.\d+$/.test(f[1]))return f[1]}}}catch{}for(const S of Object.values((0,external_os_.networkInterfaces)()))for(const f of S)if(f.family==="IPv4"&&!f.internal)return f.address;return"localhost"}function parseCookies(S=""){const f={};for(const c of S.split(";")){const v=c.indexOf("=");v>0&&(f[c.slice(0,v).trim()]=c.slice(v+1).trim())}return f}const SESSION_COOKIE="myhi_sid",COOKIE_OPTS="HttpOnly; SameSite=Strict; Path=/; Max-Age=31536000";function setSessionCookie(S,f){S.setHeader("Set-Cookie",`${SESSION_COOKIE}=${f||TOKEN}; ${COOKIE_OPTS}`)}function getSessionToken(S){return parseCookies(S)[SESSION_COOKIE]||null}function hasValidSession(S){const f=getSessionToken(S);if(f&&userSessions.has(f)){const c=userSessions.get(f);return c&&(c.lastUsed=Date.now()),!0}return!1}function getUserInfo(S){const f=getSessionToken(S);return f?userSessions.get(f):null}const app=express();app.set("trust proxy",!0),app.use((S,f,c)=>{f.setHeader("Referrer-Policy","no-referrer"),f.setHeader("X-Content-Type-Options","nosniff"),c()});const httpServer=(0,external_http_.createServer)(app),_corsAllowed=/^https?:\/\/(localhost|127\.0\.0\.1|\[::1\]|10\.\d+\.\d+\.\d+|172\.(1[6-9]|2\d|3[01])\.\d+\.\d+|192\.168\.\d+\.\d+|100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\.\d+\.\d+)(:\d+)?$/,io=new Server({cors:{origin:(S,f)=>{if(!S||_corsAllowed.test(S))return f(null,!0);f(new Error("CORS \u4E0D\u5141\u8BB8\u6B64\u6765\u6E90"),!1)},credentials:!0},transports:["websocket"]});io.attach(httpServer);const manager=new SessionManager,AUTO_ATTACH=process.env.MYHI_AUTO_ATTACH!=="0",_autoSpawned=new Set;function spawnLocalTerminal(S,f){if(!AUTO_ATTACH||_autoSpawned.has(S))return;_autoSpawned.add(S);const c=__nccwpck_require__.ab+"attach.js",v=process.execPath,m=f||"myhi";if(process.platform==="win32"){const g=`"${v}" "${c}" ${S}`,u=(0,external_child_process_namespaceObject.spawn)("wt.exe",["-w","0","new-tab","--title",m,"--","cmd","/k",g],{detached:!0,stdio:"ignore"});u.unref(),u.on("error",d=>{console.warn("[attach] wt.exe \u5931\u8D25\uFF0C\u56DE\u9000\u5230 cmd:",d.message),(0,external_child_process_namespaceObject.spawn)("cmd.exe",["/c","start",`"${m}"`,"cmd","/k",g],{detached:!0,stdio:"ignore"}).unref()})}else if(process.platform==="darwin"){const g=`tell application "Terminal" to do script "${v} ${c} ${S}"`;(0,external_child_process_namespaceObject.spawn)("osascript",["-e",g],{detached:!0,stdio:"ignore"}).unref()}else{const g=`${v} "${c}" ${S}`;for(const[u,d]of[["gnome-terminal",["--","bash","-c",`${g}; exec bash`]],["xterm",["-title",m,"-e",g]],["konsole",["--new-tab","-e",g]]]){const a=(0,external_child_process_namespaceObject.spawn)(u,d,{detached:!0,stdio:"ignore"});a.unref(),a.on("error",()=>{});break}}}const uploadDir=(0,external_path_.join)(configDir,"uploads");(0,external_fs_.mkdirSync)(uploadDir,{recursive:!0});function checkAuth(S,f,c){const v=S.query.token;if(v&&(v===TOKEN||userSessions.has(v))){const m=userSessions.get(v);if(m?.onetime){userSessions.delete(v);const u=(0,external_crypto_.randomBytes)(16).toString("hex");userSessions.set(u,{role:m.role,name:m.name,lastUsed:Date.now()}),setSessionCookie(f,u)}else setSessionCookie(f,v===TOKEN?TOKEN:v);const g=S.path+(Object.keys(S.query).filter(u=>u!=="token").length?"?"+new URLSearchParams(Object.fromEntries(Object.entries(S.query).filter(([u])=>u!=="token"))):"");return f.redirect(g)}if(hasValidSession(S.headers.cookie)){if(isExclusiveMode()&&activeUser){const m=getSessionToken(S.headers.cookie);if(m!==TOKEN){const g=userSessions.get(m);if(!g||g.name!==activeUser.name)return f.setHeader("Set-Cookie",`${SESSION_COOKIE}=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0`),f.redirect("/login")}}return c()}f.redirect("/login")}const _require=(0,external_module_namespaceObject.createRequire)(import.meta.url);function pkgDirSafe(S){try{return(0,external_path_.dirname)(_require.resolve(`${S}/package.json`))}catch{return null}}const libDir=(0,external_path_.join)(server_dirname,"lib");app.use("/lib/xterm",express.static(pkgDirSafe("xterm")||(0,external_path_.join)(libDir,"xterm"))),app.use("/lib/xterm-fit",express.static(pkgDirSafe("xterm-addon-fit")||(0,external_path_.join)(libDir,"xterm-fit"))),app.use("/lib/xterm-links",express.static(pkgDirSafe("xterm-addon-web-links")||(0,external_path_.join)(libDir,"xterm-links")));const _loginAttempts=new Map,LOGIN_MAX_ATTEMPTS=5,LOGIN_LOCKOUT_MS=300*1e3;function checkLoginRate(S){const f=Date.now(),c=_loginAttempts.get(S);return!c||f>c.resetAt?!0:c.count<LOGIN_MAX_ATTEMPTS}function recordLoginFailure(S){const f=Date.now(),c=_loginAttempts.get(S);!c||f>c.resetAt?_loginAttempts.set(S,{count:1,resetAt:f+LOGIN_LOCKOUT_MS}):c.count++}function clearLoginFailures(S){_loginAttempts.delete(S)}setInterval(()=>{const S=Date.now();for(const[f,c]of _loginAttempts)S>c.resetAt&&_loginAttempts.delete(f)},600*1e3),app.get("/login",(S,f)=>{f.sendFile(__nccwpck_require__.ab+"login.html")}),app.post("/login",express.urlencoded({extended:!1}),(S,f)=>{const c=S.ip;if(!checkLoginRate(c))return f.redirect("/login?error=locked");loadRoles(),loadUsers();const v=S.body?.password,m=S.query.from,g=m&&m.startsWith("/")&&!m.startsWith("//")?m:"/";if(hasUsers()){const d=lookupUser(v);if(!d)return recordLoginFailure(c),f.redirect("/login?error=1");if(isExclusiveMode()&&activeUser&&activeUser.name!==d.name)return f.redirect("/login?error=occupied&user="+encodeURIComponent(activeUser.name));clearLoginFailures(c);const a=(0,external_crypto_.randomBytes)(16).toString("hex");return userSessions.set(a,{role:"admin",name:d.name,dir:d.dir,lastUsed:Date.now()}),isExclusiveMode()&&(activeUser?activeUser.tokens.add(a):activeUser={name:d.name,dir:d.dir,tokens:new Set([a]),loginAt:Date.now()}),setSessionCookie(f,a),console.log(`[\u767B\u5F55] ${d.name} \u767B\u5F55\uFF08${isExclusiveMode()?"\u72EC\u5360":"\u5171\u4EAB"}\u6A21\u5F0F\uFF09`),f.redirect(g)}const u=lookupPassword(v);if(u){clearLoginFailures(c);const d=(0,external_crypto_.randomBytes)(16).toString("hex");return userSessions.set(d,{role:u.role,name:u.name,lastUsed:Date.now()}),setSessionCookie(f,d),f.redirect(g)}if(v===PASSWORD){clearLoginFailures(c);const d=(0,external_crypto_.randomBytes)(16).toString("hex");return userSessions.set(d,{role:"admin",name:"\u7BA1\u7406\u5458",lastUsed:Date.now()}),setSessionCookie(f,d),f.redirect(g)}recordLoginFailure(c),f.redirect("/login?error=1")}),app.post("/logout",(S,f)=>{const c=getSessionToken(S.headers.cookie);c&&(activeUser&&activeUser.tokens.has(c)&&(activeUser.tokens.delete(c),activeUser.tokens.size===0?(console.log(`[\u9000\u51FA] ${activeUser.name} \u5168\u90E8\u8BBE\u5907\u9000\u51FA\uFF0C\u91CA\u653E\u767B\u5F55\u72B6\u6001\uFF08\u4F1A\u8BDD\u4FDD\u7559\uFF09`),activeUser=null):console.log(`[\u9000\u51FA] ${activeUser.name} \u4E00\u4E2A\u8BBE\u5907\u9000\u51FA\uFF08\u5269\u4F59 ${activeUser.tokens.size} \u4E2A\uFF09`)),userSessions.delete(c)),f.setHeader("Set-Cookie",`${SESSION_COOKIE}=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0`),f.redirect("/login")}),app.get("/api/status",(S,f)=>{if(isExclusiveMode()&&activeUser)return f.json({occupied:!0,userName:activeUser.name,releasing:!!_exclusiveReleaseTimer});if(hasUsers()&&!isExclusiveMode()){const c=new Set;for(const[,v]of io.sockets.sockets)v.data.userName&&v.data.userName!=="\u7BA1\u7406\u5458"&&c.add(v.data.userName);return f.json({occupied:!1,onlineUsers:[...c]})}f.json({occupied:!1})}),app.get("/",checkAuth,(S,f)=>f.sendFile(__nccwpck_require__.ab+"index.html")),app.get("/terminal/:id",checkAuth,(S,f)=>f.sendFile(__nccwpck_require__.ab+"chat.html")),app.get("/terminal-raw/:id",checkAuth,(S,f)=>f.sendFile(__nccwpck_require__.ab+"terminal.html")),app.use("/lib",express.static(__nccwpck_require__.ab+"lib")),app.get("/api/sessions",checkAuth,(S,f)=>{const c=getUserInfo(S.headers.cookie);f.json(manager.list(c?.name))}),app.get("/api/usage",checkAuth,(S,f)=>{try{const c=(0,external_path_.join)((0,external_os_.homedir)(),".claude","stats-cache.json");let v=null;(0,external_fs_.existsSync)(c)&&(v=JSON.parse((0,external_fs_.readFileSync)(c,"utf8")));const m=manager.listSessions().filter(r=>r.mode==="agent"&&r.alive).map(r=>({id:r.id,title:r.title,owner:r.owner,usage:r.usage})),g=new Date,u=new Date(g-10080*60*1e3).toISOString().slice(0,10),d=v?.dailyActivity?.filter(r=>r.date>=u)||[],a={messageCount:d.reduce((r,t)=>r+t.messageCount,0),sessionCount:d.reduce((r,t)=>r+t.sessionCount,0),toolCallCount:d.reduce((r,t)=>r+t.toolCallCount,0)};let n=null;for(const r of m)if(r.usage?.rateLimitInfo){n=r.usage.rateLimitInfo;break}f.json({rateLimit:n,sevenDay:a,activeSessions:m,totalStats:v?{totalSessions:v.totalSessions,totalMessages:v.totalMessages,modelUsage:v.modelUsage,firstSessionDate:v.firstSessionDate,lastComputedDate:v.lastComputedDate}:null})}catch(c){f.status(500).json({error:c.message})}}),app.post("/api/sessions",checkAuth,express.json(),(S,f)=>{const c=getUserInfo(S.headers.cookie),v=manager.create({...S.body,owner:c?.name,userDir:c?.dir});f.status(201).json(v.toJSON())}),app.delete("/api/sessions/:id",checkAuth,(S,f)=>{manager.kill(S.params.id),f.status(204).end()}),app.get("/api/claude-sessions",checkAuth,(S,f)=>{const c=getUserInfo(S.headers.cookie);f.json(listLocalClaudeSessions(c?.dir))}),app.get("/api/dirs",checkAuth,(S,f)=>{const c=getUserInfo(S.headers.cookie);if(!c||c.role!=="admin")return f.status(403).json({error:"\u6CA1\u6709\u76EE\u5F55\u6D4F\u89C8\u6743\u9650"});const v=c.dir?(0,external_path_.resolve)((0,external_path_.normalize)(c.dir)):null,m=process.platform==="win32"?"\\":"/";let g=S.query.path||v||process.env.MYHI_CWD||(0,external_os_.homedir)(),u=(0,external_path_.resolve)((0,external_path_.normalize)(g)).replace(/[/\\]+$/,"");process.platform==="win32"&&/^[A-Za-z]:$/.test(u)&&(u+="\\"),v&&!u.startsWith(v)&&(u=v);try{const d=(0,external_fs_.readdirSync)(u,{withFileTypes:!0}).filter(r=>r.isDirectory()&&!r.name.startsWith(".")).map(r=>({name:r.name,path:u.replace(/[/\\]+$/,"")+m+r.name})).sort((r,t)=>r.name.localeCompare(t.name)),a=(0,external_path_.join)(u,".."),n=!v||(0,external_path_.resolve)((0,external_path_.normalize)(a)).startsWith(v);f.json({current:u,parent:n&&a!==u?a:null,dirs:d})}catch(d){f.status(400).json({error:d.message})}}),app.get("/api/me",checkAuth,(S,f)=>{const c=getUserInfo(S.headers.cookie);f.json({name:c?.name||"\u7528\u6237",exclusive:isExclusiveMode(),hasUsers:hasUsers(),dir:c?.dir||null})}),app.post("/upload",checkAuth,(S,f)=>{const c=S.query.sessionId,v=c?manager.get(c):null,m=v?.cwd?(0,external_path_.join)(v.cwd,"upload"):uploadDir;(0,external_fs_.mkdirSync)(m,{recursive:!0}),multer({storage:multer.diskStorage({destination:m,filename:(u,d,a)=>{const n=d.originalname.match(/\.[^.]+$/)?.[0]||".jpg";a(null,`${Date.now()}-${(0,external_crypto_.randomBytes)(3).toString("hex")}${n}`)}}),limits:{fileSize:20*1024*1024},fileFilter:(u,d,a)=>a(null,d.mimetype.startsWith("image/"))}).single("image")(S,f,u=>{if(u)return f.status(400).json({error:u.message});if(!S.file)return f.status(400).json({error:"\u6CA1\u6709\u56FE\u7247"});f.json({path:(0,external_path_.resolve)(S.file.path).replace(/\\/g,"/")})})}),app.get("/qr/:sessionId",checkAuth,async(S,f)=>{const c=getTailscaleIP(),v=(0,external_crypto_.randomBytes)(16).toString("hex");userSessions.set(v,{role:"admin",name:"\u626B\u7801\u7528\u6237",onetime:!0,lastUsed:Date.now()});const m=`http://${c}:${PORT}/terminal/${S.params.sessionId}?token=${v}`;try{const g=await lib.toString(m,{type:"svg"});f.setHeader("Content-Type","image/svg+xml"),f.send(g)}catch(g){f.status(500).send(g.message)}}),io.use((S,f)=>{const c=S.handshake.headers.cookie;if(hasValidSession(c)){const m=getUserInfo(c);return S.data.role=m?.role||"admin",S.data.userName=m?.name||"\u7528\u6237",S.data.dir=m?.dir||null,f()}if((S.handshake.auth?.token||S.handshake.query?.token)===TOKEN)return S.data.role="admin",S.data.userName="\u7BA1\u7406\u5458",f();f(new Error("\u672A\u6388\u6743"))});const EXCLUSIVE_RELEASE_DELAY=120*1e3;let _exclusiveReleaseTimer=null;function checkExclusiveRelease(){if(!isExclusiveMode()||!activeUser)return;let S=!1;for(const[,f]of io.sockets.sockets)if(f.data.userName===activeUser.name){S=!0;break}if(S){_exclusiveReleaseTimer&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);return}_exclusiveReleaseTimer||(_exclusiveReleaseTimer=setTimeout(()=>{if(_exclusiveReleaseTimer=null,!!activeUser){for(const[,f]of io.sockets.sockets)if(f.data.userName===activeUser.name)return;console.log(`[\u72EC\u5360] ${activeUser.name} \u5DF2\u79BB\u7EBF\u8D85\u65F6\uFF0C\u91CA\u653E\u767B\u5F55\u72B6\u6001\uFF08\u4F1A\u8BDD\u4FDD\u7559\uFF09`);for(const f of activeUser.tokens)userSessions.delete(f);activeUser=null}},EXCLUSIVE_RELEASE_DELAY))}function broadcastSessions(){for(const[,S]of io.sockets.sockets)S.emit("sessions",manager.list(S.data.userName))}io.on("connection",S=>{const f=S.handshake.address?.replace("::ffff:","")||"?";console.log(`[\u8FDE\u63A5] ${S.data.userName}(${S.data.role}) \u4ECE ${f} \u63A5\u5165 id=${S.id}`),_exclusiveReleaseTimer&&activeUser&&S.data.userName===activeUser.name&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);let c=null,v=null,m=null,g=null,u=null;function d(){c&&(c.isController(S.id)&&(c.releaseControl(),io.emit("control-changed",{sessionId:c.id,holder:null,holderName:null})),c.removeViewer(S.id),v&&c.off("data",v),m&&c.off("agent:message",m),g&&c.off("agent:busy",g),u&&c.off("agent:error",u),v=null,m=null,g=null,u=null)}S.on("join",a=>{const n=manager.get(a);if(!n){S.emit("error",{message:`\u4F1A\u8BDD ${a} \u672A\u627E\u5230`});return}d(),c=n,c.addViewer(S.id),n.mode==="agent"?(m=r=>S.emit("agent:message",r),c.on("agent:message",m),g=r=>S.emit("agent:busy",r),c.on("agent:busy",g),u=r=>S.emit("agent:error",r),c.on("agent:error",u)):(v=r=>S.emit("output",r),c.on("data",v),c.once("exit",r=>{S.emit("session-exit",{code:r}),v&&c?.off("data",v)}),spawnLocalTerminal(a,n.title)),console.log(`[\u52A0\u5165] ${S.data.userName} \u52A0\u5165\u4F1A\u8BDD "${n.title}" (${a}) \u6A21\u5F0F=${n.mode||"pty"}`),S.emit("joined",{...n.toJSON(),role:S.data.role}),n.mode==="agent"?n._history?.length&&S.emit("agent:history",n._history):n._scrollback?.length&&S.emit("output",n._scrollback),broadcastSessions()}),S.on("disconnect",()=>{console.log(`[\u65AD\u5F00] ${S.data.userName} \u79BB\u5F00\u4F1A\u8BDD "${c?.title||"?"}" id=${S.id}`),d(),broadcastSessions(),checkExclusiveRelease()}),S.on("agent:query",async({prompt:a}={})=>{if(!c||c.mode!=="agent"){S.emit("agent:error",{message:"\u5F53\u524D\u4E0D\u662F Agent \u6A21\u5F0F\u4F1A\u8BDD"});return}if(!c.isController(S.id)){S.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}if(c.isBusy){S.emit("agent:error",{message:"\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210"});return}try{await c.query(a)}catch(n){console.error("[agent:query] \u9519\u8BEF:",n.message),S.emit("agent:error",{message:n.message})}}),S.on("agent:interrupt",()=>{!c||c.mode!=="agent"||c.interrupt()}),S.on("agent:permission",({requestId:a,allow:n}={})=>{if(!(!c||c.mode!=="agent")){if(!c.isController(S.id)){S.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}c.respondPermission(a,n)}}),S.on("create-agent",(a,n)=>{if(!hasPermission(S.data.role,"admin")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(S.data.dir){const t=(0,external_path_.resolve)((0,external_path_.normalize)(S.data.dir)),e=a?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(a.cwd)):null;if(e&&e!==t&&!e.startsWith(t+external_path_.sep)){typeof n=="function"&&n({ok:!1,error:"\u4E0D\u80FD\u5728\u7ED1\u5B9A\u76EE\u5F55\u4E4B\u5916\u521B\u5EFA\u4F1A\u8BDD"});return}e||(a={...a,cwd:t})}const r=a?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(r))try{(0,external_fs_.mkdirSync)(r,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${r}`)}catch(t){typeof n=="function"&&n({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${t.message}`});return}try{const t=manager.createAgent({...a,owner:S.data.userName,userDir:S.data.dir});console.log(`[\u4F1A\u8BDD] ${S.data.userName} \u521B\u5EFA Agent \u4F1A\u8BDD "${t.title}" (${t.id})`),broadcastSessions(),typeof n=="function"&&n({ok:!0,session:t.toJSON()})}catch(t){typeof n=="function"&&n({ok:!1,error:t.message})}}),S.on("input",a=>{if(!(a==null||!c)&&c.mode!=="agent"){if(!c.isController(S.id)){S.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}c.lastInputTime=Date.now(),c.write(a)}}),S.on("take-control",({sessionId:a}={})=>{const n=a?manager.get(a):c;if(n){if(!hasPermission(S.data.role,"operator")){S.emit("control-denied",{reason:"\u4F60\u7684\u89D2\u8272\u6CA1\u6709\u63A7\u5236\u6743\u9650"});return}if(n.controlHolder&&n.controlHolder!==S.id&&S.data.role!=="admin"){S.emit("control-denied",{reason:"\u5176\u4ED6\u7528\u6237\u6B63\u5728\u63A7\u5236\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u91CA\u653E"});return}n.takeControl(S.id,S.data.userName),console.log(`[\u63A7\u5236] ${S.data.userName} \u83B7\u53D6\u4F1A\u8BDD "${n.title}" \u7684\u63A7\u5236\u6743`),io.emit("control-changed",{sessionId:n.id,holder:S.id,holderName:S.data.userName})}}),S.on("release-control",({sessionId:a}={})=>{const n=a?manager.get(a):c;n&&n.isController(S.id)&&(console.log(`[\u63A7\u5236] ${S.data.userName} \u91CA\u653E\u4F1A\u8BDD "${n.title}" \u7684\u63A7\u5236\u6743`),n.releaseControl(),io.emit("control-changed",{sessionId:n.id,holder:null,holderName:null}))}),S.on("set-mode",({sessionId:a,mode:n}={})=>{const r=a?manager.get(a):c;r&&(r.permissionMode=n,io.emit("mode-changed",{sessionId:r.id,mode:n}))}),S.on("rename",({sessionId:a,title:n}={})=>{const r=a?manager.get(a):c;!r||!n||(r.title=n,io.emit("session-renamed",{sessionId:r.id,title:n}),broadcastSessions())}),S.on("resize",({cols:a,rows:n})=>c?.resize(a,n)),S.on("list",()=>S.emit("sessions",manager.list(S.data.userName))),S.on("dirs",(a,n)=>{if(typeof n!="function")return;const r=S.data.dir?(0,external_path_.resolve)((0,external_path_.normalize)(S.data.dir)):null,t=process.platform==="win32"?"\\":"/";let e=(a||r||process.env.MYHI_CWD||(0,external_os_.homedir)()).replace(/[/\\]+$/,"")||(0,external_os_.homedir)();process.platform==="win32"&&/^[A-Za-z]:$/.test(e)&&(e+="\\");const o=(0,external_path_.resolve)((0,external_path_.normalize)(e));r&&o!==r&&!o.startsWith(r+t)&&(e=r);try{const s=(0,external_fs_.readdirSync)(e,{withFileTypes:!0}).filter(h=>h.isDirectory()&&!h.name.startsWith(".")).map(h=>({name:h.name,path:e.replace(/[/\\]+$/,"")+t+h.name})).sort((h,b)=>h.name.localeCompare(b.name)),i=(0,external_path_.join)(e,".."),p=(0,external_path_.resolve)((0,external_path_.normalize)(i)),l=!r||p===r||p.startsWith(r+t);n({ok:!0,current:e,parent:l&&i!==e?i:null,dirs:s})}catch(s){n({ok:!1,error:s.message})}}),S.on("create",(a,n)=>{if(!hasPermission(S.data.role,"admin")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(S.data.dir){const t=(0,external_path_.resolve)((0,external_path_.normalize)(S.data.dir)),e=a?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(a.cwd)):null;if(e&&e!==t&&!e.startsWith(t+external_path_.sep)){typeof n=="function"&&n({ok:!1,error:"\u4E0D\u80FD\u5728\u7ED1\u5B9A\u76EE\u5F55\u4E4B\u5916\u521B\u5EFA\u4F1A\u8BDD"});return}e||(a={...a,cwd:t})}const r=a?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(r))try{(0,external_fs_.mkdirSync)(r,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${r}`)}catch(t){typeof n=="function"&&n({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${t.message}`});return}try{const t=manager.create({...a,owner:S.data.userName,userDir:S.data.dir});console.log(`[\u4F1A\u8BDD] ${S.data.userName} \u521B\u5EFA PTY \u4F1A\u8BDD "${t.title}" (${t.id})`),broadcastSessions(),typeof n=="function"&&n({ok:!0,session:t.toJSON()})}catch(t){console.error("[\u521B\u5EFA] PTY \u542F\u52A8\u5931\u8D25:",t.message),typeof n=="function"&&n({ok:!1,error:t.message})}}),S.on("kill",a=>{if(!hasPermission(S.data.role,"admin")){S.emit("error",{message:"\u6CA1\u6709\u5220\u9664\u4F1A\u8BDD\u7684\u6743\u9650"});return}console.log(`[\u4F1A\u8BDD] ${S.data.userName} \u5220\u9664\u4F1A\u8BDD ${a}`),manager.kill(a),_autoSpawned.delete(a),broadcastSessions()}),S.on("kick-user",({socketId:a,sessionId:n}={},r)=>{if(!hasPermission(S.data.role,"admin")){typeof r=="function"&&r({ok:!1,error:"\u6CA1\u6709\u8E22\u51FA\u7528\u6237\u7684\u6743\u9650"});return}const t=io.sockets.sockets.get(a);if(!t){typeof r=="function"&&r({ok:!1,error:"\u76EE\u6807\u7528\u6237\u4E0D\u5728\u7EBF"});return}const e=t.data.userName||"\u672A\u77E5";console.log(`[\u8E22\u51FA] ${S.data.userName} \u8E22\u51FA\u4E86\u7528\u6237 ${e} (${a})`),t.emit("kicked",{reason:`\u4F60\u5DF2\u88AB\u7BA1\u7406\u5458 ${S.data.userName} \u8E22\u51FA`}),t.disconnect(!0),typeof r=="function"&&r({ok:!0,name:e})}),S.on("list-viewers",({sessionId:a}={},n)=>{if(typeof n!="function")return;const r=a?manager.get(a):c;if(!r){n({ok:!1,error:"\u4F1A\u8BDD\u4E0D\u5B58\u5728"});return}const t=[];for(const e of r._viewers){const o=io.sockets.sockets.get(e);o&&t.push({socketId:e,userName:o.data.userName||"\u672A\u77E5",role:o.data.role||"viewer",isController:r.controlHolder===e})}n({ok:!0,viewers:t})})});const CONTROL_TIMEOUT=300*1e3;setInterval(()=>{for(const S of manager.listSessions())S.controlHolder&&S.lastInputTime&&Date.now()-S.lastInputTime>CONTROL_TIMEOUT&&(S.releaseControl(),io.emit("control-changed",{sessionId:S.id,holder:null,holderName:null}))},60*1e3);function showStartupInfo(){const S=httpServer.address().port;PORT=S;const f=getTailscaleIP(),c=`http://${f}:${S}/?token=${TOKEN}`;console.log(`
|
|
361
|
+
`)[0]}catch{}try{if(process.platform==="win32"){const f=(0,external_child_process_namespaceObject.execSync)("route print 0.0.0.0",{timeout:3e3,stdio:"pipe"}).toString().match(/0\.0\.0\.0\s+0\.0\.0\.0\s+\S+\s+(\d+\.\d+\.\d+\.\d+)/);if(f)return f[1]}else try{const f=(0,external_child_process_namespaceObject.execSync)("ip route get 1.1.1.1",{timeout:3e3,stdio:"pipe"}).toString().match(/src\s+(\d+\.\d+\.\d+\.\d+)/);if(f)return f[1]}catch{const S=(0,external_child_process_namespaceObject.execSync)("route -n get default 2>/dev/null || route -n 2>/dev/null",{timeout:3e3,stdio:"pipe"}).toString(),f=S.match(/interface:\s*(\S+)/i)||S.match(/0\.0\.0\.0\s+(\d+\.\d+\.\d+\.\d+)/);if(f){const c=(0,external_os_.networkInterfaces)()[f[1]];if(c){const v=c.find(m=>m.family==="IPv4"&&!m.internal);if(v)return v.address}if(/^\d+\.\d+\.\d+\.\d+$/.test(f[1]))return f[1]}}}catch{}for(const S of Object.values((0,external_os_.networkInterfaces)()))for(const f of S)if(f.family==="IPv4"&&!f.internal)return f.address;return"localhost"}function parseCookies(S=""){const f={};for(const c of S.split(";")){const v=c.indexOf("=");v>0&&(f[c.slice(0,v).trim()]=c.slice(v+1).trim())}return f}const SESSION_COOKIE="myhi_sid",COOKIE_OPTS="HttpOnly; SameSite=Strict; Path=/; Max-Age=31536000";function setSessionCookie(S,f){S.setHeader("Set-Cookie",`${SESSION_COOKIE}=${f||TOKEN}; ${COOKIE_OPTS}`)}function getSessionToken(S){return parseCookies(S)[SESSION_COOKIE]||null}function hasValidSession(S){const f=getSessionToken(S);if(f&&userSessions.has(f)){const c=userSessions.get(f);return c&&(c.lastUsed=Date.now()),!0}return!1}function getUserInfo(S){const f=getSessionToken(S);return f?userSessions.get(f):null}const app=express();app.set("trust proxy",!0),app.use((S,f,c)=>{f.setHeader("Referrer-Policy","no-referrer"),f.setHeader("X-Content-Type-Options","nosniff"),c()});const httpServer=(0,external_http_.createServer)(app),_corsAllowed=/^https?:\/\/(localhost|127\.0\.0\.1|\[::1\]|10\.\d+\.\d+\.\d+|172\.(1[6-9]|2\d|3[01])\.\d+\.\d+|192\.168\.\d+\.\d+|100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\.\d+\.\d+)(:\d+)?$/,io=new Server({cors:{origin:(S,f)=>{if(!S||_corsAllowed.test(S))return f(null,!0);f(new Error("CORS \u4E0D\u5141\u8BB8\u6B64\u6765\u6E90"),!1)},credentials:!0},transports:["websocket"]});io.attach(httpServer);const manager=new SessionManager,AUTO_ATTACH=process.env.MYHI_AUTO_ATTACH!=="0",_autoSpawned=new Set;function spawnLocalTerminal(S,f){if(!AUTO_ATTACH||_autoSpawned.has(S))return;_autoSpawned.add(S);const c=__nccwpck_require__.ab+"attach.js",v=process.execPath,m=f||"myhi";if(process.platform==="win32"){const g=`"${v}" "${c}" ${S}`,u=(0,external_child_process_namespaceObject.spawn)("wt.exe",["-w","0","new-tab","--title",m,"--","cmd","/k",g],{detached:!0,stdio:"ignore"});u.unref(),u.on("error",d=>{console.warn("[attach] wt.exe \u5931\u8D25\uFF0C\u56DE\u9000\u5230 cmd:",d.message),(0,external_child_process_namespaceObject.spawn)("cmd.exe",["/c","start",`"${m}"`,"cmd","/k",g],{detached:!0,stdio:"ignore"}).unref()})}else if(process.platform==="darwin"){const g=`tell application "Terminal" to do script "${v} ${c} ${S}"`;(0,external_child_process_namespaceObject.spawn)("osascript",["-e",g],{detached:!0,stdio:"ignore"}).unref()}else{const g=`${v} "${c}" ${S}`;for(const[u,d]of[["gnome-terminal",["--","bash","-c",`${g}; exec bash`]],["xterm",["-title",m,"-e",g]],["konsole",["--new-tab","-e",g]]]){const a=(0,external_child_process_namespaceObject.spawn)(u,d,{detached:!0,stdio:"ignore"});a.unref(),a.on("error",()=>{});break}}}const uploadDir=(0,external_path_.join)(configDir,"uploads");(0,external_fs_.mkdirSync)(uploadDir,{recursive:!0});function checkAuth(S,f,c){const v=S.query.token;if(v&&(v===TOKEN||userSessions.has(v))){const m=userSessions.get(v);if(m?.onetime){userSessions.delete(v);const u=(0,external_crypto_.randomBytes)(16).toString("hex");userSessions.set(u,{role:m.role,name:m.name,lastUsed:Date.now()}),setSessionCookie(f,u)}else setSessionCookie(f,v===TOKEN?TOKEN:v);const g=S.path+(Object.keys(S.query).filter(u=>u!=="token").length?"?"+new URLSearchParams(Object.fromEntries(Object.entries(S.query).filter(([u])=>u!=="token"))):"");return f.redirect(g)}if(hasValidSession(S.headers.cookie)){if(isExclusiveMode()&&activeUser){const m=getSessionToken(S.headers.cookie);if(m!==TOKEN){const g=userSessions.get(m);if(!g||g.name!==activeUser.name)return f.setHeader("Set-Cookie",`${SESSION_COOKIE}=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0`),f.redirect("/login")}}return c()}f.redirect("/login")}const _require=(0,external_module_namespaceObject.createRequire)(import.meta.url);function pkgDirSafe(S){try{return(0,external_path_.dirname)(_require.resolve(`${S}/package.json`))}catch{return null}}const libDir=(0,external_path_.join)(server_dirname,"lib");app.use("/lib/xterm",express.static(pkgDirSafe("xterm")||(0,external_path_.join)(libDir,"xterm"))),app.use("/lib/xterm-fit",express.static(pkgDirSafe("xterm-addon-fit")||(0,external_path_.join)(libDir,"xterm-fit"))),app.use("/lib/xterm-links",express.static(pkgDirSafe("xterm-addon-web-links")||(0,external_path_.join)(libDir,"xterm-links")));const _loginAttempts=new Map,LOGIN_MAX_ATTEMPTS=5,LOGIN_LOCKOUT_MS=300*1e3;function checkLoginRate(S){const f=Date.now(),c=_loginAttempts.get(S);return!c||f>c.resetAt?!0:c.count<LOGIN_MAX_ATTEMPTS}function recordLoginFailure(S){const f=Date.now(),c=_loginAttempts.get(S);!c||f>c.resetAt?_loginAttempts.set(S,{count:1,resetAt:f+LOGIN_LOCKOUT_MS}):c.count++}function clearLoginFailures(S){_loginAttempts.delete(S)}setInterval(()=>{const S=Date.now();for(const[f,c]of _loginAttempts)S>c.resetAt&&_loginAttempts.delete(f)},600*1e3),app.get("/login",(S,f)=>{f.sendFile(__nccwpck_require__.ab+"login.html")}),app.post("/login",express.urlencoded({extended:!1}),(S,f)=>{const c=S.ip;if(!checkLoginRate(c))return f.redirect("/login?error=locked");loadRoles(),loadUsers();const v=S.body?.password,m=S.query.from,g=m&&m.startsWith("/")&&!m.startsWith("//")?m:"/";if(hasUsers()){const d=lookupUser(v);if(!d)return recordLoginFailure(c),f.redirect("/login?error=1");if(isExclusiveMode()&&activeUser&&activeUser.name!==d.name)return f.redirect("/login?error=occupied&user="+encodeURIComponent(activeUser.name));clearLoginFailures(c);const a=(0,external_crypto_.randomBytes)(16).toString("hex");return userSessions.set(a,{role:"admin",name:d.name,dir:d.dir,lastUsed:Date.now()}),isExclusiveMode()&&(activeUser?activeUser.tokens.add(a):activeUser={name:d.name,dir:d.dir,tokens:new Set([a]),loginAt:Date.now()}),setSessionCookie(f,a),console.log(`[\u767B\u5F55] ${d.name} \u767B\u5F55\uFF08${isExclusiveMode()?"\u72EC\u5360":"\u5171\u4EAB"}\u6A21\u5F0F\uFF09`),f.redirect(g)}const u=lookupPassword(v);if(u){clearLoginFailures(c);const d=(0,external_crypto_.randomBytes)(16).toString("hex");return userSessions.set(d,{role:u.role,name:u.name,lastUsed:Date.now()}),setSessionCookie(f,d),f.redirect(g)}if(v===PASSWORD){clearLoginFailures(c);const d=(0,external_crypto_.randomBytes)(16).toString("hex");return userSessions.set(d,{role:"admin",name:"\u7BA1\u7406\u5458",lastUsed:Date.now()}),setSessionCookie(f,d),f.redirect(g)}recordLoginFailure(c),f.redirect("/login?error=1")}),app.post("/logout",(S,f)=>{const c=getSessionToken(S.headers.cookie);c&&(activeUser&&activeUser.tokens.has(c)&&(activeUser.tokens.delete(c),activeUser.tokens.size===0?(console.log(`[\u9000\u51FA] ${activeUser.name} \u5168\u90E8\u8BBE\u5907\u9000\u51FA\uFF0C\u91CA\u653E\u767B\u5F55\u72B6\u6001\uFF08\u4F1A\u8BDD\u4FDD\u7559\uFF09`),activeUser=null):console.log(`[\u9000\u51FA] ${activeUser.name} \u4E00\u4E2A\u8BBE\u5907\u9000\u51FA\uFF08\u5269\u4F59 ${activeUser.tokens.size} \u4E2A\uFF09`)),userSessions.delete(c)),f.setHeader("Set-Cookie",`${SESSION_COOKIE}=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0`),f.redirect("/login")}),app.get("/api/status",(S,f)=>{if(isExclusiveMode()&&activeUser)return f.json({occupied:!0,userName:activeUser.name,releasing:!!_exclusiveReleaseTimer});if(hasUsers()&&!isExclusiveMode()){const c=new Set;for(const[,v]of io.sockets.sockets)v.data.userName&&v.data.userName!=="\u7BA1\u7406\u5458"&&c.add(v.data.userName);return f.json({occupied:!1,onlineUsers:[...c]})}f.json({occupied:!1})}),app.get("/",checkAuth,(S,f)=>f.sendFile(__nccwpck_require__.ab+"index.html")),app.get("/terminal/:id",checkAuth,(S,f)=>f.sendFile(__nccwpck_require__.ab+"chat.html")),app.get("/terminal-raw/:id",checkAuth,(S,f)=>f.sendFile(__nccwpck_require__.ab+"terminal.html")),app.use("/lib",express.static(__nccwpck_require__.ab+"lib")),app.get("/api/sessions",checkAuth,(S,f)=>{const c=getUserInfo(S.headers.cookie);f.json(manager.list(c?.name))}),app.get("/api/usage",(S,f)=>{try{const c=(0,external_path_.join)((0,external_os_.homedir)(),".claude","stats-cache.json");let v=null;(0,external_fs_.existsSync)(c)&&(v=JSON.parse((0,external_fs_.readFileSync)(c,"utf8")));const m=manager.listSessions().filter(r=>r.mode==="agent"&&r.alive).map(r=>({id:r.id,title:r.title,owner:r.owner,usage:r.usage})),g=new Date,u=new Date(g-10080*60*1e3).toISOString().slice(0,10),d=v?.dailyActivity?.filter(r=>r.date>=u)||[],a={messageCount:d.reduce((r,t)=>r+t.messageCount,0),sessionCount:d.reduce((r,t)=>r+t.sessionCount,0),toolCallCount:d.reduce((r,t)=>r+t.toolCallCount,0)};let n=null;for(const r of m)if(r.usage?.rateLimitInfo){n=r.usage.rateLimitInfo;break}f.json({rateLimit:n,sevenDay:a,activeSessions:m,totalStats:v?{totalSessions:v.totalSessions,totalMessages:v.totalMessages,modelUsage:v.modelUsage,firstSessionDate:v.firstSessionDate,lastComputedDate:v.lastComputedDate}:null})}catch(c){f.status(500).json({error:c.message})}}),app.post("/api/sessions",checkAuth,express.json(),(S,f)=>{const c=getUserInfo(S.headers.cookie),v=manager.create({...S.body,owner:c?.name,userDir:c?.dir});f.status(201).json(v.toJSON())}),app.delete("/api/sessions/:id",checkAuth,(S,f)=>{manager.kill(S.params.id),f.status(204).end()}),app.get("/api/claude-sessions",checkAuth,(S,f)=>{const c=getUserInfo(S.headers.cookie);f.json(listLocalClaudeSessions(c?.dir))}),app.get("/api/dirs",checkAuth,(S,f)=>{const c=getUserInfo(S.headers.cookie);if(!c||c.role!=="admin")return f.status(403).json({error:"\u6CA1\u6709\u76EE\u5F55\u6D4F\u89C8\u6743\u9650"});const v=c.dir?(0,external_path_.resolve)((0,external_path_.normalize)(c.dir)):null,m=process.platform==="win32"?"\\":"/";let g=S.query.path||v||process.env.MYHI_CWD||(0,external_os_.homedir)(),u=(0,external_path_.resolve)((0,external_path_.normalize)(g)).replace(/[/\\]+$/,"");process.platform==="win32"&&/^[A-Za-z]:$/.test(u)&&(u+="\\"),v&&!u.startsWith(v)&&(u=v);try{const d=(0,external_fs_.readdirSync)(u,{withFileTypes:!0}).filter(r=>r.isDirectory()&&!r.name.startsWith(".")).map(r=>({name:r.name,path:u.replace(/[/\\]+$/,"")+m+r.name})).sort((r,t)=>r.name.localeCompare(t.name)),a=(0,external_path_.join)(u,".."),n=!v||(0,external_path_.resolve)((0,external_path_.normalize)(a)).startsWith(v);f.json({current:u,parent:n&&a!==u?a:null,dirs:d})}catch(d){f.status(400).json({error:d.message})}}),app.get("/api/me",checkAuth,(S,f)=>{const c=getUserInfo(S.headers.cookie);f.json({name:c?.name||"\u7528\u6237",exclusive:isExclusiveMode(),hasUsers:hasUsers(),dir:c?.dir||null})}),app.post("/upload",checkAuth,(S,f)=>{const c=S.query.sessionId,v=c?manager.get(c):null,m=v?.cwd?(0,external_path_.join)(v.cwd,"upload"):uploadDir;(0,external_fs_.mkdirSync)(m,{recursive:!0}),multer({storage:multer.diskStorage({destination:m,filename:(u,d,a)=>{const n=d.originalname.match(/\.[^.]+$/)?.[0]||".jpg";a(null,`${Date.now()}-${(0,external_crypto_.randomBytes)(3).toString("hex")}${n}`)}}),limits:{fileSize:20*1024*1024},fileFilter:(u,d,a)=>a(null,d.mimetype.startsWith("image/"))}).single("image")(S,f,u=>{if(u)return f.status(400).json({error:u.message});if(!S.file)return f.status(400).json({error:"\u6CA1\u6709\u56FE\u7247"});f.json({path:(0,external_path_.resolve)(S.file.path).replace(/\\/g,"/")})})}),app.get("/qr/:sessionId",checkAuth,async(S,f)=>{const c=getTailscaleIP(),v=(0,external_crypto_.randomBytes)(16).toString("hex");userSessions.set(v,{role:"admin",name:"\u626B\u7801\u7528\u6237",onetime:!0,lastUsed:Date.now()});const m=`http://${c}:${PORT}/terminal/${S.params.sessionId}?token=${v}`;try{const g=await lib.toString(m,{type:"svg"});f.setHeader("Content-Type","image/svg+xml"),f.send(g)}catch(g){f.status(500).send(g.message)}}),io.use((S,f)=>{const c=S.handshake.headers.cookie;if(hasValidSession(c)){const m=getUserInfo(c);return S.data.role=m?.role||"admin",S.data.userName=m?.name||"\u7528\u6237",S.data.dir=m?.dir||null,f()}if((S.handshake.auth?.token||S.handshake.query?.token)===TOKEN)return S.data.role="admin",S.data.userName="\u7BA1\u7406\u5458",f();f(new Error("\u672A\u6388\u6743"))});const EXCLUSIVE_RELEASE_DELAY=120*1e3;let _exclusiveReleaseTimer=null;function checkExclusiveRelease(){if(!isExclusiveMode()||!activeUser)return;let S=!1;for(const[,f]of io.sockets.sockets)if(f.data.userName===activeUser.name){S=!0;break}if(S){_exclusiveReleaseTimer&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);return}_exclusiveReleaseTimer||(_exclusiveReleaseTimer=setTimeout(()=>{if(_exclusiveReleaseTimer=null,!!activeUser){for(const[,f]of io.sockets.sockets)if(f.data.userName===activeUser.name)return;console.log(`[\u72EC\u5360] ${activeUser.name} \u5DF2\u79BB\u7EBF\u8D85\u65F6\uFF0C\u91CA\u653E\u767B\u5F55\u72B6\u6001\uFF08\u4F1A\u8BDD\u4FDD\u7559\uFF09`);for(const f of activeUser.tokens)userSessions.delete(f);activeUser=null}},EXCLUSIVE_RELEASE_DELAY))}function broadcastSessions(){for(const[,S]of io.sockets.sockets)S.emit("sessions",manager.list(S.data.userName))}io.on("connection",S=>{const f=S.handshake.address?.replace("::ffff:","")||"?";console.log(`[\u8FDE\u63A5] ${S.data.userName}(${S.data.role}) \u4ECE ${f} \u63A5\u5165 id=${S.id}`),_exclusiveReleaseTimer&&activeUser&&S.data.userName===activeUser.name&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);let c=null,v=null,m=null,g=null,u=null;function d(){c&&(c.isController(S.id)&&(c.releaseControl(),io.emit("control-changed",{sessionId:c.id,holder:null,holderName:null})),c.removeViewer(S.id),v&&c.off("data",v),m&&c.off("agent:message",m),g&&c.off("agent:busy",g),u&&c.off("agent:error",u),v=null,m=null,g=null,u=null)}S.on("join",a=>{const n=manager.get(a);if(!n){S.emit("error",{message:`\u4F1A\u8BDD ${a} \u672A\u627E\u5230`});return}d(),c=n,c.addViewer(S.id),n.mode==="agent"?(m=r=>S.emit("agent:message",r),c.on("agent:message",m),g=r=>S.emit("agent:busy",r),c.on("agent:busy",g),u=r=>S.emit("agent:error",r),c.on("agent:error",u)):(v=r=>S.emit("output",r),c.on("data",v),c.once("exit",r=>{S.emit("session-exit",{code:r}),v&&c?.off("data",v)}),spawnLocalTerminal(a,n.title)),console.log(`[\u52A0\u5165] ${S.data.userName} \u52A0\u5165\u4F1A\u8BDD "${n.title}" (${a}) \u6A21\u5F0F=${n.mode||"pty"}`),S.emit("joined",{...n.toJSON(),role:S.data.role}),n.mode==="agent"?n._history?.length&&S.emit("agent:history",n._history):n._scrollback?.length&&S.emit("output",n._scrollback),broadcastSessions()}),S.on("disconnect",()=>{console.log(`[\u65AD\u5F00] ${S.data.userName} \u79BB\u5F00\u4F1A\u8BDD "${c?.title||"?"}" id=${S.id}`),d(),broadcastSessions(),checkExclusiveRelease()}),S.on("agent:query",async({prompt:a}={})=>{if(!c||c.mode!=="agent"){S.emit("agent:error",{message:"\u5F53\u524D\u4E0D\u662F Agent \u6A21\u5F0F\u4F1A\u8BDD"});return}if(!c.isController(S.id)){S.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}if(c.isBusy){S.emit("agent:error",{message:"\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210"});return}try{await c.query(a)}catch(n){console.error("[agent:query] \u9519\u8BEF:",n.message),S.emit("agent:error",{message:n.message})}}),S.on("agent:interrupt",()=>{!c||c.mode!=="agent"||c.interrupt()}),S.on("agent:permission",({requestId:a,allow:n}={})=>{if(!(!c||c.mode!=="agent")){if(!c.isController(S.id)){S.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}c.respondPermission(a,n)}}),S.on("create-agent",(a,n)=>{if(!hasPermission(S.data.role,"admin")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(S.data.dir){const t=(0,external_path_.resolve)((0,external_path_.normalize)(S.data.dir)),e=a?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(a.cwd)):null;if(e&&e!==t&&!e.startsWith(t+external_path_.sep)){typeof n=="function"&&n({ok:!1,error:"\u4E0D\u80FD\u5728\u7ED1\u5B9A\u76EE\u5F55\u4E4B\u5916\u521B\u5EFA\u4F1A\u8BDD"});return}e||(a={...a,cwd:t})}const r=a?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(r))try{(0,external_fs_.mkdirSync)(r,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${r}`)}catch(t){typeof n=="function"&&n({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${t.message}`});return}try{const t=manager.createAgent({...a,owner:S.data.userName,userDir:S.data.dir});console.log(`[\u4F1A\u8BDD] ${S.data.userName} \u521B\u5EFA Agent \u4F1A\u8BDD "${t.title}" (${t.id})`),broadcastSessions(),typeof n=="function"&&n({ok:!0,session:t.toJSON()})}catch(t){typeof n=="function"&&n({ok:!1,error:t.message})}}),S.on("input",a=>{if(!(a==null||!c)&&c.mode!=="agent"){if(!c.isController(S.id)){S.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}c.lastInputTime=Date.now(),c.write(a)}}),S.on("take-control",({sessionId:a}={})=>{const n=a?manager.get(a):c;if(n){if(!hasPermission(S.data.role,"operator")){S.emit("control-denied",{reason:"\u4F60\u7684\u89D2\u8272\u6CA1\u6709\u63A7\u5236\u6743\u9650"});return}if(n.controlHolder&&n.controlHolder!==S.id&&S.data.role!=="admin"){S.emit("control-denied",{reason:"\u5176\u4ED6\u7528\u6237\u6B63\u5728\u63A7\u5236\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u91CA\u653E"});return}n.takeControl(S.id,S.data.userName),console.log(`[\u63A7\u5236] ${S.data.userName} \u83B7\u53D6\u4F1A\u8BDD "${n.title}" \u7684\u63A7\u5236\u6743`),io.emit("control-changed",{sessionId:n.id,holder:S.id,holderName:S.data.userName})}}),S.on("release-control",({sessionId:a}={})=>{const n=a?manager.get(a):c;n&&n.isController(S.id)&&(console.log(`[\u63A7\u5236] ${S.data.userName} \u91CA\u653E\u4F1A\u8BDD "${n.title}" \u7684\u63A7\u5236\u6743`),n.releaseControl(),io.emit("control-changed",{sessionId:n.id,holder:null,holderName:null}))}),S.on("set-mode",({sessionId:a,mode:n}={})=>{const r=a?manager.get(a):c;r&&(r.permissionMode=n,io.emit("mode-changed",{sessionId:r.id,mode:n}))}),S.on("rename",({sessionId:a,title:n}={})=>{const r=a?manager.get(a):c;!r||!n||(r.title=n,io.emit("session-renamed",{sessionId:r.id,title:n}),broadcastSessions())}),S.on("resize",({cols:a,rows:n})=>c?.resize(a,n)),S.on("list",()=>S.emit("sessions",manager.list(S.data.userName))),S.on("dirs",(a,n)=>{if(typeof n!="function")return;const r=S.data.dir?(0,external_path_.resolve)((0,external_path_.normalize)(S.data.dir)):null,t=process.platform==="win32"?"\\":"/";let e=(a||r||process.env.MYHI_CWD||(0,external_os_.homedir)()).replace(/[/\\]+$/,"")||(0,external_os_.homedir)();process.platform==="win32"&&/^[A-Za-z]:$/.test(e)&&(e+="\\");const o=(0,external_path_.resolve)((0,external_path_.normalize)(e));r&&o!==r&&!o.startsWith(r+t)&&(e=r);try{const s=(0,external_fs_.readdirSync)(e,{withFileTypes:!0}).filter(h=>h.isDirectory()&&!h.name.startsWith(".")).map(h=>({name:h.name,path:e.replace(/[/\\]+$/,"")+t+h.name})).sort((h,b)=>h.name.localeCompare(b.name)),i=(0,external_path_.join)(e,".."),p=(0,external_path_.resolve)((0,external_path_.normalize)(i)),l=!r||p===r||p.startsWith(r+t);n({ok:!0,current:e,parent:l&&i!==e?i:null,dirs:s})}catch(s){n({ok:!1,error:s.message})}}),S.on("create",(a,n)=>{if(!hasPermission(S.data.role,"admin")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(S.data.dir){const t=(0,external_path_.resolve)((0,external_path_.normalize)(S.data.dir)),e=a?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(a.cwd)):null;if(e&&e!==t&&!e.startsWith(t+external_path_.sep)){typeof n=="function"&&n({ok:!1,error:"\u4E0D\u80FD\u5728\u7ED1\u5B9A\u76EE\u5F55\u4E4B\u5916\u521B\u5EFA\u4F1A\u8BDD"});return}e||(a={...a,cwd:t})}const r=a?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(r))try{(0,external_fs_.mkdirSync)(r,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${r}`)}catch(t){typeof n=="function"&&n({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${t.message}`});return}try{const t=manager.create({...a,owner:S.data.userName,userDir:S.data.dir});console.log(`[\u4F1A\u8BDD] ${S.data.userName} \u521B\u5EFA PTY \u4F1A\u8BDD "${t.title}" (${t.id})`),broadcastSessions(),typeof n=="function"&&n({ok:!0,session:t.toJSON()})}catch(t){console.error("[\u521B\u5EFA] PTY \u542F\u52A8\u5931\u8D25:",t.message),typeof n=="function"&&n({ok:!1,error:t.message})}}),S.on("kill",a=>{if(!hasPermission(S.data.role,"admin")){S.emit("error",{message:"\u6CA1\u6709\u5220\u9664\u4F1A\u8BDD\u7684\u6743\u9650"});return}console.log(`[\u4F1A\u8BDD] ${S.data.userName} \u5220\u9664\u4F1A\u8BDD ${a}`),manager.kill(a),_autoSpawned.delete(a),broadcastSessions()}),S.on("kick-user",({socketId:a,sessionId:n}={},r)=>{if(!hasPermission(S.data.role,"admin")){typeof r=="function"&&r({ok:!1,error:"\u6CA1\u6709\u8E22\u51FA\u7528\u6237\u7684\u6743\u9650"});return}const t=io.sockets.sockets.get(a);if(!t){typeof r=="function"&&r({ok:!1,error:"\u76EE\u6807\u7528\u6237\u4E0D\u5728\u7EBF"});return}const e=t.data.userName||"\u672A\u77E5";console.log(`[\u8E22\u51FA] ${S.data.userName} \u8E22\u51FA\u4E86\u7528\u6237 ${e} (${a})`),t.emit("kicked",{reason:`\u4F60\u5DF2\u88AB\u7BA1\u7406\u5458 ${S.data.userName} \u8E22\u51FA`}),t.disconnect(!0),typeof r=="function"&&r({ok:!0,name:e})}),S.on("list-viewers",({sessionId:a}={},n)=>{if(typeof n!="function")return;const r=a?manager.get(a):c;if(!r){n({ok:!1,error:"\u4F1A\u8BDD\u4E0D\u5B58\u5728"});return}const t=[];for(const e of r._viewers){const o=io.sockets.sockets.get(e);o&&t.push({socketId:e,userName:o.data.userName||"\u672A\u77E5",role:o.data.role||"viewer",isController:r.controlHolder===e})}n({ok:!0,viewers:t})})});const CONTROL_TIMEOUT=300*1e3;setInterval(()=>{for(const S of manager.listSessions())S.controlHolder&&S.lastInputTime&&Date.now()-S.lastInputTime>CONTROL_TIMEOUT&&(S.releaseControl(),io.emit("control-changed",{sessionId:S.id,holder:null,holderName:null}))},60*1e3);function showStartupInfo(){const S=httpServer.address().port;PORT=S;const f=getTailscaleIP(),c=`http://${f}:${S}/?token=${TOKEN}`;console.log(`
|
|
362
362
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`),console.log(" myhi \u2014 \u57FA\u4E8E Tailscale \u7684 Web \u7EC8\u7AEF"),console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),console.log(`
|
|
363
363
|
\u5730\u5740: http://${f}:${S}`),console.log(` \u5BC6\u7801: ${PASSWORD} (\u7F16\u8F91 ~/.myhi/password \u53EF\u4FEE\u6539)`),console.log(`
|
|
364
364
|
\u626B\u63CF\u4E8C\u7EF4\u7801\u5728\u624B\u673A\u4E0A\u6253\u5F00:
|