@wendongfly/myhi 1.3.71 → 1.3.72

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
@@ -400,7 +400,7 @@ Content-Length: `+C+`\r
400
400
  helper = store --file ${l.replace(/\\/g,"/")}
401
401
  [user]
402
402
  name = ${o}
403
- `,{mode:384})}catch{}console.log(`[\u7BA1\u7406] \u6DFB\u52A0\u7528\u6237 ${o} (\u76EE\u5F55: ${t})`),w.json({ok:!0})})),app.delete("/api/admin/user",checkAdminAuth,express.json(),((A,w)=>{const{name:d}=A.body||{};if(!d)return w.json({ok:!1,error:"\u8BF7\u6307\u5B9A\u7528\u6237\u540D\u79F0"});if(loadUsers(),!listUsers().find((o=>o.name===d)))return w.json({ok:!1,error:"\u7528\u6237\u4E0D\u5B58\u5728"});try{const o=(0,external_path_.join)(configDir,"users.json"),t=JSON.parse((0,external_fs_.readFileSync)(o,"utf8"));for(const[c,l]of Object.entries(t.users||{}))if(l.name===d){delete t.users[c];break}(0,external_fs_.writeFileSync)(o,JSON.stringify(t,null,2),{mode:384}),loadUsers(),console.log(`[\u7BA1\u7406] \u5220\u9664\u7528\u6237 ${d}`),w.json({ok:!0})}catch(o){w.json({ok:!1,error:o.message})}})),app.post("/api/admin/user/password",checkAdminAuth,express.json(),((A,w)=>{const{name:d,password:o}=A.body||{};if(!d||!o)return w.json({ok:!1,error:"\u540D\u79F0\u548C\u65B0\u5BC6\u7801\u5FC5\u586B"});try{const t=(0,external_path_.join)(configDir,"users.json"),c=JSON.parse((0,external_fs_.readFileSync)(t,"utf8"));let l=null;for(const[v,s]of Object.entries(c.users||{}))if(s.name===d){l=s,delete c.users[v];break}if(!l)return w.json({ok:!1,error:"\u7528\u6237\u4E0D\u5B58\u5728"});c.users[o]=l,(0,external_fs_.writeFileSync)(t,JSON.stringify(c,null,2),{mode:384}),loadUsers(),console.log(`[\u7BA1\u7406] \u4FEE\u6539\u7528\u6237 ${d} \u7684\u5BC6\u7801`),w.json({ok:!0})}catch(t){w.json({ok:!1,error:t.message})}})),app.post("/api/admin/password",checkAdminAuth,express.json(),((A,w)=>{const{password:d}=A.body||{};if(!d||d.length<4)return w.json({ok:!1,error:"\u5BC6\u7801\u81F3\u5C114\u4F4D"});try{(0,external_fs_.writeFileSync)((0,external_path_.join)(configDir,"password"),d,{mode:384}),PASSWORD=d,w.json({ok:!0}),console.log("[\u7BA1\u7406] \u7BA1\u7406\u5BC6\u7801\u5DF2\u4FEE\u6539")}catch(o){w.json({ok:!1,error:o.message})}})),app.post("/upload",checkAuth,((A,w)=>{const d=A.query.sessionId,o=d?manager.get(d):null,t=o?.cwd?(0,external_path_.join)(o.cwd,"upload"):uploadDir;(0,external_fs_.mkdirSync)(t,{recursive:!0}),multer({storage:multer.diskStorage({destination:t,filename:(c,l,v)=>{const s=l.originalname.match(/\.[^.]+$/)?.[0]||".jpg";v(null,`${Date.now()}-${(0,external_crypto_.randomBytes)(3).toString("hex")}${s}`)}}),limits:{fileSize:20*1024*1024},fileFilter:(c,l,v)=>v(null,l.mimetype.startsWith("image/"))}).single("image")(A,w,(c=>{if(c)return w.status(400).json({error:c.message});if(!A.file)return w.status(400).json({error:"\u6CA1\u6709\u56FE\u7247"});w.json({path:(0,external_path_.resolve)(A.file.path).replace(/\\/g,"/")})}))})),app.post("/api/voice-transcribe",checkAuth,multer({storage:multer.memoryStorage(),limits:{fileSize:10*1024*1024}}).single("audio"),(async(A,w)=>{if(!A.file)return w.status(400).json({error:"\u65E0\u97F3\u9891\u6570\u636E"});const d=process.env.ASR_URL||(()=>{try{return JSON.parse((0,external_fs_.readFileSync)((0,external_path_.join)((0,external_os_.homedir)(),".myhi","asr.json"),"utf8")).url}catch{return null}})();if(!d)return w.status(503).json({error:"\u672A\u914D\u7F6E ASR \u670D\u52A1\uFF0C\u8BF7\u8BBE\u7F6E ASR_URL \u73AF\u5883\u53D8\u91CF\u6216 ~/.myhi/asr.json"});try{const o=new FormData;o.append("audio",new Blob([A.file.buffer],{type:A.file.mimetype||"audio/webm"}),"audio.webm");const c=await(await fetch(d+"/transcribe",{method:"POST",body:o})).json();w.json({text:c.text||"",error:c.error})}catch(o){w.status(500).json({error:o.message})}})),app.post("/api/voice-assist/organize",checkAuth,express.json(),(async(A,w)=>{const{transcript:d}=A.body||{};if(!d?.trim())return w.status(400).json({error:"\u65E0\u8F6C\u5F55\u5185\u5BB9"});const o=`\u4F60\u662F\u4E00\u4E2A\u9700\u6C42\u5206\u6790\u52A9\u624B\u3002\u7528\u6237\u901A\u8FC7\u8BED\u97F3\u53E3\u8FF0\u4E86\u4E00\u4E9B\u9700\u6C42\uFF0C\u539F\u59CB\u8F6C\u5F55\u5982\u4E0B\uFF1A
403
+ `,{mode:384})}catch{}console.log(`[\u7BA1\u7406] \u6DFB\u52A0\u7528\u6237 ${o} (\u76EE\u5F55: ${t})`),w.json({ok:!0})})),app.delete("/api/admin/user",checkAdminAuth,express.json(),((A,w)=>{const{name:d}=A.body||{};if(!d)return w.json({ok:!1,error:"\u8BF7\u6307\u5B9A\u7528\u6237\u540D\u79F0"});if(loadUsers(),!listUsers().find((o=>o.name===d)))return w.json({ok:!1,error:"\u7528\u6237\u4E0D\u5B58\u5728"});try{const o=(0,external_path_.join)(configDir,"users.json"),t=JSON.parse((0,external_fs_.readFileSync)(o,"utf8"));for(const[c,l]of Object.entries(t.users||{}))if(l.name===d){delete t.users[c];break}(0,external_fs_.writeFileSync)(o,JSON.stringify(t,null,2),{mode:384}),loadUsers(),console.log(`[\u7BA1\u7406] \u5220\u9664\u7528\u6237 ${d}`),w.json({ok:!0})}catch(o){w.json({ok:!1,error:o.message})}})),app.post("/api/admin/user/password",checkAdminAuth,express.json(),((A,w)=>{const{name:d,password:o}=A.body||{};if(!d||!o)return w.json({ok:!1,error:"\u540D\u79F0\u548C\u65B0\u5BC6\u7801\u5FC5\u586B"});try{const t=(0,external_path_.join)(configDir,"users.json"),c=JSON.parse((0,external_fs_.readFileSync)(t,"utf8"));let l=null;for(const[v,s]of Object.entries(c.users||{}))if(s.name===d){l=s,delete c.users[v];break}if(!l)return w.json({ok:!1,error:"\u7528\u6237\u4E0D\u5B58\u5728"});c.users[o]=l,(0,external_fs_.writeFileSync)(t,JSON.stringify(c,null,2),{mode:384}),loadUsers(),console.log(`[\u7BA1\u7406] \u4FEE\u6539\u7528\u6237 ${d} \u7684\u5BC6\u7801`),w.json({ok:!0})}catch(t){w.json({ok:!1,error:t.message})}})),app.post("/api/admin/password",checkAdminAuth,express.json(),((A,w)=>{const{password:d}=A.body||{};if(!d||d.length<4)return w.json({ok:!1,error:"\u5BC6\u7801\u81F3\u5C114\u4F4D"});try{(0,external_fs_.writeFileSync)((0,external_path_.join)(configDir,"password"),d,{mode:384}),PASSWORD=d,w.json({ok:!0}),console.log("[\u7BA1\u7406] \u7BA1\u7406\u5BC6\u7801\u5DF2\u4FEE\u6539")}catch(o){w.json({ok:!1,error:o.message})}})),app.post("/upload",checkAuth,((A,w)=>{const d=A.query.sessionId,o=d?manager.get(d):null,t=o?.cwd?(0,external_path_.join)(o.cwd,"upload"):uploadDir;(0,external_fs_.mkdirSync)(t,{recursive:!0}),multer({storage:multer.diskStorage({destination:t,filename:(c,l,v)=>{const s=l.originalname.match(/\.[^.]+$/)?.[0]||".jpg";v(null,`${Date.now()}-${(0,external_crypto_.randomBytes)(3).toString("hex")}${s}`)}}),limits:{fileSize:20*1024*1024},fileFilter:(c,l,v)=>v(null,l.mimetype.startsWith("image/"))}).single("image")(A,w,(c=>{if(c)return w.status(400).json({error:c.message});if(!A.file)return w.status(400).json({error:"\u6CA1\u6709\u56FE\u7247"});w.json({path:(0,external_path_.resolve)(A.file.path).replace(/\\/g,"/")})}))})),app.post("/api/voice-transcribe",checkAuth,multer({storage:multer.memoryStorage(),limits:{fileSize:200*1024*1024}}).single("audio"),(async(A,w)=>{if(!A.file)return w.status(400).json({error:"\u65E0\u97F3\u9891\u6570\u636E"});const d=process.env.ASR_URL||(()=>{try{return JSON.parse((0,external_fs_.readFileSync)((0,external_path_.join)((0,external_os_.homedir)(),".myhi","asr.json"),"utf8")).url}catch{return null}})();if(!d)return w.status(503).json({error:"\u672A\u914D\u7F6E ASR \u670D\u52A1\uFF0C\u8BF7\u8BBE\u7F6E ASR_URL \u73AF\u5883\u53D8\u91CF\u6216 ~/.myhi/asr.json"});try{const o=new FormData;o.append("audio",new Blob([A.file.buffer],{type:A.file.mimetype||"audio/webm"}),"audio.webm");const c=await(await fetch(d+"/transcribe",{method:"POST",body:o})).json();w.json({text:c.text||"",error:c.error})}catch(o){w.status(500).json({error:o.message})}})),app.post("/api/voice-assist/organize",checkAuth,express.json(),(async(A,w)=>{const{transcript:d}=A.body||{};if(!d?.trim())return w.status(400).json({error:"\u65E0\u8F6C\u5F55\u5185\u5BB9"});const o=`\u4F60\u662F\u4E00\u4E2A\u9700\u6C42\u5206\u6790\u52A9\u624B\u3002\u7528\u6237\u901A\u8FC7\u8BED\u97F3\u53E3\u8FF0\u4E86\u4E00\u4E9B\u9700\u6C42\uFF0C\u539F\u59CB\u8F6C\u5F55\u5982\u4E0B\uFF1A
404
404
 
