@wendongfly/myhi 1.3.120 → 1.3.121

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.min.js CHANGED
@@ -394,7 +394,7 @@ Content-Length: `+S+`\r
394
394
  [user]
395
395
  name = ${e}
396
396
  email = ${e}@myhi
397
- `;(0,external_fs_.writeFileSync)(v,_,{mode:384});try{await r(["remote","remove","origin"])}catch{}await r(["remote","add","origin",i])}if(await r(["add","-A"]),!await r(["status","--porcelain"]))return b.json({ok:!0,message:"\u6CA1\u6709\u9700\u8981\u63D0\u4EA4\u7684\u53D8\u66F4",pushed:!1});await r(["commit","-m",u]);const p=m||"main";try{await r(["push","-u","origin",p])}catch(s){if(s.message.includes("src refspec")||s.message.includes("does not match"))await r(["checkout","-b",p]),await r(["push","-u","origin",p]);else throw s}const f=await r(["log","--oneline","-1"]);b.json({ok:!0,message:`\u5DF2\u63D0\u4EA4\u5E76\u63A8\u9001: ${f}`,pushed:!0})}catch(p){b.json({ok:!1,error:p.message})}})),app.get("/api/git/info",checkAuth,((C,b)=>{const l=C.query.sessionId,i=l?manager.get(l):null;if(!i)return b.json({});const e=i.cwd||process.cwd();try{const c=(0,external_child_process_namespaceObject.execSync)("git remote get-url origin",{cwd:e,encoding:"utf8",timeout:5e3}).trim(),u=(0,external_child_process_namespaceObject.execSync)("git branch --show-current",{cwd:e,encoding:"utf8",timeout:5e3}).trim();let m="";const o=(0,external_path_.join)(e,".gitconfig");if((0,external_fs_.existsSync)(o)){const n=(0,external_fs_.readFileSync)(o,"utf8").match(/name\s*=\s*(.+)/);n&&(m=n[1].trim())}b.json({url:c,branch:u||"main",username:m})}catch{b.json({})}}));function skillFilePath(C,b){const l=b.split(":");return(0,external_path_.join)(C,...l.slice(0,-1),l[l.length-1]+".md")}app.get("/api/skills",checkAuth,((C,b)=>{const l=C.query.sessionId,e=(l?manager.get(l):null)?.cwd||process.cwd(),c=[],u=C.query.detail==="1";function m(o,n,a=""){if((0,external_fs_.existsSync)(o))try{for(const t of(0,external_fs_.readdirSync)(o,{withFileTypes:!0})){if(t.isDirectory()){m((0,external_path_.join)(o,t.name),n,a?`${a}:${t.name}`:t.name);continue}if(!t.name.endsWith(".md"))continue;const r=t.name.replace(/\.md$/,""),p=a?`${a}:${r}`:r,f=(0,external_path_.join)(o,t.name);try{const s=(0,external_fs_.readFileSync)(f,"utf8"),d=(s.split(`
397
+ `;(0,external_fs_.writeFileSync)(v,_,{mode:384});try{await r(["remote","remove","origin"])}catch{}await r(["remote","add","origin",i])}if(await r(["add","-A"]),!await r(["status","--porcelain"]))return b.json({ok:!0,message:"\u6CA1\u6709\u9700\u8981\u63D0\u4EA4\u7684\u53D8\u66F4",pushed:!1});await r(["commit","-m",u]);const p=m||"main";try{await r(["push","-u","origin",p])}catch(s){if(s.message.includes("src refspec")||s.message.includes("does not match"))await r(["checkout","-b",p]),await r(["push","-u","origin",p]);else throw s}const f=await r(["log","--oneline","-1"]);b.json({ok:!0,message:`\u5DF2\u63D0\u4EA4\u5E76\u63A8\u9001: ${f}`,pushed:!0})}catch(p){b.json({ok:!1,error:p.message})}})),app.get("/api/git/info",checkAuth,((C,b)=>{const l=C.query.sessionId,i=l?manager.get(l):null;if(!i)return b.json({});const e=i.cwd||process.cwd();try{const c=(0,external_child_process_namespaceObject.execSync)("git remote get-url origin",{cwd:e,encoding:"utf8",timeout:5e3}).trim(),u=(0,external_child_process_namespaceObject.execSync)("git branch --show-current",{cwd:e,encoding:"utf8",timeout:5e3}).trim();let m="";const o=(0,external_path_.join)(e,".gitconfig");if((0,external_fs_.existsSync)(o)){const n=(0,external_fs_.readFileSync)(o,"utf8").match(/name\s*=\s*(.+)/);n&&(m=n[1].trim())}b.json({url:c,branch:u||"main",username:m})}catch{b.json({})}}));function skillFilePath(C,b){const l=b.split(":");return(0,external_path_.join)(C,...l.slice(0,-1),l[l.length-1]+".md")}function taskCwdFromTitle(C,b){const l=b?(0,external_path_.resolve)((0,external_path_.normalize)(b)):process.env.MYHI_CWD||process.cwd(),i=String(C||"").trim().replace(/[\\/:*?"<>|]+/g,"_").replace(/^\.+/,"").slice(0,80).trim();return i?(0,external_path_.join)(l,i):l}app.get("/api/skills",checkAuth,((C,b)=>{const l=C.query.sessionId,e=(l?manager.get(l):null)?.cwd||process.cwd(),c=[],u=C.query.detail==="1";function m(o,n,a=""){if((0,external_fs_.existsSync)(o))try{for(const t of(0,external_fs_.readdirSync)(o,{withFileTypes:!0})){if(t.isDirectory()){m((0,external_path_.join)(o,t.name),n,a?`${a}:${t.name}`:t.name);continue}if(!t.name.endsWith(".md"))continue;const r=t.name.replace(/\.md$/,""),p=a?`${a}:${r}`:r,f=(0,external_path_.join)(o,t.name);try{const s=(0,external_fs_.readFileSync)(f,"utf8"),d=(s.split(`
398
398
  `).find((_=>_.trim()))||"").replace(/^#+\s*/,"").trim().slice(0,60),v={name:p,desc:d,source:n};u&&(v.content=s),c.push(v)}catch{}}}catch{}}m((0,external_path_.join)(e,".claude","commands"),"project"),m((0,external_path_.join)((0,external_os_.homedir)(),".claude","commands"),"user"),m(__nccwpck_require__.ab+"builtin-skills","builtin"),b.json({skills:c})})),app.get("/api/skills/content",checkAuth,((C,b)=>{const{name:l,sessionId:i}=C.query;if(!l)return b.status(400).json({error:"\u7F3A\u5C11 name"});const c=(i?manager.get(i):null)?.cwd||process.cwd(),u=[{dir:(0,external_path_.join)(c,".claude","commands"),source:"project"},{dir:(0,external_path_.join)((0,external_os_.homedir)(),".claude","commands"),source:"user"},{dir:__nccwpck_require__.ab+"builtin-skills",source:"builtin"}];for(const{dir:m,source:o}of u){const n=skillFilePath(m,l);if((0,external_fs_.existsSync)(n))try{return b.json({content:(0,external_fs_.readFileSync)(n,"utf8"),source:o})}catch{}}b.status(404).json({error:"\u6280\u80FD\u4E0D\u5B58\u5728"})})),app.post("/api/skills",checkAuth,express.json(),((C,b)=>{const{name:l,content:i,scope:e}=C.body||{};if(!l||!i)return b.status(400).json({error:"\u7F3A\u5C11 name \u6216 content"});if(!/^[\w:.-]+$/.test(l))return b.status(400).json({error:"\u540D\u79F0\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001-\u3001_\u3001.\u3001:"});const c=C.query.sessionId,m=(c?manager.get(c):null)?.cwd||process.cwd(),o=e==="project"?(0,external_path_.join)(m,".claude","commands"):(0,external_path_.join)((0,external_os_.homedir)(),".claude","commands"),n=skillFilePath(o,l);try{(0,external_fs_.mkdirSync)((0,external_path_.dirname)(n),{recursive:!0}),(0,external_fs_.writeFileSync)(n,i,"utf8"),b.json({ok:!0,path:n})}catch(a){b.status(500).json({error:a.message})}})),app.delete("/api/skills",checkAuth,express.json(),((C,b)=>{const{name:l,scope:i}=C.body||{};if(!l)return b.status(400).json({error:"\u7F3A\u5C11 name"});const e=C.query.sessionId,u=(e?manager.get(e):null)?.cwd||process.cwd(),m=i==="project"?(0,external_path_.join)(u,".claude","commands"):(0,external_path_.join)((0,external_os_.homedir)(),".claude","commands"),o=skillFilePath(m,l);try{(0,external_fs_.existsSync)(o)&&(0,external_fs_.unlinkSync)(o),b.json({ok:!0})}catch(n){b.status(500).json({error:n.message})}})),app.post("/api/skills/scan-git",checkAuth,express.json(),((C,b)=>{const{url:l,username:i,password:e}=C.body||{};if(!l)return b.status(400).json({error:"\u7F3A\u5C11 Git \u4ED3\u5E93\u5730\u5740"});let c=l;if(i&&e&&/^https?:\/\//.test(l))try{const t=new URL(l);t.username=encodeURIComponent(i),t.password=encodeURIComponent(e),c=t.toString()}catch{}const u=(0,external_path_.join)((0,external_os_.tmpdir)(),"myhi-skill-"+Date.now());try{(0,external_child_process_namespaceObject.execSync)(`git clone --depth 1 "${c}" "${u}"`,{timeout:6e4,stdio:"pipe",encoding:"utf8",env:{...process.env,GIT_TERMINAL_PROMPT:"0"}})}catch(t){const r=(t.stderr||"").trim(),p=(t.stdout||"").trim(),g=(r||p||t.message||"\u672A\u77E5\u9519\u8BEF").split(`
