@wendongfly/myhi 1.3.93 → 1.3.95
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/bin/myhi.js +12 -0
- package/dist/index.js +1 -1
- package/dist/index.min.js +1 -1
- package/package.json +1 -1
package/dist/index.min.js
CHANGED
|
@@ -374,7 +374,7 @@ Content-Length: `+C+`\r
|
|
|
374
374
|
`),VALID_PERMISSION_MODES=new Set(["bypassPermissions","plan","acceptEdits"]);function normalizePermissionMode(T){return T==="bypass"?"bypassPermissions":VALID_PERMISSION_MODES.has(T)?T:"bypassPermissions"}class AgentSession extends external_events_.EventEmitter{constructor(_,f={}){super(),this.id=_,this.createdAt=f.createdAt||new Date().toISOString(),this.title=f.title||"claude",this.cwd=f.cwd||process.env.MYHI_CWD||process.cwd(),this.tags=Array.isArray(f.tags)?f.tags:[],this.permissionMode=normalizePermissionMode(f.permissionMode),this.owner=f.owner||null,this.userDir=f.userDir||null,this.claudeSessionId=f.resumeSessionId||null,this.mode="agent",this.alive=!0,this._viewers=new Set,this._viewerNames=new Map,this.controlHolder=null,this.controlHolderName=null,this.lastInputTime=null,this._proc=null,this._busy=!1,this._interrupted=!1,this._buffer="",this._pendingResolve=null,this._pendingReject=null,this._keepAliveTimer=null,this._history=[],this._loopSigCounts=new Map,this._loopPoisonHits=0,this._loopTurnToolCalls=0,this._loopTripped=!1,this._loopAutoRecover=0,this._pendingSteer=null,this._imageBlockCount=0,this._imageNudgeAt=IMAGE_NUDGE_STEP,this._lastActivityAt=f.lastActivityAt||0,this._awaitingTool=!1,this._watchdogTimer=null,this._usage={totalCostUSD:0,totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheCreationTokens:0,queryCount:0,rateLimitInfo:null,modelUsage:{}},this.claudeSessionId&&this._loadResumedHistory()}_buildEnv(){const _={...process.env};if(delete _.CLAUDECODE,delete _.CLAUDE_CODE_ENTRYPOINT,delete _.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC,this.userDir){const f=(0,external_path_.join)(this.userDir,".gitconfig");(0,external_fs_.existsSync)(f)&&(_.GIT_CONFIG_GLOBAL=f)}try{const f=(0,external_path_.join)((0,external_os_.homedir)(),".myhi","gateway.json");if((0,external_fs_.existsSync)(f)){const a=JSON.parse((0,external_fs_.readFileSync)(f,"utf8"));a.baseUrl&&(_.ANTHROPIC_BASE_URL=a.baseUrl),a.apiKey&&(_.ANTHROPIC_API_KEY=a.apiKey)}}catch{}return _}_buildArgs(){const _=["--output-format","stream-json","--input-format","stream-json","--verbose"];_.push("--append-system-prompt",MYHI_SYSTEM_PROMPT.replace(/\s*\n\s*/g," ").trim());const f=normalizePermissionMode(this.permissionMode);if(f==="bypassPermissions")_.push("--dangerously-skip-permissions");else if(f==="plan")_.push("--permission-mode","plan"),_.push("--allowedTools","WebSearch"),_.push("--allowedTools","WebFetch");else if(f==="acceptEdits"){_.push("--permission-mode","acceptEdits");const a=["Bash(git *)","Bash(npm *)","Bash(npx *)","Bash(node *)","Bash(ls *)","Bash(cat *)","Bash(mkdir *)","Bash(cp *)","Bash(mv *)","Bash(rm *)","Bash(cd *)","Bash(pwd)","Bash(find *)","Bash(grep *)","Bash(curl *)","Bash(wget *)","Bash(pip *)","Bash(python *)","Bash(python3 *)","Bash(chmod *)","Bash(chown *)","Bash(tar *)","Bash(unzip *)","Bash(zip *)","Bash(sed *)","Bash(awk *)","Bash(head *)","Bash(tail *)","Bash(wc *)","Bash(sort *)","Bash(echo *)","Bash(which *)","Bash(apt *)","Bash(apt-get *)","Bash(docker *)","Bash(ssh *)","Bash(scp *)","Bash(rsync *)","Bash(touch *)","Bash(diff *)","Bash(env *)","Bash(export *)","Bash(source *)","Bash(tee *)","Bash(xargs *)","Bash(du *)","Bash(df *)","Bash(ps *)","Bash(kill *)","Bash(systemctl *)","Bash(journalctl *)","Bash(sudo *)"];for(const t of a)_.push("--allowedTools",t)}return this.modelId&&_.push("--model",this.modelId),this.claudeSessionId&&_.push("--resume",this.claudeSessionId),_}_writeStdin(_){if(!this._proc||!this._proc.stdin?.writable)return!1;try{return this._proc.stdin.write(JSON.stringify(_)+`
|
|
375
375
|
`),!0}catch{return!1}}_spawnProcess(){this._keepAliveTimer&&(clearInterval(this._keepAliveTimer),this._keepAliveTimer=null);const _=findClaude(),f=this._buildArgs(),a=this._buildEnv(),t=_.command,c=[..._.preArgs,...f];console.log(`[agent] \u542F\u52A8\u6301\u4E45\u8FDB\u7A0B: ${t} ${_.preArgs.join(" ")} (\u4F1A\u8BDD: ${this.claudeSessionId||"\u65B0\u5EFA"})`),this._proc=(0,external_child_process_namespaceObject.spawn)(t,c,{cwd:this.cwd,env:a,stdio:["pipe","pipe","pipe"]}),this._buffer="",this._proc.stdout.on("data",(l=>{this._buffer+=l.toString();const m=this._buffer.split(`
|
|
376
376
|
`);this._buffer=m.pop()||"";for(const o of m){const i=o.replace(/\r$/,"");if(i)try{const n=JSON.parse(i);this._handleMessage(n)}catch{i.trim()&&(this.emit("agent:message",{type:"system",subtype:"info",message:i.trim()}),this._checkDeathLoop({type:"system",_raw:i}))}}})),this._proc.stderr.on("data",(l=>{const m=l.toString().trim();m&&!m.includes("Warning:")&&!m.includes("DeprecationWarning")&&(console.error("[agent:stderr]",m),this.emit("agent:error",{message:m}),this._checkDeathLoop({type:"stderr",_raw:m}))})),this._proc.on("close",(l=>{if(!this._interrupted&&this._buffer.trim())try{const m=JSON.parse(this._buffer.trim());this._handleMessage(m)}catch{}this._keepAliveTimer&&(clearInterval(this._keepAliveTimer),this._keepAliveTimer=null),this._stopStallWatchdog(),this._proc=null,this._buffer="",console.log(`[agent] \u8FDB\u7A0B\u9000\u51FA (code ${l}), \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 ${l})`)),this._pendingResolve=null,this._pendingReject=null)),this._flushPendingSteer(),this.alive&&l!==0&&l!==null&&this.emit("agent:error",{message:`Claude \u8FDB\u7A0B\u5F02\u5E38\u9000\u51FA (code ${l})\uFF0C\u4E0B\u6B21\u67E5\u8BE2\u5C06\u81EA\u52A8\u91CD\u542F`})})),this._proc.on("error",(l=>{this._keepAliveTimer&&(clearInterval(this._keepAliveTimer),this._keepAliveTimer=null),this._stopStallWatchdog(),this._proc=null,this._busy=!1,this.emit("agent:busy",!1),this.emit("agent:error",{message:`\u542F\u52A8 Claude \u5931\u8D25: ${l.message}`}),this._pendingReject&&(this._pendingReject(l),this._pendingResolve=null,this._pendingReject=null)})),this._keepAliveTimer=setInterval((()=>{this._writeStdin({type:"keep_alive"})}),3e4)}async query(_,{internal:f=!1}={}){if(this._busy){this.emit("agent:error",{message:"\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210"});return}if(_==="/clear"){this.reset(),this.emit("agent:message",{type:"system",subtype:"info",message:"\u5DF2\u6E05\u9664 Claude \u4E0A\u4E0B\u6587\uFF0C\u4E0B\u6B21\u63D0\u95EE\u5C06\u5F00\u542F\u5168\u65B0\u5BF9\u8BDD"});return}const a=_.match(/^\/resume\s+(\S+)/);if(a){if(this._proc){try{this._proc.kill("SIGTERM")}catch{}this._proc=null}this.claudeSessionId=a[1],this._history=[],this._buffer="",this._loadResumedHistory(),this.emit("agent:message",{type:"system",subtype:"info",message:`\u5DF2\u5207\u6362\u5230\u4F1A\u8BDD ${a[1].slice(0,8)}...\uFF0C\u4E0B\u6B21\u63D0\u95EE\u5C06\u6062\u590D\u8BE5\u5BF9\u8BDD`});return}const t=_.match(/^\/model\s+(\S+)/);if(t){if(this.modelId=t[1],this._proc){try{this._proc.kill("SIGTERM")}catch{}this._proc=null}this.emit("agent:message",{type:"system",subtype:"info",message:`\u6A21\u578B\u5DF2\u5207\u6362\u4E3A ${t[1]}`});return}if(_==="/plan"||_.startsWith("/plan ")){if(this.permissionMode==="plan"){if(this.permissionMode=normalizePermissionMode(this._prePlanMode),this._prePlanMode=null,this._proc){try{this._proc.kill("SIGTERM")}catch{}this._proc=null}this.emit("agent:message",{type:"system",subtype:"info",message:"\u5DF2\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"})}else{if(this._prePlanMode=this.permissionMode,this.permissionMode="plan",this._proc){try{this._proc.kill("SIGTERM")}catch{}this._proc=null}this.emit("agent:message",{type:"system",subtype:"info",message:"\u5DF2\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\uFF08\u53EA\u89C4\u5212\u4E0D\u6267\u884C\uFF09"});const l=_.slice(5).trim();if(l){setTimeout((()=>this.query(l)),500);return}}return}if(_.startsWith("/rename")){this.emit("agent:message",{type:"system",subtype:"info",message:"\u4F1A\u8BDD\u5DF2\u547D\u540D"});return}return this._busy=!0,this._interrupted=!1,this.emit("agent:busy",!0),this._loopSigCounts.clear(),this._loopPoisonHits=0,this._loopTurnToolCalls=0,this._loopTripped=!1,f||(this._loopAutoRecover=0),this._lastActivityAt=Date.now(),this._awaitingTool=!1,this._startStallWatchdog(),this._history.push({type:"user",content:_,timestamp:Date.now()}),this._proc||this._spawnProcess(),new Promise(((c,l)=>{this._pendingResolve=c,this._pendingReject=l,_.startsWith("/")&&(this._slashTimeout=setTimeout((()=>{this._busy&&(this._busy=!1,this._interrupted=!1,this.emit("agent:busy",!1),this.emit("agent:message",{type:"system",subtype:"info",message:`\u547D\u4EE4 ${_} \u5DF2\u53D1\u9001`}),this._pendingResolve&&(this._pendingResolve(0),this._pendingResolve=null,this._pendingReject=null))}),3e4)),this._writeStdin({type:"user",message:{role:"user",content:_}})||(this._busy=!1,this.emit("agent:busy",!1),this._pendingResolve=null,this._pendingReject=null,l(new Error("Claude \u8FDB\u7A0B\u4E0D\u53EF\u5199")))}))}_handleMessage(_){const f=!!this.claudeSessionId;if(this._lastActivityAt=Date.now(),_.type==="assistant"&&Array.isArray(_.message?.content)?_.message.content.some((l=>l.type==="tool_use"))&&(this._awaitingTool=!0):_.type==="user"&&(this._awaitingTool=!1),_.session_id&&!this.claudeSessionId&&(this.claudeSessionId=_.session_id),_.type==="system"&&_.subtype==="init"&&_.session_id&&(this.claudeSessionId=_.session_id),!f&&this.claudeSessionId&&this.emit("session-id",this.claudeSessionId),_.type==="system"&&_.subtype==="init"&&this.permissionMode==="bypassPermissions"&&_.permissionMode&&_.permissionMode!=="bypassPermissions"){const l=_.permissionMode;this.reset(),this.emit("agent:message",{type:"system",subtype:"warning",message:`\u26A0\uFE0F \u8FD9\u4E2A\u4F1A\u8BDD\u88AB --resume \u5E26\u56DE\u4E86\u300C${l}\u300D\u6A21\u5F0F\uFF08\u975E bypass\uFF0C\u4F1A\u62E6\u5199/\u5220\u4E14\u65E0\u6CD5\u8FD0\u884C\u65F6\u63D0\u6743\uFF0C\u70B9\u300C\u9000\u51FA\u8BA1\u5212\u300D\u4E5F\u9003\u4E0D\u6389\uFF09\u3002\u5DF2\u81EA\u52A8\u65AD\u5F00\u65E7\u4F1A\u8BDD\u94FE\u3001\u91CD\u5F00\u4E3A\u5E72\u51C0\u7684 bypass \u4F1A\u8BDD\u2014\u2014\u8BF7\u91CD\u53D1\u4F60\u521A\u624D\u7684\u6307\u4EE4\uFF0C\u8FD9\u6B21\u4F1A\u76F4\u63A5\u6267\u884C\u3002`});return}const a=stripHeavyPayload({..._,timestamp:Date.now()}),t=JSON.stringify(a);t.length>10240&&(a._truncated=!0),this._history.push(a);const c=500;if(this._history.length>c&&(this._history=this._history.slice(-c)),this.emit("agent:message",_),this._trackImagePressure(t),this._checkDeathLoop(_,t),_.type==="rate_limit_event"&&_.rate_limit_info&&(this._usage.rateLimitInfo=_.rate_limit_info),_.type==="result"&&(this._usage.queryCount++,_.total_cost_usd&&(this._usage.totalCostUSD+=_.total_cost_usd),_.usage&&(this._usage.totalInputTokens+=_.usage.input_tokens||0,this._usage.totalOutputTokens+=_.usage.output_tokens||0,this._usage.totalCacheReadTokens+=_.usage.cache_read_input_tokens||0,this._usage.totalCacheCreationTokens+=_.usage.cache_creation_input_tokens||0),_.modelUsage))for(const[l,m]of Object.entries(_.modelUsage))this._usage.modelUsage[l]||(this._usage.modelUsage[l]={inputTokens:0,outputTokens:0,costUSD:0}),this._usage.modelUsage[l].inputTokens+=m.inputTokens||0,this._usage.modelUsage[l].outputTokens+=m.outputTokens||0,this._usage.modelUsage[l].costUSD+=m.costUSD||0;_.type==="result"&&(this._slashTimeout&&(clearTimeout(this._slashTimeout),this._slashTimeout=null),this._stopStallWatchdog(),this._busy=!1,this._interrupted=!1,this.emit("agent:busy",!1),this._pendingResolve&&(this._pendingResolve(0),this._pendingResolve=null,this._pendingReject=null),this._flushPendingSteer())}_trackImagePressure(_){const f=(_.match(/"type":"image"/g)||[]).length;f&&(this._imageBlockCount+=f,this._imageBlockCount>=this._imageNudgeAt&&(this._imageNudgeAt+=IMAGE_NUDGE_STEP,this.emit("agent:message",{type:"system",subtype:"warning",message:`\u2139\uFE0F \u672C\u4F1A\u8BDD\u5DF2\u7D2F\u79EF\u7EA6 ${this._imageBlockCount} \u5F20\u56FE\u7247\u3002\u56FE\u7247\u8D8A\u591A\u8D8A\u5BB9\u6613\u89E6\u53D1 API \u56FE\u7247\u5904\u7406\u9519\u8BEF\u5E76\u62D6\u6162/\u6D88\u8017\u989D\u5EA6\uFF0C\u5EFA\u8BAE\u7528 /clear \u91CD\u5F00\u4E00\u4E2A\u5E72\u51C0\u4F1A\u8BDD\uFF0C\u6216\u51CF\u5C11\u540E\u7EED\u622A\u56FE\u3002`})))}_checkDeathLoop(_,f){if(this._loopTripped)return;let a=!1;try{const t=f||JSON.stringify(_);a=LOOP_POISON_PHRASES.some((c=>t.includes(c)))}catch{}if(a&&(this._loopPoisonHits++,this._loopPoisonHits>=LOOP_MAX_POISON_HITS)){this._tripLoopBreaker("\u8BE5\u56FE\u7247/\u5185\u5BB9 API \u53CD\u590D\u65E0\u6CD5\u5904\u7406\u5E76\u5DF2\u88AB\u79FB\u9664\uFF0C\u8BF7\u4E0D\u8981\u518D\u7528 Read \u91CD\u65B0\u8BFB\u53D6\u5B83\u2014\u2014\u5B83\u5DF2\u4E0D\u53EF\u7528\u3002\u8BF7\u57FA\u4E8E\u73B0\u6709\u6587\u5B57\u4FE1\u606F\u7EE7\u7EED\uFF1B\u82E5\u786E\u5B9E\u9700\u8981\u8BE5\u56FE\uFF0C\u8BF7\u63D0\u793A\u7528\u6237\u91CD\u65B0\u4E0A\u4F20\u4E00\u5F20\u66F4\u5C0F\u7684\u622A\u56FE\u3002");return}if(_.type==="assistant"&&Array.isArray(_.message?.content))for(const t of _.message.content){if(t.type!=="tool_use")continue;if(this._loopTurnToolCalls++,this._loopTurnToolCalls>LOOP_MAX_TURN_TOOLCALLS){this._tripLoopBreaker(`\u672C\u8F6E\u5DE5\u5177\u8C03\u7528\u5DF2\u8FBE ${this._loopTurnToolCalls} \u6B21\u5E76\u63D2\u5165\u68C0\u67E5\u70B9\u3002\u82E5\u4ECD\u5728\u6B63\u5E38\u63A8\u8FDB\uFF0C\u8BF7\u6982\u8FF0\u5F53\u524D\u8FDB\u5C55\u540E\u7EE7\u7EED\uFF1B\u82E5\u5728\u91CD\u590D\u540C\u7C7B\u64CD\u4F5C\u800C\u6CA1\u6709\u8FDB\u5C55\uFF0C\u8BF7\u6362\u4E00\u79CD\u601D\u8DEF\uFF0C\u6216\u5148\u5411\u7528\u6237\u6C47\u62A5\u518D\u7B49\u5F85\u6307\u793A\u3002`);return}const c=`${t.name}:${this._hashInput(t.input)}`,l=(this._loopSigCounts.get(c)||0)+1;if(this._loopSigCounts.set(c,l),l>=LOOP_MAX_IDENTICAL_CALLS){this._tripLoopBreaker(`\u5DE5\u5177\u300C${t.name}\u300D\u5DF2\u7528\u5B8C\u5168\u76F8\u540C\u7684\u53C2\u6570\u8C03\u7528 ${l} \u6B21\uFF0C\u7591\u4F3C\u9677\u5165\u6B7B\u5FAA\u73AF\u3002\u8BF7\u505C\u6B62\u91CD\u590D\u8BE5\u8C03\u7528\uFF0C\u6539\u7528\u4E0D\u540C\u53C2\u6570/\u4E0D\u540C\u5DE5\u5177\uFF0C\u6216\u8DF3\u8FC7\u8FD9\u4E00\u6B65\u7EE7\u7EED\u3002`);return}}}_hashInput(_){let f;try{f=JSON.stringify(stripHeavyPayload(_))}catch{f=String(_)}f.length>4096&&(f=f.slice(0,4096));let a=5381;for(let t=0;t<f.length;t++)a=(a<<5)+a+f.charCodeAt(t)|0;return a.toString(36)}_tripLoopBreaker(_){if(this._loopTripped=!0,console.warn("[agent] \u{1F50C} \u6B7B\u5FAA\u73AF\u7194\u65AD:",_),this._loopAutoRecover>=LOOP_MAX_AUTO_RECOVER){this._pendingSteer=null,this.emit("agent:message",{type:"system",subtype:"warning",message:"\u26A0\uFE0F \u591A\u6B21\u81EA\u52A8\u7EA0\u504F\u4ECD\u672A\u8DF3\u51FA\u5FAA\u73AF\uFF0C\u5DF2\u505C\u6B62\u4EE5\u4FDD\u62A4 session \u989D\u5EA6\u3002\u8BF7 /clear \u91CD\u5F00\u6216\u6362\u4E2A\u95EE\u6CD5\u3002"}),this.interrupt();return}this._loopAutoRecover++,this._pendingSteer=_,this.emit("agent:message",{type:"system",subtype:"warning",message:`\u26A0\uFE0F \u7194\u65AD\u4FDD\u62A4\uFF08\u7B2C ${this._loopAutoRecover} \u6B21\u81EA\u52A8\u7EA0\u504F\uFF09\uFF1A${_}`}),this.interrupt()}_flushPendingSteer(){if(!this._pendingSteer)return;const _=this._pendingSteer;this._pendingSteer=null,setTimeout((()=>{!this._busy&&this.alive&&this.query(_,{internal:!0}).catch((()=>{}))}),600)}_startStallWatchdog(){this._stopStallWatchdog(),this._watchdogTimer=setInterval((()=>{if(!this._busy){this._stopStallWatchdog();return}if(this._awaitingTool)return;const _=Date.now()-this._lastActivityAt;if(_>=STALL_WATCHDOG_MS){const f=Math.round(_/1e3);console.warn(`[agent] \u23F1 \u505C\u6446\u770B\u95E8\u72D7\u89E6\u53D1\uFF1A\u7B49\u5F85\u6A21\u578B\u54CD\u5E94\u5DF2 ${f}s \u65E0\u4EFB\u4F55\u6D88\u606F\uFF0C\u5F3A\u5236\u4E2D\u65AD`),this.emit("agent:message",{type:"system",subtype:"warning",message:`\u23F1 \u68C0\u6D4B\u5230\u4F1A\u8BDD\u505C\u6446\uFF08\u7B49\u5F85\u6A21\u578B\u54CD\u5E94 ${f}s \u65E0\u54CD\u5E94\uFF0C\u7591\u4F3C API \u4F20\u8F93\u5C42\u91CD\u8BD5\u5361\u4F4F\uFF09\uFF0C\u5DF2\u5F3A\u5236\u4E2D\u65AD\u672C\u56DE\u5408\u3002\u8BF7\u91CD\u8BD5\u6216\u7A0D\u540E\u518D\u8BD5\u3002`}),this._stopStallWatchdog(),this.interrupt()}}),STALL_CHECK_INTERVAL_MS),this._watchdogTimer.unref&&this._watchdogTimer.unref()}_stopStallWatchdog(){this._watchdogTimer&&(clearInterval(this._watchdogTimer),this._watchdogTimer=null)}respondPermission(_,f){return this._writeStdin({type:"control_response",request_id:_,allow:f})}_hardKillTree(_){if(_)try{if(process.platform==="win32")(0,external_child_process_namespaceObject.execSync)(`taskkill /PID ${_} /F /T`,{stdio:"pipe",timeout:5e3});else{try{process.kill(_,"SIGTERM")}catch{}setTimeout((()=>{try{process.kill(_,0)}catch{return}try{process.kill(_,"SIGKILL")}catch{}}),1e3)}}catch{}}interrupt(){if(!this._proc||!this._busy)return;this._interrupted=!0;const _=this._proc.pid,f=this._proc,t=this._writeStdin({type:"control_request",request_id:`interrupt-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,request:{subtype:"interrupt"}})?1500:0;setTimeout((()=>{this._busy&&this._proc===f&&(console.log(`[agent] graceful interrupt \u8D85\u65F6\uFF0C\u5F3A\u5236\u7ED3\u675F\u8FDB\u7A0B\u6811 PID ${_}`),this._hardKillTree(_))}),t),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&&(this._hardKillTree(this._proc.pid),this._proc=null),this._pendingReject){try{this._pendingReject(new Error("\u4F1A\u8BDD\u5DF2\u7EC8\u6B62"))}catch{}this._pendingResolve=null,this._pendingReject=null}this._busy=!1}_loadResumedHistory(){try{const _=(0,external_path_.join)((0,external_os_.homedir)(),".claude","projects");if(!(0,external_fs_.existsSync)(_))return;for(const f of(0,external_fs_.readdirSync)(_,{withFileTypes:!0})){if(!f.isDirectory())continue;const a=(0,external_path_.join)(_,f.name,this.claudeSessionId+".jsonl");if(!(0,external_fs_.existsSync)(a))continue;const t=(0,external_fs_.readFileSync)(a,"utf8").split(`
|
|
377
|
-
`).filter(Boolean).slice(-20);for(const c of t)try{const l=JSON.parse(c);if(l.type==="human"||l.type==="user"&&l.message?.content){const m=typeof l.message.content=="string"?l.message.content:l.message.content.find((o=>o.type==="text"))?.text||"";m&&this._history.push({type:"user",content:m,timestamp:l.timestamp})}else l.type==="assistant"&&l.message?.content?this._history.push({type:"assistant",message:l.message,timestamp:l.timestamp}):l.type==="result"&&this._history.push({type:"result",total_cost_usd:l.costUSD||l.total_cost_usd,timestamp:l.timestamp})}catch{}
|
|
377
|
+
`).filter(Boolean).slice(-20);for(const c of t)try{const l=JSON.parse(c);if(l.type==="human"||l.type==="user"&&l.message?.content){const m=typeof l.message.content=="string"?l.message.content:l.message.content.find((o=>o.type==="text"))?.text||"";m&&this._history.push({type:"user",content:m,timestamp:l.timestamp})}else l.type==="assistant"&&l.message?.content?this._history.push({type:"assistant",message:l.message,timestamp:l.timestamp}):l.type==="result"&&this._history.push({type:"result",total_cost_usd:l.costUSD||l.total_cost_usd,timestamp:l.timestamp})}catch{}try{const c=(0,external_fs_.statSync)(a).mtimeMs;c>0&&(this._lastActivityAt=Math.max(this._lastActivityAt,c))}catch{}return}}catch(_){console.warn("[agent] \u52A0\u8F7D\u6062\u590D\u4F1A\u8BDD\u5386\u53F2\u5931\u8D25:",_.message)}}get isBusy(){return this._busy}getRecentHistory(_=20){return this._history.slice(-_)}getUsage(){return{...this._usage}}addViewer(_,f){this._viewers.add(_),f&&this._viewerNames.set(_,f)}removeViewer(_){this._viewers.delete(_),this._viewerNames.delete(_)}get viewerCount(){return new Set(this._viewerNames.values()).size||this._viewers.size}takeControl(_,f){this.controlHolder=_,this.controlHolderName=f||null,this.lastInputTime=Date.now()}releaseControl(){this.controlHolder=null,this.controlHolderName=null,this.lastInputTime=null}isController(_){return this.controlHolder===_}setPermissionMode(_){this.permissionMode=normalizePermissionMode(_),this._proc&&(this.kill(),this.alive=!0)}reset(){this._proc&&(this._hardKillTree(this._proc.pid),this._proc=null),this.claudeSessionId=null,this._history=[],this._buffer="",this._imageBlockCount=0,this._imageNudgeAt=IMAGE_NUDGE_STEP,this.permissionMode="bypassPermissions"}toJSON(){return{id:this.id,title:this.title,cwd:this.cwd,tags:this.tags,createdAt:this.createdAt,lastActivityAt:this._lastActivityAt||null,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 getSessionHealth(T){const _={found:!1,persistedMode:null,poisoned:!1,messageCount:0,transcriptKB:0,imageCount:0,updatedAt:null};if(!T)return _;try{const f=(0,external_path_.join)((0,external_os_.homedir)(),".claude","projects");if(!(0,external_fs_.existsSync)(f))return _;for(const a of(0,external_fs_.readdirSync)(f,{withFileTypes:!0})){if(!a.isDirectory())continue;const t=(0,external_path_.join)(f,a.name,T+".jsonl");if(!(0,external_fs_.existsSync)(t))continue;const c=(0,external_fs_.readFileSync)(t,"utf8"),l=c.split(`
|
|
378
378
|
`).filter(Boolean);let m=null,o=null,i=0;for(const n of l){const e=n.match(/"type":"image"/g);if(e&&(i+=e.length),n.includes("permissionMode"))try{const r=JSON.parse(n);r.type==="user"&&r.permissionMode&&(m=r.permissionMode)}catch{}}try{const n=JSON.parse(l[l.length-1]);n.timestamp&&(o=n.timestamp)}catch{}return{found:!0,persistedMode:m,poisoned:!!(m&&m!=="bypassPermissions"),messageCount:l.length,transcriptKB:Math.round(c.length/1024),imageCount:i,updatedAt:o}}}catch{}return _}let _claudeSessionsCache=null,_claudeSessionsCacheTime=0;const CLAUDE_SESSIONS_CACHE_TTL=3e4;function listLocalClaudeSessions(T){const _=Date.now();if(_claudeSessionsCache&&_-_claudeSessionsCacheTime<CLAUDE_SESSIONS_CACHE_TTL){if(!T)return _claudeSessionsCache;const c=(0,external_path_.resolve)((0,external_path_.normalize)(T)).replace(/[\\/]+$/,"");return _claudeSessionsCache.filter((l=>(0,external_path_.resolve)((0,external_path_.normalize)(l.projectPath)).replace(/[\\/]+$/,"").startsWith(c)))}const f=[],a=T?(0,external_path_.resolve)((0,external_path_.normalize)(T)).replace(/[\\/]+$/,""):null;try{const c=(0,external_path_.join)((0,external_os_.homedir)(),".claude","projects");if(!(0,external_fs_.existsSync)(c))return f;for(const l of(0,external_fs_.readdirSync)(c,{withFileTypes:!0})){if(!l.isDirectory())continue;const m=(0,external_path_.join)(c,l.name);try{for(const o of(0,external_fs_.readdirSync)(m)){if(!o.endsWith(".jsonl"))continue;const i=o.replace(".jsonl",""),n=(0,external_path_.join)(m,o);try{const e=(0,external_fs_.readFileSync)(n,"utf8").split(`
|
|
379
379
|
`).filter(Boolean);let r=null,u=null,p=0,s="";for(const h of e)try{const g=JSON.parse(h);if(r||(r=g),u=g,p++,!s&&g.type==="human"||g.type==="user"&&g.message?.content){const b=g.message.content;if(typeof b=="string")s=b.slice(0,120);else if(Array.isArray(b)){const d=b.find((w=>w.type==="text"));d&&(s=d.text?.slice(0,120)||"")}}}catch{}let v=l.name;if(process.platform==="win32"&&/^[A-Za-z]--/.test(v)?v=v[0]+":\\"+v.slice(3).replace(/-/g,"\\"):v.startsWith("-")&&(v=v.replace(/-/g,"/")),a&&!(0,external_path_.resolve)((0,external_path_.normalize)(v)).replace(/[\\/]+$/,"").startsWith(a))continue;f.push({sessionId:i,projectDir:l.name,projectPath:v,messageCount:p,summary:s,createdAt:r?.timestamp||null,updatedAt:u?.timestamp||null})}catch{}}}catch{}}}catch{}f.sort(((c,l)=>new Date(l.updatedAt||0).getTime()-new Date(c.updatedAt||0).getTime()));const t=f.slice(0,50);return _claudeSessionsCache=t,_claudeSessionsCacheTime=Date.now(),t.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"),savePath=null;function loadSavedConfigs(){try{return JSON.parse((0,external_fs_.readFileSync)(SESSIONS_FILE,"utf8"))}catch{return[]}}function writeSavedConfigs(T){try{(0,external_fs_.mkdirSync)(CONFIG_DIR,{recursive:!0});const _=SESSIONS_FILE+".tmp";(0,external_fs_.writeFileSync)(_,JSON.stringify(T,null,2),{mode:384}),(0,external_fs_.renameSync)(_,SESSIONS_FILE)}catch(_){console.error("[sessions] \u6301\u4E45\u5316\u5199\u5165\u5931\u8D25:",_.message)}}class Session extends external_events_.EventEmitter{constructor(_,f={}){super(),this.id=_,this.createdAt=f.createdAt||new Date().toISOString(),this.title=f.title||DEFAULT_SHELL,this.cwd=f.cwd||process.env.MYHI_CWD||process.cwd(),this.tags=Array.isArray(f.tags)?f.tags:[],this.initCmd=f.initCmd||null,this.owner=f.owner||null,this.cols=f.cols||120,this.rows=f.rows||30,this._lastActivityAt=f.lastActivityAt||0,this._viewers=new Set,this._viewerNames=new Map,this.controlHolder=null,this.controlHolderName=null,this.lastInputTime=null;const a={...process.env};if(delete a.CLAUDECODE,delete a.CLAUDE_CODE_ENTRYPOINT,delete a.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC,f.userDir){const c=(0,external_path_.join)(f.userDir,".gitconfig");(0,external_fs_.existsSync)(c)&&(a.GIT_CONFIG_GLOBAL=c)}this._pty=external_node_pty_namespaceObject.spawn(DEFAULT_SHELL,[],{name:"xterm-256color",cols:this.cols,rows:this.rows,cwd:this.cwd,env:a,useConpty:!1}),this._scrollback="";const t=100*1024;if(this._pty.onData((c=>{this.emit("data",c),this._scrollback+=c,this._scrollback.length>t&&(this._scrollback=this._scrollback.slice(this._scrollback.length-t))})),this._pty.onExit((({exitCode:c})=>{this.exitCode=c,this.emit("exit",c)})),f.initCmd){const c=f.initCmd;let l=!1;const m=o=>{!l&&/[$>#\]]\s*$/.test(o.trimEnd())&&(l=!0,this._pty.off("data",m),setTimeout((()=>this._pty.write(c+"\r")),120))};this._pty.onData(m),setTimeout((()=>{l||(l=!0,this._pty.write(c+"\r"))}),3e3)}}write(_){_!=null&&(this._lastActivityAt=Date.now(),this._pty.write(_))}resize(_,f){this.cols=_,this.rows=f,this._pty.resize(_,f)}kill(){try{this._pty.kill()}catch{}}addViewer(_,f){this._viewers.add(_),f&&this._viewerNames.set(_,f)}removeViewer(_){this._viewers.delete(_),this._viewerNames.delete(_)}get viewerCount(){return new Set(this._viewerNames.values()).size||this._viewers.size}takeControl(_,f){this.controlHolder=_,this.controlHolderName=f||null,this.lastInputTime=Date.now()}releaseControl(){this.controlHolder=null,this.controlHolderName=null,this.lastInputTime=null}isController(_){return this.controlHolder===_}toJSON(){return{id:this.id,title:this.title,cwd:this.cwd,tags:this.tags,createdAt:this.createdAt,lastActivityAt:this._lastActivityAt||null,cols:this.cols,rows:this.rows,viewers:this.viewerCount,alive:this.exitCode===void 0,controlHolder:this.controlHolder,controlHolderName:this.controlHolderName,owner:this.owner}}}class SessionManager{constructor(){this._sessions=new Map,this._agentSessions=new Map;for(const _ of loadSavedConfigs())try{if(_.mode==="agent"){if(_.claudeSessionId){const f=(0,external_crypto_.randomUUID)(),a=new AgentSession(f,{..._,resumeSessionId:_.claudeSessionId});a.on("session-id",(()=>this._persist())),this._agentSessions.set(f,a),console.log(`[\u4F1A\u8BDD] \u6062\u590D Agent "${_.title}" (claude: ${_.claudeSessionId.slice(0,8)}...)`)}}else this._spawn((0,external_crypto_.randomUUID)(),_,!1)}catch(f){console.warn(`[\u4F1A\u8BDD] \u6062\u590D "${_.title}" \u5931\u8D25:`,f.message)}}_spawn(_,f,a=!0){const t=new Session(_,f);return this._sessions.set(_,t),t.on("exit",(()=>{setTimeout((()=>this._sessions.delete(_)),300*1e3)})),a&&this._persist(),t}create(_={}){return this._spawn((0,external_crypto_.randomUUID)(),_,!0)}createAgent(_={}){const f=(0,external_crypto_.randomUUID)(),a=new AgentSession(f,_);return this._agentSessions.set(f,a),a.on("session-id",(()=>this._persist())),this._persist(),a}get(_){return this._sessions.get(_)||this._agentSessions.get(_)}list(_,f=!1){let a=[...this._sessions.values()].map((c=>({...c.toJSON(),mode:"pty"}))),t=[...this._agentSessions.values()].map((c=>c.toJSON()));return _&&!f&&(a=a.filter((c=>!c.owner||c.owner===_)),t=t.filter((c=>!c.owner||c.owner===_))),[...a,...t]}listSessions(){return[...this._sessions.values(),...this._agentSessions.values()]}kill(_){const f=this._sessions.get(_);if(f){f.kill(),this._sessions.delete(_),this._persist();return}const a=this._agentSessions.get(_);a&&(a.kill(),this._agentSessions.delete(_),this._persist())}persist(){this._persist()}_persist(){const _=[...this._sessions.values()].filter((a=>a.exitCode===void 0)).map((a=>({mode:"pty",title:a.title,cwd:a.cwd,tags:a.tags?.length?a.tags:void 0,createdAt:a.createdAt||void 0,lastActivityAt:a._lastActivityAt||void 0,initCmd:a.initCmd||void 0,owner:a.owner||void 0}))),f=[...this._agentSessions.values()].filter((a=>a.alive)).map((a=>({mode:"agent",title:a.title,cwd:a.cwd,tags:a.tags?.length?a.tags:void 0,createdAt:a.createdAt||void 0,lastActivityAt:a._lastActivityAt||void 0,owner:a.owner||void 0,userDir:a.userDir||void 0,claudeSessionId:a.claudeSessionId||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,usersConfig=null;function loadRoles(){try{if((0,external_fs_.existsSync)(ROLES_FILE))return rolesConfig=JSON.parse((0,external_fs_.readFileSync)(ROLES_FILE,"utf8")),rolesConfig}catch(T){console.warn("[\u89D2\u8272] \u52A0\u8F7D roles.json \u5931\u8D25:",T.message)}return rolesConfig=null,null}function lookupPassword(T){if(!rolesConfig?.passwords)return null;const _=rolesConfig.passwords[T];return _?{name:_.name||"\u7528\u6237",role:_.role||"viewer"}:null}function hasPermission(T,_){return(ROLE_LEVELS[T]||0)>=(ROLE_LEVELS[_]||0)}function isMultiUserMode(){return rolesConfig!==null&&rolesConfig.passwords&&Object.keys(rolesConfig.passwords).length>0}function getDefaultRole(){return rolesConfig?.defaultRole||"admin"}function loadUsers(){try{if((0,external_fs_.existsSync)(USERS_FILE))return usersConfig=JSON.parse((0,external_fs_.readFileSync)(USERS_FILE,"utf8")),usersConfig}catch(T){console.warn("[\u7528\u6237] \u52A0\u8F7D users.json \u5931\u8D25:",T.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(T){usersConfig||(usersConfig={users:{}}),usersConfig.exclusive=!!T,_writeUsers()}function lookupUser(T){if(!usersConfig?.users)return null;const _=usersConfig.users[T];return _?{name:_.name||"\u7528\u6237",dir:_.dir}:null}function listUsers(){return usersConfig?.users?Object.entries(usersConfig.users).map((([T,_])=>({password:T.slice(0,2)+"*".repeat(T.length-2),name:_.name,dir:_.dir}))):[]}function addUser(T,_,f){usersConfig||(usersConfig={users:{}}),usersConfig.users||(usersConfig.users={}),usersConfig.users[T]={name:_,dir:f},_writeUsers()}function removeUser(T){return!usersConfig?.users||!usersConfig.users[T]?!1:(delete usersConfig.users[T],_writeUsers(),!0)}function _writeUsers(){(0,external_fs_.mkdirSync)(roles_CONFIG_DIR,{recursive:!0}),(0,external_fs_.writeFileSync)(USERS_FILE,JSON.stringify(usersConfig,null,2),{mode:384})}const execAsync=(0,external_util_.promisify)(external_child_process_namespaceObject.exec),server_dirname=(0,external_path_.dirname)((0,external_url_.fileURLToPath)(import.meta.url));let PORT=parseInt(process.env.PORT,10)||12300;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});let httpsServer=null,httpServer=null;function getOrCreateCert(){const T=(0,external_path_.join)(configDir,"cert.pem"),_=(0,external_path_.join)(configDir,"key.pem");if((0,external_fs_.existsSync)(T)&&(0,external_fs_.existsSync)(_))try{return{cert:(0,external_fs_.readFileSync)(T),key:(0,external_fs_.readFileSync)(_)}}catch{}try{const f=selfsigned.generate([{name:"commonName",value:"myhi"}],{days:3650,keySize:2048});return(0,external_fs_.writeFileSync)(T,f.cert,"utf8"),(0,external_fs_.writeFileSync)(_,f.private,"utf8"),console.log("[myhi] \u81EA\u7B7E\u540D HTTPS \u8BC1\u4E66\u5DF2\u751F\u6210"),{cert:f.cert,key:f.private}}catch{}try{return(0,external_child_process_namespaceObject.execSync)(`openssl req -x509 -newkey rsa:2048 -keyout "${_}" -out "${T}" -days 3650 -nodes -subj "/CN=myhi"`,{stdio:"pipe",timeout:1e4}),{cert:(0,external_fs_.readFileSync)(T),key:(0,external_fs_.readFileSync)(_)}}catch(f){return console.warn(`[myhi] \u751F\u6210 HTTPS \u8BC1\u4E66\u5931\u8D25: ${f.message?.split(`
|
|
380
380
|
`)[0]||f}`),null}}const pidFile=(0,external_path_.join)(configDir,"server.pid"),daemonPidFile=(0,external_path_.join)(configDir,"daemon.pid"),IS_DAEMON_CHILD=!!process.env.MYHI_DAEMON;function killOldProcess(T,_){let f=!1;try{process.kill(T,0),f=!0}catch{}if(!f)return!0;console.log(`[myhi] \u68C0\u6D4B\u5230\u5DF2\u8FD0\u884C\u7684${_} (PID ${T})\uFF0C\u6B63\u5728\u505C\u6B62...`);try{process.platform==="win32"?(0,external_child_process_namespaceObject.execSync)(`taskkill /PID ${T} /F /T`,{stdio:"pipe",timeout:5e3}):process.kill(T,"SIGTERM")}catch{}const a=Date.now()+5e3;for(;Date.now()<a;){try{process.kill(T,0)}catch{return!0}const c=Date.now()+200;for(;Date.now()<c;);}let t=!1;try{process.kill(T,0),t=!0}catch{}return!t}(function T(){try{const _=parseInt((0,external_fs_.readFileSync)(daemonPidFile,"utf8").trim(),10);if(_&&_!==process.pid&&_!==parseInt(process.env.MYHI_DAEMON_PID||"0",10)){let f=!1;try{process.kill(_,0),f=!0}catch{}if(f&&!IS_DAEMON_CHILD){console.log("[myhi] \u68C0\u6D4B\u5230\u540E\u53F0 daemon \u5728\u8FD0\u884C\uFF0C\u5148\u505C\u6B62..."),killOldProcess(_,"daemon")||(console.error("[myhi] \u65E0\u6CD5\u505C\u6B62 daemon\uFF0C\u8BF7\u5148\u8FD0\u884C: myhi stop"),process.exit(1));try{(0,external_fs_.unlinkSync)(daemonPidFile)}catch{}}}}catch{}if(!IS_DAEMON_CHILD)try{const _=parseInt((0,external_fs_.readFileSync)(pidFile,"utf8").trim(),10);_&&_!==process.pid&&(killOldProcess(_,"\u5B9E\u4F8B")||(console.error(`[myhi] \u65E0\u6CD5\u505C\u6B62\u65E7\u8FDB\u7A0B (PID ${_})\uFF0C\u8BF7\u624B\u52A8\u6267\u884C\uFF1A`),console.error(" myhi stop"),console.error(` \u6216: ${process.platform==="win32"?`taskkill /PID ${_} /F`:`kill -9 ${_}`}`),process.exit(1)))}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{}}function gracefulShutdown(){try{if(typeof manager<"u"){try{manager.persist()}catch{}for(const T of manager.listSessions())try{T.kill()}catch{}}}catch{}cleanupPid()}process.on("exit",cleanupPid),process.on("SIGTERM",(()=>{gracefulShutdown(),process.exit(0)})),process.on("SIGINT",(()=>{gracefulShutdown(),process.exit(0)})),process.on("uncaughtException",(T=>{console.error("[myhi] \u672A\u6355\u83B7\u5F02\u5E38:",T.message),gracefulShutdown(),process.exit(1)})),process.on("unhandledRejection",(T=>{console.error("[myhi] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",T)}));function readOrCreate(T,_){try{if((0,external_fs_.existsSync)(T))return(0,external_fs_.readFileSync)(T,"utf8").trim()}catch{}const f=_();return(0,external_fs_.writeFileSync)(T,f,{mode:384}),f}const TOKEN=readOrCreate((0,external_path_.join)(configDir,"token"),(()=>(0,external_crypto_.randomBytes)(16).toString("hex")));let 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 T=Date.now();for(const[_,f]of userSessions)f.permanent||(!f.lastUsed||T-f.lastUsed>SESSION_MAX_AGE)&&userSessions.delete(_)}),3600*1e3);function getTailscaleIP(){try{return(0,external_child_process_namespaceObject.execSync)("tailscale ip -4",{timeout:3e3,stdio:"pipe"}).toString().trim().split(`
|