405
405
  ---
406
406
  ${d}
@@ -413,7 +413,7 @@ ${d}
413
413
  4. \u4FDD\u7559\u6240\u6709\u5177\u4F53\u7684\u6570\u5B57\u3001\u540D\u79F0\u3001\u89C4\u5219\u7B49\u5173\u952E\u4FE1\u606F
414
414
  5. \u5982\u6709\u6B67\u4E49\u8BF7\u5728\u672B\u5C3E\u7528"\u2753\u5F85\u786E\u8BA4"\u6807\u6CE8
415
415
 
416
- \u53EA\u8F93\u51FA\u6574\u7406\u540E\u7684\u9700\u6C42\u5185\u5BB9\uFF0C\u4E0D\u9700\u8981\u89E3\u91CA\u3002\u5FC5\u987B\u7528\u4E2D\u6587\u8F93\u51FA\u3002`;try{const t=await new Promise(((c,l)=>{let v="",s="";const i=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",n=process.platform==="win32"?process.env.ComSpec||"cmd.exe":i,e=process.platform==="win32"?["/c",i,"-p",o]:["-p",o],r=(0,external_child_process_namespaceObject.spawn)(n,e,{env:{...process.env,NO_COLOR:"1"},timeout:9e4});r.stdout.on("data",(u=>{v+=u.toString()})),r.stderr.on("data",(u=>{s+=u.toString()})),r.on("close",(u=>{u!==0&&!v.trim()?l(new Error(s||`exit ${u}`)):c(v.trim())})),r.on("error",l)}));w.json({requirement:t})}catch(t){w.status(500).json({error:t.message})}})),app.get("/qr/:sessionId",checkAuth,(async(A,w)=>{const d=getTailscaleIP(),o=(0,external_crypto_.randomBytes)(16).toString("hex");userSessions.set(o,{role:"admin",name:"\u626B\u7801\u7528\u6237",onetime:!0,lastUsed:Date.now()});const c=`${httpsServer?"https":"http"}://${d}:${PORT}/terminal/${A.params.sessionId}?token=${o}`;try{const l=await lib.toString(c,{type:"svg"});w.setHeader("Content-Type","image/svg+xml"),w.send(l)}catch(l){w.status(500).send(l.message)}})),io.use(((A,w)=>{const d=A.handshake.headers.cookie;if(hasValidSession(d)){const t=getUserInfo(d);return A.data.role=t?.role||"admin",A.data.userName=t?.name||"\u7528\u6237",A.data.dir=t?.dir||null,w()}const o=A.handshake.auth?.password;if(o){loadUsers();const t=lookupUser(o);if(t)return A.data.role="operator",A.data.userName=t.name,A.data.dir=t.dir,w()}if((A.handshake.auth?.token||A.handshake.query?.token)===TOKEN)return A.data.role="admin",A.data.userName="\u7BA1\u7406\u5458",w();w(new Error("\u672A\u6388\u6743"))}));const EXCLUSIVE_RELEASE_DELAY=120*1e3;let _exclusiveReleaseTimer=null;function checkExclusiveRelease(){if(!isExclusiveMode()||!activeUser)return;let A=!1;for(const[,w]of io.sockets.sockets)if(w.data.userName===activeUser.name){A=!0;break}if(A){_exclusiveReleaseTimer&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);return}_exclusiveReleaseTimer||(_exclusiveReleaseTimer=setTimeout((()=>{if(_exclusiveReleaseTimer=null,!!activeUser){for(const[,w]of io.sockets.sockets)if(w.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 w of activeUser.tokens)userSessions.delete(w);activeUser=null}}),EXCLUSIVE_RELEASE_DELAY))}let _broadcastTimer=null;function broadcastSessions(){_broadcastTimer||(_broadcastTimer=setTimeout((()=>{_broadcastTimer=null;for(const[,A]of io.sockets.sockets)A.emit("sessions",manager.list(A.data.userName,A.data.role==="admin"))}),100))}io.on("connection",(A=>{const w=A.handshake.address?.replace("::ffff:","")||"?";console.log(`[\u8FDE\u63A5] ${A.data.userName}(${A.data.role}) \u4ECE ${w} \u63A5\u5165 id=${A.id}`),_exclusiveReleaseTimer&&activeUser&&A.data.userName===activeUser.name&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);let d=null,o=null,t=null,c=null,l=null;function v(){d&&(d.isController(A.id)&&(d.releaseControl(),io.emit("control-changed",{sessionId:d.id,holder:null,holderName:null})),d.removeViewer(A.id),o&&d.off("data",o),t&&d.off("agent:message",t),c&&d.off("agent:busy",c),l&&d.off("agent:error",l),o=null,t=null,c=null,l=null)}A.on("join",(s=>{const i=manager.get(s);if(!i){A.emit("error",{message:`\u4F1A\u8BDD ${s} \u672A\u627E\u5230`});return}const n=d?.id===s;if(v(),d=i,d.addViewer(A.id,A.data.userName),i.mode==="agent"?(t=e=>A.emit("agent:message",e),d.on("agent:message",t),c=e=>A.emit("agent:busy",e),d.on("agent:busy",c),l=e=>A.emit("agent:error",e),d.on("agent:error",l)):(o=e=>A.emit("output",e),d.on("data",o),d.once("exit",(e=>{A.emit("session-exit",{code:e}),o&&d?.off("data",o)})),spawnLocalTerminal(s,i.title)),console.log(`[\u52A0\u5165] ${A.data.userName} \u52A0\u5165\u4F1A\u8BDD "${i.title}" (${s}) \u6A21\u5F0F=${i.mode||"pty"}${n?" [\u91CD\u65B0\u8BA2\u9605]":""}`),A.emit("joined",{...i.toJSON(),role:A.data.role}),!n){if(i.mode==="agent")i._history?.length&&A.emit("agent:history",i._history);else if(i._scrollback?.length){const e=i._scrollback;if(e.length<=4096)A.emit("output",e);else{let r=0;(function u(){r>=e.length||(A.emit("output",e.slice(r,r+4096)),r+=4096,setImmediate(u))})()}}}broadcastSessions()})),A.on("disconnect",(()=>{console.log(`[\u65AD\u5F00] ${A.data.userName} \u79BB\u5F00\u4F1A\u8BDD "${d?.title||"?"}" id=${A.id}`),v(),broadcastSessions(),checkExclusiveRelease(),manager.persist()})),A.on("agent:query",(async({prompt:s}={})=>{if(!d||d.mode!=="agent"){A.emit("agent:error",{message:"\u5F53\u524D\u4E0D\u662F Agent \u6A21\u5F0F\u4F1A\u8BDD"});return}if(!d.isController(A.id)){A.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}if(d.isBusy){A.emit("agent:error",{message:"\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210"});return}try{await d.query(s)}catch(i){console.error("[agent:query] \u9519\u8BEF:",i.message);try{A.connected&&A.emit("agent:error",{message:i.message})}catch{}}})),A.on("agent:interrupt",(()=>{!d||d.mode!=="agent"||d.interrupt()})),A.on("create-agent",((s,i)=>{if(!hasPermission(A.data.role,"operator")){typeof i=="function"&&i({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(A.data.dir){const e=(0,external_path_.resolve)((0,external_path_.normalize)(A.data.dir)),r=s?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(s.cwd)):null;if(r&&r!==e&&!r.startsWith(e+external_path_.sep)){typeof i=="function"&&i({ok:!1,error:"\u4E0D\u80FD\u5728\u7ED1\u5B9A\u76EE\u5F55\u4E4B\u5916\u521B\u5EFA\u4F1A\u8BDD"});return}r||(s={...s,cwd:e})}const n=s?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(n))try{(0,external_fs_.mkdirSync)(n,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${n}`)}catch(e){typeof i=="function"&&i({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e.message}`});return}try{const e=manager.createAgent({...s,owner:A.data.userName,userDir:A.data.dir});console.log(`[\u4F1A\u8BDD] ${A.data.userName} \u521B\u5EFA Agent \u4F1A\u8BDD "${e.title}" (${e.id})`),broadcastSessions(),typeof i=="function"&&i({ok:!0,session:e.toJSON()})}catch(e){typeof i=="function"&&i({ok:!1,error:e.message})}})),A.on("input",(s=>{if(!(s==null||!d)&&d.mode!=="agent"){if(!d.isController(A.id)){A.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}d.lastInputTime=Date.now(),d.write(s)}})),A.on("take-control",(({sessionId:s}={})=>{const i=s?manager.get(s):d;if(i){if(!hasPermission(A.data.role,"operator")){A.emit("control-denied",{reason:"\u4F60\u7684\u89D2\u8272\u6CA1\u6709\u63A7\u5236\u6743\u9650"});return}if(i.controlHolder&&i.controlHolder!==A.id){const n=i.controlHolderName===A.data.userName;if(A.data.role!=="admin"&&!n){A.emit("control-denied",{reason:"\u5176\u4ED6\u7528\u6237\u6B63\u5728\u63A7\u5236\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u91CA\u653E"});return}}i.takeControl(A.id,A.data.userName),console.log(`[\u63A7\u5236] ${A.data.userName} \u83B7\u53D6\u4F1A\u8BDD "${i.title}" \u7684\u63A7\u5236\u6743`),io.emit("control-changed",{sessionId:i.id,holder:A.id,holderName:A.data.userName})}})),A.on("release-control",(({sessionId:s}={})=>{const i=s?manager.get(s):d;!i||!i.isController(A.id)||(console.log(`[\u63A7\u5236] ${A.data.userName} \u91CA\u653E\u4F1A\u8BDD "${i.title}" \u7684\u63A7\u5236\u6743`),i.releaseControl(),io.emit("control-changed",{sessionId:i.id,holder:null,holderName:null}))})),A.on("set-mode",(({sessionId:s,mode:i}={})=>{const n=s?manager.get(s):d;n&&(n.mode==="agent"&&n.setPermissionMode?(n.setPermissionMode(i),console.log(`[\u6A21\u5F0F] ${A.data.userName} \u5207\u6362\u4F1A\u8BDD "${n.title}" \u4E3A ${i}`)):n.permissionMode=i,io.emit("mode-changed",{sessionId:n.id,mode:i}),manager.persist())})),A.on("rename",(({sessionId:s,title:i}={})=>{const n=s?manager.get(s):d;!n||!i||(n.title=i,io.emit("session-renamed",{sessionId:n.id,title:i}),broadcastSessions(),manager.persist())})),A.on("resize",(({cols:s,rows:i})=>d?.resize(s,i))),A.on("list",(()=>A.emit("sessions",manager.list(A.data.userName,A.data.role==="admin")))),A.on("dirs",((s,i)=>{if(typeof i!="function")return;const n=A.data.dir?(0,external_path_.resolve)((0,external_path_.normalize)(A.data.dir)):null,e=process.platform==="win32"?"\\":"/";let r=(s||n||process.env.MYHI_CWD||(0,external_os_.homedir)()).replace(/[/\\]+$/,"")||(0,external_os_.homedir)();process.platform==="win32"&&/^[A-Za-z]:$/.test(r)&&(r+="\\");const u=(0,external_path_.resolve)((0,external_path_.normalize)(r));n&&u!==n&&!u.startsWith(n+e)&&(r=n);try{const p=(0,external_fs_.readdirSync)(r,{withFileTypes:!0}).filter((m=>m.isDirectory()&&m.name!==".git")).map((m=>({name:m.name,path:r.replace(/[/\\]+$/,"")+e+m.name}))).sort(((m,b)=>m.name.localeCompare(b.name))),a=(0,external_path_.join)(r,".."),g=(0,external_path_.resolve)((0,external_path_.normalize)(a)),h=!n||g===n||g.startsWith(n+e);i({ok:!0,current:r,parent:h&&a!==r?a:null,dirs:p})}catch(p){i({ok:!1,error:p.message})}})),A.on("create",((s,i)=>{if(!hasPermission(A.data.role,"operator")){typeof i=="function"&&i({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(A.data.dir){const e=(0,external_path_.resolve)((0,external_path_.normalize)(A.data.dir)),r=s?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(s.cwd)):null;if(r&&r!==e&&!r.startsWith(e+external_path_.sep)){typeof i=="function"&&i({ok:!1,error:"\u4E0D\u80FD\u5728\u7ED1\u5B9A\u76EE\u5F55\u4E4B\u5916\u521B\u5EFA\u4F1A\u8BDD"});return}r||(s={...s,cwd:e})}const n=s?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(n))try{(0,external_fs_.mkdirSync)(n,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${n}`)}catch(e){typeof i=="function"&&i({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e.message}`});return}try{const e=manager.create({...s,owner:A.data.userName,userDir:A.data.dir});console.log(`[\u4F1A\u8BDD] ${A.data.userName} \u521B\u5EFA PTY \u4F1A\u8BDD "${e.title}" (${e.id})`),broadcastSessions(),typeof i=="function"&&i({ok:!0,session:e.toJSON()})}catch(e){console.error("[\u521B\u5EFA] PTY \u542F\u52A8\u5931\u8D25:",e.message),typeof i=="function"&&i({ok:!1,error:e.message})}})),A.on("kill",(s=>{if(!hasPermission(A.data.role,"operator")){A.emit("error",{message:"\u6CA1\u6709\u5220\u9664\u4F1A\u8BDD\u7684\u6743\u9650"});return}console.log(`[\u4F1A\u8BDD] ${A.data.userName} \u5220\u9664\u4F1A\u8BDD ${s}`),manager.kill(s),_autoSpawned.delete(s),broadcastSessions()})),A.on("kick-user",(({socketId:s,sessionId:i}={},n)=>{if(!hasPermission(A.data.role,"admin")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u8E22\u51FA\u7528\u6237\u7684\u6743\u9650"});return}const e=io.sockets.sockets.get(s);if(!e){typeof n=="function"&&n({ok:!1,error:"\u76EE\u6807\u7528\u6237\u4E0D\u5728\u7EBF"});return}const r=e.data.userName||"\u672A\u77E5";console.log(`[\u8E22\u51FA] ${A.data.userName} \u8E22\u51FA\u4E86\u7528\u6237 ${r} (${s})`),e.emit("kicked",{reason:`\u4F60\u5DF2\u88AB\u7BA1\u7406\u5458 ${A.data.userName} \u8E22\u51FA`}),e.disconnect(!0),typeof n=="function"&&n({ok:!0,name:r})})),A.on("list-viewers",(({sessionId:s}={},i)=>{if(typeof i!="function")return;const n=s?manager.get(s):d;if(!n){i({ok:!1,error:"\u4F1A\u8BDD\u4E0D\u5B58\u5728"});return}const e=[];for(const r of n._viewers){const u=io.sockets.sockets.get(r);u&&e.push({socketId:r,userName:u.data.userName||"\u672A\u77E5",role:u.data.role||"viewer",isController:n.controlHolder===r})}i({ok:!0,viewers:e})}))}));const CONTROL_TIMEOUT=300*1e3;setInterval((()=>{for(const A of manager.listSessions()){A.controlHolder&&(!io.sockets.sockets.get(A.controlHolder)||A.lastInputTime&&Date.now()-A.lastInputTime>CONTROL_TIMEOUT)&&(A.releaseControl(),io.emit("control-changed",{sessionId:A.id,holder:null,holderName:null}));for(const w of A._viewers)io.sockets.sockets.has(w)||A.removeViewer(w)}}),60*1e3);function showStartupInfo(){PORT=(httpsServer||httpServer).address()?.port||PORT;const w=getTailscaleIP(),o=`${httpsServer?"https":"http"}://${w}:${PORT}`;console.log(`
416
+ \u53EA\u8F93\u51FA\u6574\u7406\u540E\u7684\u9700\u6C42\u5185\u5BB9\uFF0C\u4E0D\u9700\u8981\u89E3\u91CA\u3002\u5FC5\u987B\u7528\u4E2D\u6587\u8F93\u51FA\u3002`;try{const t=await new Promise(((c,l)=>{let v="",s="";const i=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",n=process.platform==="win32"?process.env.ComSpec||"cmd.exe":i,e=process.platform==="win32"?["/c",i,"--print"]:["--print"],r=(0,external_child_process_namespaceObject.spawn)(n,e,{stdio:["pipe","pipe","pipe"],env:{...process.env,NO_COLOR:"1"},timeout:9e4});r.stdin.write(o,"utf8"),r.stdin.end(),r.stdout.on("data",(u=>{v+=u.toString()})),r.stderr.on("data",(u=>{s+=u.toString()})),r.on("close",(u=>{u!==0&&!v.trim()?l(new Error(s||`exit ${u}`)):c(v.trim())})),r.on("error",l)}));w.json({requirement:t})}catch(t){w.status(500).json({error:t.message})}})),app.get("/qr/:sessionId",checkAuth,(async(A,w)=>{const d=getTailscaleIP(),o=(0,external_crypto_.randomBytes)(16).toString("hex");userSessions.set(o,{role:"admin",name:"\u626B\u7801\u7528\u6237",onetime:!0,lastUsed:Date.now()});const c=`${httpsServer?"https":"http"}://${d}:${PORT}/terminal/${A.params.sessionId}?token=${o}`;try{const l=await lib.toString(c,{type:"svg"});w.setHeader("Content-Type","image/svg+xml"),w.send(l)}catch(l){w.status(500).send(l.message)}})),io.use(((A,w)=>{const d=A.handshake.headers.cookie;if(hasValidSession(d)){const t=getUserInfo(d);return A.data.role=t?.role||"admin",A.data.userName=t?.name||"\u7528\u6237",A.data.dir=t?.dir||null,w()}const o=A.handshake.auth?.password;if(o){loadUsers();const t=lookupUser(o);if(t)return A.data.role="operator",A.data.userName=t.name,A.data.dir=t.dir,w()}if((A.handshake.auth?.token||A.handshake.query?.token)===TOKEN)return A.data.role="admin",A.data.userName="\u7BA1\u7406\u5458",w();w(new Error("\u672A\u6388\u6743"))}));const EXCLUSIVE_RELEASE_DELAY=120*1e3;let _exclusiveReleaseTimer=null;function checkExclusiveRelease(){if(!isExclusiveMode()||!activeUser)return;let A=!1;for(const[,w]of io.sockets.sockets)if(w.data.userName===activeUser.name){A=!0;break}if(A){_exclusiveReleaseTimer&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);return}_exclusiveReleaseTimer||(_exclusiveReleaseTimer=setTimeout((()=>{if(_exclusiveReleaseTimer=null,!!activeUser){for(const[,w]of io.sockets.sockets)if(w.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 w of activeUser.tokens)userSessions.delete(w);activeUser=null}}),EXCLUSIVE_RELEASE_DELAY))}let _broadcastTimer=null;function broadcastSessions(){_broadcastTimer||(_broadcastTimer=setTimeout((()=>{_broadcastTimer=null;for(const[,A]of io.sockets.sockets)A.emit("sessions",manager.list(A.data.userName,A.data.role==="admin"))}),100))}io.on("connection",(A=>{const w=A.handshake.address?.replace("::ffff:","")||"?";console.log(`[\u8FDE\u63A5] ${A.data.userName}(${A.data.role}) \u4ECE ${w} \u63A5\u5165 id=${A.id}`),_exclusiveReleaseTimer&&activeUser&&A.data.userName===activeUser.name&&(clearTimeout(_exclusiveReleaseTimer),_exclusiveReleaseTimer=null);let d=null,o=null,t=null,c=null,l=null;function v(){d&&(d.isController(A.id)&&(d.releaseControl(),io.emit("control-changed",{sessionId:d.id,holder:null,holderName:null})),d.removeViewer(A.id),o&&d.off("data",o),t&&d.off("agent:message",t),c&&d.off("agent:busy",c),l&&d.off("agent:error",l),o=null,t=null,c=null,l=null)}A.on("join",(s=>{const i=manager.get(s);if(!i){A.emit("error",{message:`\u4F1A\u8BDD ${s} \u672A\u627E\u5230`});return}const n=d?.id===s;if(v(),d=i,d.addViewer(A.id,A.data.userName),i.mode==="agent"?(t=e=>A.emit("agent:message",e),d.on("agent:message",t),c=e=>A.emit("agent:busy",e),d.on("agent:busy",c),l=e=>A.emit("agent:error",e),d.on("agent:error",l)):(o=e=>A.emit("output",e),d.on("data",o),d.once("exit",(e=>{A.emit("session-exit",{code:e}),o&&d?.off("data",o)})),spawnLocalTerminal(s,i.title)),console.log(`[\u52A0\u5165] ${A.data.userName} \u52A0\u5165\u4F1A\u8BDD "${i.title}" (${s}) \u6A21\u5F0F=${i.mode||"pty"}${n?" [\u91CD\u65B0\u8BA2\u9605]":""}`),A.emit("joined",{...i.toJSON(),role:A.data.role}),!n){if(i.mode==="agent")i._history?.length&&A.emit("agent:history",i._history);else if(i._scrollback?.length){const e=i._scrollback;if(e.length<=4096)A.emit("output",e);else{let r=0;(function u(){r>=e.length||(A.emit("output",e.slice(r,r+4096)),r+=4096,setImmediate(u))})()}}}broadcastSessions()})),A.on("disconnect",(()=>{console.log(`[\u65AD\u5F00] ${A.data.userName} \u79BB\u5F00\u4F1A\u8BDD "${d?.title||"?"}" id=${A.id}`),v(),broadcastSessions(),checkExclusiveRelease(),manager.persist()})),A.on("agent:query",(async({prompt:s}={})=>{if(!d||d.mode!=="agent"){A.emit("agent:error",{message:"\u5F53\u524D\u4E0D\u662F Agent \u6A21\u5F0F\u4F1A\u8BDD"});return}if(!d.isController(A.id)){A.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}if(d.isBusy){A.emit("agent:error",{message:"\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210"});return}try{await d.query(s)}catch(i){console.error("[agent:query] \u9519\u8BEF:",i.message);try{A.connected&&A.emit("agent:error",{message:i.message})}catch{}}})),A.on("agent:interrupt",(()=>{!d||d.mode!=="agent"||d.interrupt()})),A.on("create-agent",((s,i)=>{if(!hasPermission(A.data.role,"operator")){typeof i=="function"&&i({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(A.data.dir){const e=(0,external_path_.resolve)((0,external_path_.normalize)(A.data.dir)),r=s?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(s.cwd)):null;if(r&&r!==e&&!r.startsWith(e+external_path_.sep)){typeof i=="function"&&i({ok:!1,error:"\u4E0D\u80FD\u5728\u7ED1\u5B9A\u76EE\u5F55\u4E4B\u5916\u521B\u5EFA\u4F1A\u8BDD"});return}r||(s={...s,cwd:e})}const n=s?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(n))try{(0,external_fs_.mkdirSync)(n,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${n}`)}catch(e){typeof i=="function"&&i({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e.message}`});return}try{const e=manager.createAgent({...s,owner:A.data.userName,userDir:A.data.dir});console.log(`[\u4F1A\u8BDD] ${A.data.userName} \u521B\u5EFA Agent \u4F1A\u8BDD "${e.title}" (${e.id})`),broadcastSessions(),typeof i=="function"&&i({ok:!0,session:e.toJSON()})}catch(e){typeof i=="function"&&i({ok:!1,error:e.message})}})),A.on("input",(s=>{if(!(s==null||!d)&&d.mode!=="agent"){if(!d.isController(A.id)){A.emit("control-denied",{reason:"\u4F60\u6CA1\u6709\u5F53\u524D\u4F1A\u8BDD\u7684\u63A7\u5236\u6743"});return}d.lastInputTime=Date.now(),d.write(s)}})),A.on("take-control",(({sessionId:s}={})=>{const i=s?manager.get(s):d;if(i){if(!hasPermission(A.data.role,"operator")){A.emit("control-denied",{reason:"\u4F60\u7684\u89D2\u8272\u6CA1\u6709\u63A7\u5236\u6743\u9650"});return}if(i.controlHolder&&i.controlHolder!==A.id){const n=i.controlHolderName===A.data.userName;if(A.data.role!=="admin"&&!n){A.emit("control-denied",{reason:"\u5176\u4ED6\u7528\u6237\u6B63\u5728\u63A7\u5236\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u91CA\u653E"});return}}i.takeControl(A.id,A.data.userName),console.log(`[\u63A7\u5236] ${A.data.userName} \u83B7\u53D6\u4F1A\u8BDD "${i.title}" \u7684\u63A7\u5236\u6743`),io.emit("control-changed",{sessionId:i.id,holder:A.id,holderName:A.data.userName})}})),A.on("release-control",(({sessionId:s}={})=>{const i=s?manager.get(s):d;!i||!i.isController(A.id)||(console.log(`[\u63A7\u5236] ${A.data.userName} \u91CA\u653E\u4F1A\u8BDD "${i.title}" \u7684\u63A7\u5236\u6743`),i.releaseControl(),io.emit("control-changed",{sessionId:i.id,holder:null,holderName:null}))})),A.on("set-mode",(({sessionId:s,mode:i}={})=>{const n=s?manager.get(s):d;n&&(n.mode==="agent"&&n.setPermissionMode?(n.setPermissionMode(i),console.log(`[\u6A21\u5F0F] ${A.data.userName} \u5207\u6362\u4F1A\u8BDD "${n.title}" \u4E3A ${i}`)):n.permissionMode=i,io.emit("mode-changed",{sessionId:n.id,mode:i}),manager.persist())})),A.on("rename",(({sessionId:s,title:i}={})=>{const n=s?manager.get(s):d;!n||!i||(n.title=i,io.emit("session-renamed",{sessionId:n.id,title:i}),broadcastSessions(),manager.persist())})),A.on("resize",(({cols:s,rows:i})=>d?.resize(s,i))),A.on("list",(()=>A.emit("sessions",manager.list(A.data.userName,A.data.role==="admin")))),A.on("dirs",((s,i)=>{if(typeof i!="function")return;const n=A.data.dir?(0,external_path_.resolve)((0,external_path_.normalize)(A.data.dir)):null,e=process.platform==="win32"?"\\":"/";let r=(s||n||process.env.MYHI_CWD||(0,external_os_.homedir)()).replace(/[/\\]+$/,"")||(0,external_os_.homedir)();process.platform==="win32"&&/^[A-Za-z]:$/.test(r)&&(r+="\\");const u=(0,external_path_.resolve)((0,external_path_.normalize)(r));n&&u!==n&&!u.startsWith(n+e)&&(r=n);try{const p=(0,external_fs_.readdirSync)(r,{withFileTypes:!0}).filter((m=>m.isDirectory()&&m.name!==".git")).map((m=>({name:m.name,path:r.replace(/[/\\]+$/,"")+e+m.name}))).sort(((m,b)=>m.name.localeCompare(b.name))),a=(0,external_path_.join)(r,".."),g=(0,external_path_.resolve)((0,external_path_.normalize)(a)),h=!n||g===n||g.startsWith(n+e);i({ok:!0,current:r,parent:h&&a!==r?a:null,dirs:p})}catch(p){i({ok:!1,error:p.message})}})),A.on("create",((s,i)=>{if(!hasPermission(A.data.role,"operator")){typeof i=="function"&&i({ok:!1,error:"\u6CA1\u6709\u521B\u5EFA\u4F1A\u8BDD\u7684\u6743\u9650"});return}if(A.data.dir){const e=(0,external_path_.resolve)((0,external_path_.normalize)(A.data.dir)),r=s?.cwd?(0,external_path_.resolve)((0,external_path_.normalize)(s.cwd)):null;if(r&&r!==e&&!r.startsWith(e+external_path_.sep)){typeof i=="function"&&i({ok:!1,error:"\u4E0D\u80FD\u5728\u7ED1\u5B9A\u76EE\u5F55\u4E4B\u5916\u521B\u5EFA\u4F1A\u8BDD"});return}r||(s={...s,cwd:e})}const n=s?.cwd||process.env.MYHI_CWD||process.cwd();if(!(0,external_fs_.existsSync)(n))try{(0,external_fs_.mkdirSync)(n,{recursive:!0}),console.log(`[\u521B\u5EFA] \u81EA\u52A8\u521B\u5EFA\u76EE\u5F55: ${n}`)}catch(e){typeof i=="function"&&i({ok:!1,error:`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e.message}`});return}try{const e=manager.create({...s,owner:A.data.userName,userDir:A.data.dir});console.log(`[\u4F1A\u8BDD] ${A.data.userName} \u521B\u5EFA PTY \u4F1A\u8BDD "${e.title}" (${e.id})`),broadcastSessions(),typeof i=="function"&&i({ok:!0,session:e.toJSON()})}catch(e){console.error("[\u521B\u5EFA] PTY \u542F\u52A8\u5931\u8D25:",e.message),typeof i=="function"&&i({ok:!1,error:e.message})}})),A.on("kill",(s=>{if(!hasPermission(A.data.role,"operator")){A.emit("error",{message:"\u6CA1\u6709\u5220\u9664\u4F1A\u8BDD\u7684\u6743\u9650"});return}console.log(`[\u4F1A\u8BDD] ${A.data.userName} \u5220\u9664\u4F1A\u8BDD ${s}`),manager.kill(s),_autoSpawned.delete(s),broadcastSessions()})),A.on("kick-user",(({socketId:s,sessionId:i}={},n)=>{if(!hasPermission(A.data.role,"admin")){typeof n=="function"&&n({ok:!1,error:"\u6CA1\u6709\u8E22\u51FA\u7528\u6237\u7684\u6743\u9650"});return}const e=io.sockets.sockets.get(s);if(!e){typeof n=="function"&&n({ok:!1,error:"\u76EE\u6807\u7528\u6237\u4E0D\u5728\u7EBF"});return}const r=e.data.userName||"\u672A\u77E5";console.log(`[\u8E22\u51FA] ${A.data.userName} \u8E22\u51FA\u4E86\u7528\u6237 ${r} (${s})`),e.emit("kicked",{reason:`\u4F60\u5DF2\u88AB\u7BA1\u7406\u5458 ${A.data.userName} \u8E22\u51FA`}),e.disconnect(!0),typeof n=="function"&&n({ok:!0,name:r})})),A.on("list-viewers",(({sessionId:s}={},i)=>{if(typeof i!="function")return;const n=s?manager.get(s):d;if(!n){i({ok:!1,error:"\u4F1A\u8BDD\u4E0D\u5B58\u5728"});return}const e=[];for(const r of n._viewers){const u=io.sockets.sockets.get(r);u&&e.push({socketId:r,userName:u.data.userName||"\u672A\u77E5",role:u.data.role||"viewer",isController:n.controlHolder===r})}i({ok:!0,viewers:e})}))}));const CONTROL_TIMEOUT=300*1e3;setInterval((()=>{for(const A of manager.listSessions()){A.controlHolder&&(!io.sockets.sockets.get(A.controlHolder)||A.lastInputTime&&Date.now()-A.lastInputTime>CONTROL_TIMEOUT)&&(A.releaseControl(),io.emit("control-changed",{sessionId:A.id,holder:null,holderName:null}));for(const w of A._viewers)io.sockets.sockets.has(w)||A.removeViewer(w)}}),60*1e3);function showStartupInfo(){PORT=(httpsServer||httpServer).address()?.port||PORT;const w=getTailscaleIP(),o=`${httpsServer?"https":"http"}://${w}:${PORT}`;console.log(`
417
417
  \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(`
418
418
  \u5730\u5740: ${o}`),httpsServer&&console.log(` HTTP\u91CD\u5B9A\u5411: http://${w}:${PORT+1} \u2192 HTTPS`),console.log(` \u5BC6\u7801: ${PASSWORD} (\u7F16\u8F91 ~/.myhi/password \u53EF\u4FEE\u6539)`),console.log(`
419
419
  \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.71",
3
+ "version": "1.3.72",
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",