399
399
  `).filter((d=>d.trim())).slice(-3).join(" ").slice(0,200);return b.status(400).json({error:"\u514B\u9686\u5931\u8D25: "+g})}const m=[];function o(t,r=""){if((0,external_fs_.existsSync)(t))try{for(const p of(0,external_fs_.readdirSync)(t,{withFileTypes:!0})){if(p.name.startsWith("."))continue;if(p.isDirectory()){o((0,external_path_.join)(t,p.name),r?`${r}:${p.name}`:p.name);continue}if(!p.name.endsWith(".md")||["README.MD","CHANGELOG.MD","LICENSE.MD","CONTRIBUTING.MD"].includes(p.name.toUpperCase()))continue;const f=p.name.replace(/\.md$/,""),s=r?`${r}:${f}`:f,g=(0,external_path_.join)(t,p.name);try{const d=(0,external_fs_.readFileSync)(g,"utf8"),_=(d.split(`
400
400
  `).find((h=>h.trim()))||"").replace(/^#+\s*/,"").trim().slice(0,80);m.push({name:s,desc:_,content:d})}catch{}}}catch{}}const n=(0,external_path_.join)(u,"commands"),a=(0,external_path_.join)(u,".claude","commands");(0,external_fs_.existsSync)(n)?o(n):(0,external_fs_.existsSync)(a)?o(a):o(u);try{(0,external_child_process_namespaceObject.execSync)(process.platform==="win32"?`rmdir /s /q ${JSON.stringify(u)}`:`rm -rf ${JSON.stringify(u)}`,{timeout:1e4,stdio:"pipe"})}catch{}if(!m.length)return b.json({skills:[],message:"\u4ED3\u5E93\u4E2D\u672A\u627E\u5230\u6280\u80FD\u6587\u4EF6(.md)"});b.json({skills:m})})),app.get("/api/memory",checkAuth,((C,b)=>{const l=C.query.sessionId,i=C.query.scope==="all"?"all":"project",e=l?manager.get(l):null;if(!e)return b.json({files:[],scope:i});const c=e.cwd||process.cwd(),u=String(c).replace(/[^a-zA-Z0-9]/g,"-"),m=[],o=(0,external_path_.join)(c,"CLAUDE.md");if((0,external_fs_.existsSync)(o))try{m.push({name:"CLAUDE.md",content:(0,external_fs_.readFileSync)(o,"utf8")})}catch{}const n=(0,external_path_.join)(c,".claude","settings.json");if((0,external_fs_.existsSync)(n))try{m.push({name:".claude/settings.json",content:(0,external_fs_.readFileSync)(n,"utf8")})}catch{}if(i==="all"){const r=(0,external_path_.join)((0,external_os_.homedir)(),".claude","CLAUDE.md");if((0,external_fs_.existsSync)(r))try{m.push({name:"~/.claude/CLAUDE.md",content:(0,external_fs_.readFileSync)(r,"utf8")})}catch{}}const a=[(0,external_path_.join)((0,external_os_.homedir)(),".claude","memory")],t=(0,external_path_.join)((0,external_os_.homedir)(),".claude","projects");if((0,external_fs_.existsSync)(t))try{for(const r of(0,external_fs_.readdirSync)(t)){if(i!=="all"&&r!==u)continue;const p=(0,external_path_.join)(t,r,"memory");if((0,external_fs_.existsSync)(p)){const f=(0,external_path_.join)(t,r,"CLAUDE.md");if((0,external_fs_.existsSync)(f))try{m.push({name:`.claude/projects/${r}/CLAUDE.md`,content:(0,external_fs_.readFileSync)(f,"utf8")})}catch{}try{for(const s of(0,external_fs_.readdirSync)(p)){if(!s.endsWith(".md"))continue;const g=(0,external_path_.join)(p,s);try{m.push({name:`memory/${s}`,content:(0,external_fs_.readFileSync)(g,"utf8")})}catch{}}}catch{}}}}catch{}if(i==="all"){for(const r of a)if((0,external_fs_.existsSync)(r))try{for(const p of(0,external_fs_.readdirSync)(r)){if(!p.endsWith(".md"))continue;const f=(0,external_path_.join)(r,p);try{m.push({name:`~/.claude/memory/${p}`,content:(0,external_fs_.readFileSync)(f,"utf8")})}catch{}}}catch{}}b.json({files:m,scope:i})}));const _SAFE_MD=/^[\w.\- ]+\.md$/;function memoryTarget(C,b){const l=(0,external_os_.homedir)();if(typeof b!="string"||b.includes(".."))return null;if(b.startsWith("memory/")){const e=b.slice(7);if(!_SAFE_MD.test(e))return null;const c=String(C).replace(/[^a-zA-Z0-9]/g,"-");return{path:(0,external_path_.join)(l,".claude","projects",c,"memory",e),deletable:!0}}if(b.startsWith("~/.claude/memory/")){const e=b.slice(17);return _SAFE_MD.test(e)?{path:(0,external_path_.join)(l,".claude","memory",e),deletable:!0}:null}if(b==="~/.claude/CLAUDE.md")return{path:(0,external_path_.join)(l,".claude","CLAUDE.md"),deletable:!1};if(b==="CLAUDE.md")return{path:(0,external_path_.join)(C,"CLAUDE.md"),deletable:!1};if(b===".claude/settings.json")return{path:(0,external_path_.join)(C,".claude","settings.json"),deletable:!1};const i=b.match(/^\.claude\/projects\/([\w.\-]+)\/CLAUDE\.md$/);return i?{path:(0,external_path_.join)(l,".claude","projects",i[1],"CLAUDE.md"),deletable:!1}:null}app.post("/api/memory/save",checkAuth,express.json(),((C,b)=>{const{sessionId:l,name:i,content:e}=C.body||{},c=l?manager.get(l):null,u=memoryTarget(c?.cwd||process.cwd(),i);if(!u)return b.status(400).json({error:"\u4E0D\u652F\u6301\u7F16\u8F91\u8BE5\u6587\u4EF6"});if(typeof e!="string")return b.status(400).json({error:"\u7F3A\u5C11\u5185\u5BB9"});try{(0,external_fs_.mkdirSync)((0,external_path_.dirname)(u.path),{recursive:!0}),(0,external_fs_.writeFileSync)(u.path,e,"utf8"),b.json({ok:!0})}catch(m){b.status(500).json({error:m.message})}})),app.post("/api/memory/delete",checkAuth,express.json(),((C,b)=>{const{sessionId:l,name:i}=C.body||{},e=l?manager.get(l):null,c=memoryTarget(e?.cwd||process.cwd(),i);if(!c||!c.deletable)return b.status(400).json({error:"\u8BE5\u6587\u4EF6\u4E0D\u5141\u8BB8\u5220\u9664\uFF08\u53EA\u5141\u8BB8\u5220 memory/*.md\uFF09"});try{(0,external_fs_.existsSync)(c.path)&&(0,external_fs_.unlinkSync)(c.path),b.json({ok:!0})}catch(u){b.status(500).json({error:u.message})}}));const _adminTokens=new Set,SERVER_START_TIME=Date.now();function checkAdminAuth(C,b,l){const i=C.headers.authorization;if(i&&i.startsWith("Bearer ")&&_adminTokens.has(i.slice(7)))return l();b.status(401).json({error:"\u672A\u6388\u6743"})}app.post("/api/admin/login",express.json(),((C,b)=>{const{password:l}=C.body||{};if(l===PASSWORD){const i=(0,external_crypto_.randomBytes)(16).toString("hex");return _adminTokens.add(i),b.json({ok:!0,token:i})}b.json({ok:!1,error:"\u5BC6\u7801\u9519\u8BEF"})})),app.get("/api/admin/status",checkAdminAuth,(async(C,b)=>{const l=await checkLatestVersion();loadUsers();const i=[],e=new Set;for(const[,u]of io.sockets.sockets)!u.data.userName||e.has(u.data.userName)||(e.add(u.data.userName),i.push({name:u.data.userName,role:u.data.role||"viewer"}));const c=manager.listSessions().filter((u=>u.alive!==!1)).map((u=>({id:u.id,title:u.title,mode:u.mode||"pty",owner:u.owner,viewers:u.viewerCount||0})));b.json({version:{current:getPkgVersion(),latest:l||getPkgVersion(),updateAvailable:l&&l!==getPkgVersion()},onlineUsers:i,sessions:c,users:listUsers(),uptime:Math.floor((Date.now()-SERVER_START_TIME)/1e3)})})),app.post("/api/admin/upgrade",checkAdminAuth,(async(C,b)=>{try{await execAsync(getNpmUpgradeCmd(),{encoding:"utf8",timeout:12e4}),console.log("[myhi] \u5347\u7EA7\u5B8C\u6210"),b.json({ok:!0,message:"\u5347\u7EA7\u5B8C\u6210\uFF0C\u670D\u52A1\u5C06\u81EA\u52A8\u91CD\u542F..."}),setTimeout((()=>restartService()),500)}catch(l){const i=(l.stderr||l.stdout||l.message||"").split(`
@@ -418,7 +418,7 @@ ${l}
418
418
  3. \u8BED\u8A00\u81EA\u7136\u6D41\u7545\uFF0C\u4E0D\u9700\u8981\u5206\u6761\u5217\u9879\uFF0C\u4FDD\u6301\u8FDE\u8D2F\u6BB5\u843D
419
419
  4. \u4FDD\u7559\u6240\u6709\u5177\u4F53\u7684\u6570\u5B57\u3001\u540D\u79F0\u7B49\u5173\u952E\u4FE1\u606F
420
420
 
421
- \u53EA\u8F93\u51FA\u6574\u7406\u540E\u7684\u6587\u5B57\uFF0C\u4E0D\u9700\u8981\u4EFB\u4F55\u89E3\u91CA\u6216\u6807\u9898\u3002\u5FC5\u987B\u7528\u4E2D\u6587\u8F93\u51FA\u3002`;try{const e=await new Promise(((c,u)=>{let m="",o="";const n=process.platform==="win32"?(0,external_fs_.existsSync)((0,external_path_.join)((0,external_os_.homedir)(),"AppData","Roaming","npm","claude.cmd"))?(0,external_path_.join)((0,external_os_.homedir)(),"AppData","Roaming","npm","claude.cmd"):(0,external_path_.join)((0,external_os_.homedir)(),".claude","local","claude.cmd"):"claude",a=process.platform==="win32"?process.env.ComSpec||"cmd.exe":n,t=process.platform==="win32"?["/c",n,"--print"]:["--print"],r=(0,external_child_process_namespaceObject.spawn)(a,t,{stdio:["pipe","pipe","pipe"],env:{...process.env,NO_COLOR:"1"},timeout:9e4});r.stdin.write(i,"utf8"),r.stdin.end(),r.stdout.on("data",(p=>{m+=p.toString()})),r.stderr.on("data",(p=>{o+=p.toString()})),r.on("close",(p=>{p!==0&&!m.trim()?u(new Error(o||`exit ${p}`)):c(m.trim())})),r.on("error",u)}));b.json({requirement:e})}catch(e){b.status(500).json({error:e.message})}})),app.get("/qr/:sessionId",checkAuth,(async(C,b)=>{const l=getTailscaleIP(),i=(0,external_crypto_.randomBytes)(16).toString("hex");userSessions.set(i,{role:"admin",name:"\u626B\u7801\u7528\u6237",onetime:!0,lastUsed:Date.now()});const c=`${httpsServer?"https":"http"}://${l}:${PORT}/terminal/${C.params.sessionId}?token=${i}`;try{const u=await lib.toString(c,{type:"svg"});b.setHeader("Content-Type","image/svg+xml"),b.send(u)}catch(u){b.status(500).send(u.message)}})),io.use(((C,b)=>{const l=C.handshake.headers.cookie;if(hasValidSession(l)){const e=getUserInfo(l);return C.data.role=e?.role||"admin",C.data.userName=e?.name||"\u7528\u6237",C.data.dir=e?.dir||null,b()}const i=C.handshake.auth?.password;if(i){loadUsers();const e=lookupUser(i);if(e)return C.data.role="operator",C.data.userName=e.name,C.data.dir=e.dir,b()}if((C.handshake.auth?.token||C.handshake.query?.token)===TOKEN)return C.data.role="admin",C.data.userName="\u7BA1\u7406\u5458",b();b(new Error("\u672A\u6388\u6743"))}));const EXCLUSIVE_RELEASE_DELAY=120*1e3;let _exclusiveReleaseTimer=null;function checkExclusiveRelease(){if(!isExclusiveMode()||!activeUser)return;let C=!1;for(const[,b]of io.sockets.sockets)if(b.data.userName===activeUser.name){C=!0;break}if(C){_exclusiveReleaseTimer&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);return}_exclusiveReleaseTimer||(_exclusiveReleaseTimer=setTimeout((()=>{if(_exclusiveReleaseTimer=null,!!activeUser){for(const[,b]of io.sockets.sockets)if(b.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 b of activeUser.tokens)userSessions.delete(b);activeUser=null}}),EXCLUSIVE_RELEASE_DELAY))}let _broadcastTimer=null;function broadcastSessions(){_broadcastTimer||(_broadcastTimer=setTimeout((()=>{_broadcastTimer=null;for(const[,C]of io.sockets.sockets)C.emit("sessions",manager.list(C.data.userName,C.data.role==="admin"))}),100))}io.on("connection",(C=>{const b=C.handshake.address?.replace("::ffff:","")||"?";console.log(`[\u8FDE\u63A5] ${C.data.userName}(${C.data.role}) \u4ECE ${b} \u63A5\u5165 id=${C.id}`),_exclusiveReleaseTimer&&activeUser&&C.data.userName===activeUser.name&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);let l=null,i=null,e=null,c=null,u=null;function m(){l&&(l.isController(C.id)&&(l.releaseControl(),io.emit("control-changed",{sessionId:l.id,holder:null,holderName:null})),l.removeViewer(C.id),i&&l.off("data",i),e&&l.off("agent:message",e),c&&l.off("agent:busy",c),u&&l.off("agent:error",u),i=null,e=null,c=null,u=null)}C.on("join",(o=>{const n=manager.get(o);if(!n){C.emit("error",{message:`\u4F1A\u8BDD ${o} \u672A\u627E\u5230`});return}const a=l?.id===o;if(m(),l=n,l.addViewer(C.id,C.data.userName),n.mode==="agent"?(e=t=>C.emit("agent:message",t),l.on("agent:message",e),c=t=>C.emit("agent:busy",t),l.on("agent:busy",c),u=t=>C.emit("agent:error",t),l.on("agent:error",u)):(i=t=>C.emit("output",t),l.on("data",i),l.once("exit",(t=>{C.emit("session-exit",{code:t}),i&&l?.off("data",i)})),spawnLocalTerminal(o,n.title)),console.log(`[\u52A0\u5165] ${C.data.userName} \u52A0\u5165\u4F1A\u8BDD "${n.title}" (${o}) \u6A21\u5F0F=${n.mode||"pty"}${a?" [\u91CD\u65B0\u8BA2\u9605]":""}`),C.emit("joined",{...n.toJSON(),role:C.data.role}),!a){if(n.mode==="agent")n._history?.length&&C.emit("agent:history",n._history);else if(n._scrollback?.length){const t=n._scrollback;if(t.length<=4096)C.emit("output",t);else{let r=0;(function p(){r>=t.length||(C.emit("output",t.slice(r,r+4096)),r+=4096,setImmediate(p))})()}}}broadcastSessions()})),C.on("disconnect",(()=>{console.log(`[\u65AD\u5F00] ${C.data.userName} \u79BB\u5F00\u4F1A\u8BDD "${l?.title||"?"}" id=${C.id}`),m(),broadcastSessions(),checkExclusiveRelease(),manager.persist()})),C.on("agent:query",(async({prompt:o}={})=>{if(!l||l.mode!=="agent"){C.emit("agent:error",{message:"\u5F53\u524D\u4E0D\u662F Agent \u6A21\u5F0F\u4F1A\u8BDD"});return}if(!l.isController(C.id)){C.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}if(l.isBusy){C.emit("agent:error",{message:"\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210"});return}l.lastInputTime=Date.now();try{await l.query(o)}catch(n){console.error("[agent:query] \u9519\u8BEF:",n.message);try{C.connected&&C.emit("agent:error",{message:n.message})}catch{}}})),C.on("agent:interrupt",(()=>{!l||l.mode!=="agent"||(l.isController(C.id)&&(l.lastInputTime=Date.now()),l.interrupt())})),C.on("create-agent",((o,n)=>{if(!hasPermission(C.data.role,"operator")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(C.data.dir){const t=(0,external_path_.resolve)((0,external_path_.normalize)(C.data.dir)),r=o?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(o.cwd)):null;if(r&&r!==t&&!r.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}r||(o={...o,cwd:t})}const a=o?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(a))try{(0,external_fs_.mkdirSync)(a,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${a}`)}catch(t){typeof n=="function"&&n({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${t.message}`});return}try{const t=manager.createAgent({...o,owner:C.data.userName,userDir:C.data.dir});console.log(`[\u4F1A\u8BDD] ${C.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})}})),C.on("input",(o=>{if(!(o==null||!l)&&l.mode!=="agent"){if(!l.isController(C.id)){C.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}l.lastInputTime=Date.now(),l.write(o)}})),C.on("take-control",(({sessionId:o}={})=>{const n=o?manager.get(o):l;if(n){if(!hasPermission(C.data.role,"operator")){C.emit("control-denied",{reason:"\u4F60\u7684\u89D2\u8272\u6CA1\u6709\u63A7\u5236\u6743\u9650"});return}if(n.controlHolder&&n.controlHolder!==C.id){const a=n.controlHolderName===C.data.userName;if(C.data.role!=="admin"&&!a){C.emit("control-denied",{reason:"\u5176\u4ED6\u7528\u6237\u6B63\u5728\u63A7\u5236\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u91CA\u653E"});return}}n.takeControl(C.id,C.data.userName),console.log(`[\u63A7\u5236] ${C.data.userName} \u83B7\u53D6\u4F1A\u8BDD "${n.title}" \u7684\u63A7\u5236\u6743`),io.emit("control-changed",{sessionId:n.id,holder:C.id,holderName:C.data.userName})}})),C.on("release-control",(({sessionId:o}={})=>{const n=o?manager.get(o):l;!n||!n.isController(C.id)||(console.log(`[\u63A7\u5236] ${C.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}))})),C.on("set-mode",(({sessionId:o,mode:n}={})=>{const a=o?manager.get(o):l;if(a){if(a.mode==="agent"&&a.setPermissionMode){a.setPermissionMode(n);const t=a.permissionMode;t!==n&&console.log(`[\u6A21\u5F0F] set-mode \u6536\u5230\u65E0\u6548\u6A21\u5F0F "${n}"\uFF0C\u5DF2\u5F52\u4E00\u5316\u4E3A ${t}`),console.log(`[\u6A21\u5F0F] ${C.data.userName} \u5207\u6362\u4F1A\u8BDD "${a.title}" \u4E3A ${t}`),io.emit("mode-changed",{sessionId:a.id,mode:t})}else a.permissionMode=n,io.emit("mode-changed",{sessionId:a.id,mode:n});manager.persist()}})),C.on("rename",(({sessionId:o,title:n}={})=>{const a=o?manager.get(o):l;!a||!n||(a.title=n,io.emit("session-renamed",{sessionId:a.id,title:n}),broadcastSessions(),manager.persist())})),C.on("set-tags",(({sessionId:o,tags:n}={})=>{const a=o?manager.get(o):l;!a||!Array.isArray(n)||(a.tags=[...new Set(n.map((t=>String(t).trim())).filter(Boolean).map((t=>t.slice(0,24))))].slice(0,12),io.emit("session-tagged",{sessionId:a.id,tags:a.tags}),broadcastSessions(),manager.persist())})),C.on("resize",(({cols:o,rows:n})=>l?.resize(o,n))),C.on("list",(()=>C.emit("sessions",manager.list(C.data.userName,C.data.role==="admin")))),C.on("dirs",((o,n)=>{if(typeof n!="function")return;const a=C.data.dir?(0,external_path_.resolve)((0,external_path_.normalize)(C.data.dir)):null,t=process.platform==="win32"?"\\":"/";let r=(o||a||process.env.MYHI_CWD||(0,external_os_.homedir)()).replace(/[/\\]+$/,"")||(0,external_os_.homedir)();process.platform==="win32"&&/^[A-Za-z]:$/.test(r)&&(r+="\\");const p=(0,external_path_.resolve)((0,external_path_.normalize)(r));a&&p!==a&&!p.startsWith(a+t)&&(r=a);try{const f=(0,external_fs_.readdirSync)(r,{withFileTypes:!0}).filter((v=>v.isDirectory()&&v.name!==".git")).map((v=>({name:v.name,path:r.replace(/[/\\]+$/,"")+t+v.name}))).sort(((v,_)=>v.name.localeCompare(_.name))),s=(0,external_path_.join)(r,".."),g=(0,external_path_.resolve)((0,external_path_.normalize)(s)),d=!a||g===a||g.startsWith(a+t);n({ok:!0,current:r,parent:d&&s!==r?s:null,dirs:f})}catch(f){n({ok:!1,error:f.message})}})),C.on("create",((o,n)=>{if(!hasPermission(C.data.role,"operator")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(C.data.dir){const t=(0,external_path_.resolve)((0,external_path_.normalize)(C.data.dir)),r=o?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(o.cwd)):null;if(r&&r!==t&&!r.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}r||(o={...o,cwd:t})}const a=o?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(a))try{(0,external_fs_.mkdirSync)(a,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${a}`)}catch(t){typeof n=="function"&&n({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${t.message}`});return}try{const t=manager.create({...o,owner:C.data.userName,userDir:C.data.dir});console.log(`[\u4F1A\u8BDD] ${C.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})}})),C.on("kill",(o=>{if(!hasPermission(C.data.role,"operator")){C.emit("error",{message:"\u6CA1\u6709\u5220\u9664\u4F1A\u8BDD\u7684\u6743\u9650"});return}console.log(`[\u4F1A\u8BDD] ${C.data.userName} \u5220\u9664\u4F1A\u8BDD ${o}`),manager.kill(o),_autoSpawned.delete(o),broadcastSessions()})),C.on("kick-user",(({socketId:o,sessionId:n}={},a)=>{if(!hasPermission(C.data.role,"admin")){typeof a=="function"&&a({ok:!1,error:"\u6CA1\u6709\u8E22\u51FA\u7528\u6237\u7684\u6743\u9650"});return}const t=io.sockets.sockets.get(o);if(!t){typeof a=="function"&&a({ok:!1,error:"\u76EE\u6807\u7528\u6237\u4E0D\u5728\u7EBF"});return}const r=t.data.userName||"\u672A\u77E5";console.log(`[\u8E22\u51FA] ${C.data.userName} \u8E22\u51FA\u4E86\u7528\u6237 ${r} (${o})`),t.emit("kicked",{reason:`\u4F60\u5DF2\u88AB\u7BA1\u7406\u5458 ${C.data.userName} \u8E22\u51FA`}),t.disconnect(!0),typeof a=="function"&&a({ok:!0,name:r})})),C.on("list-viewers",(({sessionId:o}={},n)=>{if(typeof n!="function")return;const a=o?manager.get(o):l;if(!a){n({ok:!1,error:"\u4F1A\u8BDD\u4E0D\u5B58\u5728"});return}const t=[];for(const r of a._viewers){const p=io.sockets.sockets.get(r);p&&t.push({socketId:r,userName:p.data.userName||"\u672A\u77E5",role:p.data.role||"viewer",isController:a.controlHolder===r})}n({ok:!0,viewers:t})}))}));const CONTROL_TIMEOUT=(Number(process.env.MYHI_CONTROL_TIMEOUT)||300)*1e3,CONTROL_SWEEP=Math.min(60*1e3,CONTROL_TIMEOUT);function shouldReleaseIdle(C){if(!C.controlHolder)return!1;if(!io.sockets.sockets.get(C.controlHolder))return!0;if(!C.lastInputTime||Date.now()-C.lastInputTime<=CONTROL_TIMEOUT||C.isBusy)return!1;for(const b of C._viewers||[])if(b!==C.controlHolder&&io.sockets.sockets.has(b))return!0;return!1}setInterval((()=>{for(const C of manager.listSessions()){shouldReleaseIdle(C)&&(C.releaseControl(),io.emit("control-changed",{sessionId:C.id,holder:null,holderName:null}));for(const b of C._viewers)io.sockets.sockets.has(b)||C.removeViewer(b)}}),CONTROL_SWEEP);function showStartupInfo(){PORT=(httpsServer||httpServer).address()?.port||PORT;const b=getTailscaleIP(),i=`${httpsServer?"https":"http"}://${b}:${PORT}`;console.log(`
421
+ \u53EA\u8F93\u51FA\u6574\u7406\u540E\u7684\u6587\u5B57\uFF0C\u4E0D\u9700\u8981\u4EFB\u4F55\u89E3\u91CA\u6216\u6807\u9898\u3002\u5FC5\u987B\u7528\u4E2D\u6587\u8F93\u51FA\u3002`;try{const e=await new Promise(((c,u)=>{let m="",o="";const n=process.platform==="win32"?(0,external_fs_.existsSync)((0,external_path_.join)((0,external_os_.homedir)(),"AppData","Roaming","npm","claude.cmd"))?(0,external_path_.join)((0,external_os_.homedir)(),"AppData","Roaming","npm","claude.cmd"):(0,external_path_.join)((0,external_os_.homedir)(),".claude","local","claude.cmd"):"claude",a=process.platform==="win32"?process.env.ComSpec||"cmd.exe":n,t=process.platform==="win32"?["/c",n,"--print"]:["--print"],r=(0,external_child_process_namespaceObject.spawn)(a,t,{stdio:["pipe","pipe","pipe"],env:{...process.env,NO_COLOR:"1"},timeout:9e4});r.stdin.write(i,"utf8"),r.stdin.end(),r.stdout.on("data",(p=>{m+=p.toString()})),r.stderr.on("data",(p=>{o+=p.toString()})),r.on("close",(p=>{p!==0&&!m.trim()?u(new Error(o||`exit ${p}`)):c(m.trim())})),r.on("error",u)}));b.json({requirement:e})}catch(e){b.status(500).json({error:e.message})}})),app.get("/qr/:sessionId",checkAuth,(async(C,b)=>{const l=getTailscaleIP(),i=(0,external_crypto_.randomBytes)(16).toString("hex");userSessions.set(i,{role:"admin",name:"\u626B\u7801\u7528\u6237",onetime:!0,lastUsed:Date.now()});const c=`${httpsServer?"https":"http"}://${l}:${PORT}/terminal/${C.params.sessionId}?token=${i}`;try{const u=await lib.toString(c,{type:"svg"});b.setHeader("Content-Type","image/svg+xml"),b.send(u)}catch(u){b.status(500).send(u.message)}})),io.use(((C,b)=>{const l=C.handshake.headers.cookie;if(hasValidSession(l)){const e=getUserInfo(l);return C.data.role=e?.role||"admin",C.data.userName=e?.name||"\u7528\u6237",C.data.dir=e?.dir||null,b()}const i=C.handshake.auth?.password;if(i){loadUsers();const e=lookupUser(i);if(e)return C.data.role="operator",C.data.userName=e.name,C.data.dir=e.dir,b()}if((C.handshake.auth?.token||C.handshake.query?.token)===TOKEN)return C.data.role="admin",C.data.userName="\u7BA1\u7406\u5458",b();b(new Error("\u672A\u6388\u6743"))}));const EXCLUSIVE_RELEASE_DELAY=120*1e3;let _exclusiveReleaseTimer=null;function checkExclusiveRelease(){if(!isExclusiveMode()||!activeUser)return;let C=!1;for(const[,b]of io.sockets.sockets)if(b.data.userName===activeUser.name){C=!0;break}if(C){_exclusiveReleaseTimer&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);return}_exclusiveReleaseTimer||(_exclusiveReleaseTimer=setTimeout((()=>{if(_exclusiveReleaseTimer=null,!!activeUser){for(const[,b]of io.sockets.sockets)if(b.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 b of activeUser.tokens)userSessions.delete(b);activeUser=null}}),EXCLUSIVE_RELEASE_DELAY))}let _broadcastTimer=null;function broadcastSessions(){_broadcastTimer||(_broadcastTimer=setTimeout((()=>{_broadcastTimer=null;for(const[,C]of io.sockets.sockets)C.emit("sessions",manager.list(C.data.userName,C.data.role==="admin"))}),100))}io.on("connection",(C=>{const b=C.handshake.address?.replace("::ffff:","")||"?";console.log(`[\u8FDE\u63A5] ${C.data.userName}(${C.data.role}) \u4ECE ${b} \u63A5\u5165 id=${C.id}`),_exclusiveReleaseTimer&&activeUser&&C.data.userName===activeUser.name&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);let l=null,i=null,e=null,c=null,u=null;function m(){l&&(l.isController(C.id)&&(l.releaseControl(),io.emit("control-changed",{sessionId:l.id,holder:null,holderName:null})),l.removeViewer(C.id),i&&l.off("data",i),e&&l.off("agent:message",e),c&&l.off("agent:busy",c),u&&l.off("agent:error",u),i=null,e=null,c=null,u=null)}C.on("join",(o=>{const n=manager.get(o);if(!n){C.emit("error",{message:`\u4F1A\u8BDD ${o} \u672A\u627E\u5230`});return}const a=l?.id===o;if(m(),l=n,l.addViewer(C.id,C.data.userName),n.mode==="agent"?(e=t=>C.emit("agent:message",t),l.on("agent:message",e),c=t=>C.emit("agent:busy",t),l.on("agent:busy",c),u=t=>C.emit("agent:error",t),l.on("agent:error",u)):(i=t=>C.emit("output",t),l.on("data",i),l.once("exit",(t=>{C.emit("session-exit",{code:t}),i&&l?.off("data",i)})),spawnLocalTerminal(o,n.title)),console.log(`[\u52A0\u5165] ${C.data.userName} \u52A0\u5165\u4F1A\u8BDD "${n.title}" (${o}) \u6A21\u5F0F=${n.mode||"pty"}${a?" [\u91CD\u65B0\u8BA2\u9605]":""}`),C.emit("joined",{...n.toJSON(),role:C.data.role}),!a){if(n.mode==="agent")n._history?.length&&C.emit("agent:history",n._history);else if(n._scrollback?.length){const t=n._scrollback;if(t.length<=4096)C.emit("output",t);else{let r=0;(function p(){r>=t.length||(C.emit("output",t.slice(r,r+4096)),r+=4096,setImmediate(p))})()}}}broadcastSessions()})),C.on("disconnect",(()=>{console.log(`[\u65AD\u5F00] ${C.data.userName} \u79BB\u5F00\u4F1A\u8BDD "${l?.title||"?"}" id=${C.id}`),m(),broadcastSessions(),checkExclusiveRelease(),manager.persist()})),C.on("agent:query",(async({prompt:o}={})=>{if(!l||l.mode!=="agent"){C.emit("agent:error",{message:"\u5F53\u524D\u4E0D\u662F Agent \u6A21\u5F0F\u4F1A\u8BDD"});return}if(!l.isController(C.id)){C.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}if(l.isBusy){C.emit("agent:error",{message:"\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210"});return}l.lastInputTime=Date.now();try{await l.query(o)}catch(n){console.error("[agent:query] \u9519\u8BEF:",n.message);try{C.connected&&C.emit("agent:error",{message:n.message})}catch{}}})),C.on("agent:interrupt",(()=>{!l||l.mode!=="agent"||(l.isController(C.id)&&(l.lastInputTime=Date.now()),l.interrupt())})),C.on("create-agent",((o,n)=>{if(!hasPermission(C.data.role,"operator")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(!o?.cwd&&o?.nestByTitle&&(o={...o,cwd:taskCwdFromTitle(o?.title,C.data.dir)}),C.data.dir){const t=(0,external_path_.resolve)((0,external_path_.normalize)(C.data.dir)),r=o?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(o.cwd)):null;if(r&&r!==t&&!r.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}r||(o={...o,cwd:t})}const a=o?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(a))try{(0,external_fs_.mkdirSync)(a,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${a}`)}catch(t){typeof n=="function"&&n({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${t.message}`});return}try{const t=manager.createAgent({...o,owner:C.data.userName,userDir:C.data.dir});console.log(`[\u4F1A\u8BDD] ${C.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})}})),C.on("input",(o=>{if(!(o==null||!l)&&l.mode!=="agent"){if(!l.isController(C.id)){C.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}l.lastInputTime=Date.now(),l.write(o)}})),C.on("take-control",(({sessionId:o}={})=>{const n=o?manager.get(o):l;if(n){if(!hasPermission(C.data.role,"operator")){C.emit("control-denied",{reason:"\u4F60\u7684\u89D2\u8272\u6CA1\u6709\u63A7\u5236\u6743\u9650"});return}if(n.controlHolder&&n.controlHolder!==C.id){const a=n.controlHolderName===C.data.userName;if(C.data.role!=="admin"&&!a){C.emit("control-denied",{reason:"\u5176\u4ED6\u7528\u6237\u6B63\u5728\u63A7\u5236\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u91CA\u653E"});return}}n.takeControl(C.id,C.data.userName),console.log(`[\u63A7\u5236] ${C.data.userName} \u83B7\u53D6\u4F1A\u8BDD "${n.title}" \u7684\u63A7\u5236\u6743`),io.emit("control-changed",{sessionId:n.id,holder:C.id,holderName:C.data.userName})}})),C.on("release-control",(({sessionId:o}={})=>{const n=o?manager.get(o):l;!n||!n.isController(C.id)||(console.log(`[\u63A7\u5236] ${C.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}))})),C.on("set-mode",(({sessionId:o,mode:n}={})=>{const a=o?manager.get(o):l;if(a){if(a.mode==="agent"&&a.setPermissionMode){a.setPermissionMode(n);const t=a.permissionMode;t!==n&&console.log(`[\u6A21\u5F0F] set-mode \u6536\u5230\u65E0\u6548\u6A21\u5F0F "${n}"\uFF0C\u5DF2\u5F52\u4E00\u5316\u4E3A ${t}`),console.log(`[\u6A21\u5F0F] ${C.data.userName} \u5207\u6362\u4F1A\u8BDD "${a.title}" \u4E3A ${t}`),io.emit("mode-changed",{sessionId:a.id,mode:t})}else a.permissionMode=n,io.emit("mode-changed",{sessionId:a.id,mode:n});manager.persist()}})),C.on("rename",(({sessionId:o,title:n}={})=>{const a=o?manager.get(o):l;!a||!n||(a.title=n,io.emit("session-renamed",{sessionId:a.id,title:n}),broadcastSessions(),manager.persist())})),C.on("set-tags",(({sessionId:o,tags:n}={})=>{const a=o?manager.get(o):l;!a||!Array.isArray(n)||(a.tags=[...new Set(n.map((t=>String(t).trim())).filter(Boolean).map((t=>t.slice(0,24))))].slice(0,12),io.emit("session-tagged",{sessionId:a.id,tags:a.tags}),broadcastSessions(),manager.persist())})),C.on("resize",(({cols:o,rows:n})=>l?.resize(o,n))),C.on("list",(()=>C.emit("sessions",manager.list(C.data.userName,C.data.role==="admin")))),C.on("dirs",((o,n)=>{if(typeof n!="function")return;const a=C.data.dir?(0,external_path_.resolve)((0,external_path_.normalize)(C.data.dir)):null,t=process.platform==="win32"?"\\":"/";let r=(o||a||process.env.MYHI_CWD||(0,external_os_.homedir)()).replace(/[/\\]+$/,"")||(0,external_os_.homedir)();process.platform==="win32"&&/^[A-Za-z]:$/.test(r)&&(r+="\\");const p=(0,external_path_.resolve)((0,external_path_.normalize)(r));a&&p!==a&&!p.startsWith(a+t)&&(r=a);try{const f=(0,external_fs_.readdirSync)(r,{withFileTypes:!0}).filter((v=>v.isDirectory()&&v.name!==".git")).map((v=>({name:v.name,path:r.replace(/[/\\]+$/,"")+t+v.name}))).sort(((v,_)=>v.name.localeCompare(_.name))),s=(0,external_path_.join)(r,".."),g=(0,external_path_.resolve)((0,external_path_.normalize)(s)),d=!a||g===a||g.startsWith(a+t);n({ok:!0,current:r,parent:d&&s!==r?s:null,dirs:f})}catch(f){n({ok:!1,error:f.message})}})),C.on("create",((o,n)=>{if(!hasPermission(C.data.role,"operator")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(!o?.cwd&&o?.nestByTitle&&(o={...o,cwd:taskCwdFromTitle(o?.title,C.data.dir)}),C.data.dir){const t=(0,external_path_.resolve)((0,external_path_.normalize)(C.data.dir)),r=o?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(o.cwd)):null;if(r&&r!==t&&!r.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}r||(o={...o,cwd:t})}const a=o?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(a))try{(0,external_fs_.mkdirSync)(a,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${a}`)}catch(t){typeof n=="function"&&n({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${t.message}`});return}try{const t=manager.create({...o,owner:C.data.userName,userDir:C.data.dir});console.log(`[\u4F1A\u8BDD] ${C.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})}})),C.on("kill",(o=>{if(!hasPermission(C.data.role,"operator")){C.emit("error",{message:"\u6CA1\u6709\u5220\u9664\u4F1A\u8BDD\u7684\u6743\u9650"});return}console.log(`[\u4F1A\u8BDD] ${C.data.userName} \u5220\u9664\u4F1A\u8BDD ${o}`),manager.kill(o),_autoSpawned.delete(o),broadcastSessions()})),C.on("kick-user",(({socketId:o,sessionId:n}={},a)=>{if(!hasPermission(C.data.role,"admin")){typeof a=="function"&&a({ok:!1,error:"\u6CA1\u6709\u8E22\u51FA\u7528\u6237\u7684\u6743\u9650"});return}const t=io.sockets.sockets.get(o);if(!t){typeof a=="function"&&a({ok:!1,error:"\u76EE\u6807\u7528\u6237\u4E0D\u5728\u7EBF"});return}const r=t.data.userName||"\u672A\u77E5";console.log(`[\u8E22\u51FA] ${C.data.userName} \u8E22\u51FA\u4E86\u7528\u6237 ${r} (${o})`),t.emit("kicked",{reason:`\u4F60\u5DF2\u88AB\u7BA1\u7406\u5458 ${C.data.userName} \u8E22\u51FA`}),t.disconnect(!0),typeof a=="function"&&a({ok:!0,name:r})})),C.on("list-viewers",(({sessionId:o}={},n)=>{if(typeof n!="function")return;const a=o?manager.get(o):l;if(!a){n({ok:!1,error:"\u4F1A\u8BDD\u4E0D\u5B58\u5728"});return}const t=[];for(const r of a._viewers){const p=io.sockets.sockets.get(r);p&&t.push({socketId:r,userName:p.data.userName||"\u672A\u77E5",role:p.data.role||"viewer",isController:a.controlHolder===r})}n({ok:!0,viewers:t})}))}));const CONTROL_TIMEOUT=(Number(process.env.MYHI_CONTROL_TIMEOUT)||300)*1e3,CONTROL_SWEEP=Math.min(60*1e3,CONTROL_TIMEOUT);function shouldReleaseIdle(C){if(!C.controlHolder)return!1;if(!io.sockets.sockets.get(C.controlHolder))return!0;if(!C.lastInputTime||Date.now()-C.lastInputTime<=CONTROL_TIMEOUT||C.isBusy)return!1;for(const b of C._viewers||[])if(b!==C.controlHolder&&io.sockets.sockets.has(b))return!0;return!1}setInterval((()=>{for(const C of manager.listSessions()){shouldReleaseIdle(C)&&(C.releaseControl(),io.emit("control-changed",{sessionId:C.id,holder:null,holderName:null}));for(const b of C._viewers)io.sockets.sockets.has(b)||C.removeViewer(b)}}),CONTROL_SWEEP);function showStartupInfo(){PORT=(httpsServer||httpServer).address()?.port||PORT;const b=getTailscaleIP(),i=`${httpsServer?"https":"http"}://${b}:${PORT}`;console.log(`
422
422
  \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(`
423
423
  \u5730\u5740: ${i}`),httpsServer&&console.log(` HTTP\u91CD\u5B9A\u5411: http://${b}:${PORT+1} \u2192 HTTPS`),console.log(` \u5BC6\u7801: ${PASSWORD} (\u7F16\u8F91 ~/.myhi/password \u53EF\u4FEE\u6539)`),console.log(`
424
424
  \u626B\u63CF\u4E8C\u7EF4\u7801\u5728\u624B\u673A\u4E0A\u6253\u5F00:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wendongfly/myhi",
3
- "version": "1.3.120",
3
+ "version": "1.3.121",
4
4
  "description": "Web-based terminal sharing with chat UI — control your terminal from phone via LAN/Tailscale",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",