gorazenxu_pimate/main.js
gorazen 5596294c44 优(model-sync): 以 Pi getState() 为权威数据源,思考档位弹窗按 thinkingLevelMap 动态渲染
- PiAgentClient 新增 PiModel/PiAgentState/AvailableModelsResult/SetModelResult 类型; sendCommand<T> 泛型化
- 新增 syncSeq 单调计数器废弃过时 getState() 响应;废弃旧 piModelMeta local 类型改用 Pi 返回的 PiModel
- updateActiveTabModel 改以 setModel RPC 响应中的 Pi 确认状态写入 tab/settings,避免 local 值与 Pi clamp 结果不一致
- 新增 syncTabStateFromPi() 统一同步入口,替代散落在各处的局部写入
- thinking_level_changed / model_changed 事件触发 syncTabStateFromPi() 权威同步
- 设置页 provider/model/effort 联动改走 updateActiveTabModel 统一入口,catch setModel 异常防崩溃
- 思考档位弹窗不再用静态硬编码列表,改为从 model.thinkingLevelMap keys 动态渲染;非推理模型显示 informational 行
- getStaticLevelDescription() 提供已知档位的中英文 label 映射

- 文档(CHANGELOG): archive working 条目到 v1.0.43
2026-07-11 02:38:04 +08:00

71 lines
201 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
"use strict";var Be=Object.create;var G=Object.defineProperty;var Oe=Object.getOwnPropertyDescriptor;var _e=Object.getOwnPropertyNames;var He=Object.getPrototypeOf,Ne=Object.prototype.hasOwnProperty;var Ue=(u,t)=>{for(var e in t)G(u,e,{get:t[e],enumerable:!0})},be=(u,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of _e(t))!Ne.call(u,s)&&s!==e&&G(u,s,{get:()=>t[s],enumerable:!(i=Oe(t,s))||i.enumerable});return u};var z=(u,t,e)=>(e=u!=null?Be(He(u)):{},be(t||!u||!u.__esModule?G(e,"default",{value:u,enumerable:!0}):e,u)),ze=u=>be(G({},"__esModule",{value:!0}),u);var at={};Ue(at,{default:()=>te});module.exports=ze(at);var I=require("obsidian");var h=require("obsidian"),A=require("fs"),B=require("path"),V=require("os");var Ce=require("child_process"),ke=require("string_decoder"),Ee=require("events"),R=z(require("path")),H=z(require("fs"));function je(u){if(process.platform!=="win32"||/[\\/]/.test(u)||/\.exe$/i.test(u))return null;let t=(process.env.PATH||"").split(R.delimiter);for(let e of t){if(!e)continue;let i=R.join(e,u+".cmd");if(!H.existsSync(i))continue;let s=R.dirname(i),n=R.basename(s).toLowerCase()===".bin"?R.dirname(s):s,o=[R.join(n,"node_modules","@earendil-works","pi-coding-agent","dist","cli.js"),R.join(s,"node_modules","@earendil-works","pi-coding-agent","dist","cli.js")];for(let a of o){if(!H.existsSync(a))continue;let r=R.join(s,"node.exe"),l=R.join(n,"node.exe");return{cmd:H.existsSync(r)?r:H.existsSync(l)?l:"node",scriptArgs:[a]}}}return null}function Ve(){if(process.platform==="win32")return null;let u=[...(process.env.PATH||"").split(R.delimiter),"/opt/homebrew/bin","/usr/local/bin"],t=new Set;for(let e of u){if(!e||t.has(e))continue;t.add(e);let i=R.join(e,"node");if(H.existsSync(i))return i}return null}function Te(u,t){let e=H.realpathSync(u);return/\.js$/i.test(e)&&t?{cmd:t,scriptArgs:[e]}:null}function Ke(u){if(process.platform==="win32")return null;let t=Ve();if(/\.js$/i.test(u))return t?{cmd:t,scriptArgs:[u]}:null;if(/[\\/]/.test(u))return H.existsSync(u)?Te(u,t):null;let e=[...(process.env.PATH||"").split(R.delimiter),process.env.HOME?R.join(process.env.HOME,".local","bin"):"","/opt/homebrew/bin","/usr/local/bin"],i=new Set;for(let s of e){if(!s||i.has(s))continue;i.add(s);let n=R.join(s,u);if(H.existsSync(n))return Te(n,t)||{cmd:n,scriptArgs:[]}}return null}function We(u){return je(u)||Ke(u)}var Y=class extends Ee.EventEmitter{process=null;buffer="";decoder=new ke.StringDecoder("utf8");nextId=0;pendingRequests=new Map;options;destroyed=!1;constructor(t){super(),this.options=t}async start(){if(this.destroyed)throw new Error("Client destroyed");let t=["--mode","rpc"];this.options.provider&&t.push("--provider",this.options.provider),this.options.modelId&&t.push("--model",this.options.modelId),this.options.thinkingLevel&&t.push("--thinking",this.options.thinkingLevel),this.options.noSession&&t.push("--no-session"),this.options.tools?.length&&t.push("--tools",this.options.tools.join(","));let e={...process.env};if(this.options.apiKey){let i=this.options.provider||"anthropic",n={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY",google:"GOOGLE_API_KEY",deepseek:"DEEPSEEK_API_KEY",groq:"GROQ_API_KEY",xai:"XAI_API_KEY",mistral:"MISTRAL_API_KEY",minimax:"MINIMAX_API_KEY","minimax-cn":"MINIMAX_CN_API_KEY",siliconflow:"SILICONFLOW_API_KEY",zhipu:"ZHIPU_API_KEY"}[i];n&&(e[n]=this.options.apiKey)}return new Promise((i,s)=>{try{let n={cwd:this.options.cwd||process.cwd(),env:e,stdio:["pipe","pipe","pipe"],windowsHide:!0},o=this.options.piPath,a=t,r=We(this.options.piPath);r&&(o=r.cmd,a=[...r.scriptArgs,...t]);let l=(0,Ce.spawn)(o,a,n);this.process=l;let d=!1,c=p=>{d||(d=!0,p?s(p instanceof Error?p:new Error(String(p))):i())};l.stdout.on("data",p=>{this.handleData(p)}),l.stderr.on("data",p=>{console.error("[pi-agent stderr]",p.toString())}),l.on("error",p=>{console.error("[pi-agent] Process error:",p),d?this.emit("error",p):c(p)}),l.on("close",p=>{console.log(`[pi-agent] Process closed with code ${p}`),d?this.emit("close"):c(new Error(`pi exited with code ${p}`)),this.process=null}),window.setTimeout(()=>c(),150)}catch(n){s(n instanceof Error?n:new Error(String(n)))}})}handleData(t){for(this.buffer+=typeof t=="string"?t:this.decoder.write(t);;){let e=this.buffer.indexOf(`
`);if(e===-1)break;let i=this.buffer.slice(0,e);if(this.buffer=this.buffer.slice(e+1),i.endsWith("\r")&&(i=i.slice(0,-1)),i.trim().length!==0)try{let s=JSON.parse(i);if(s.type==="response"){let n=s,o=this.pendingRequests.get(n.id||"");o&&(this.pendingRequests.delete(n.id||""),window.clearTimeout(o.timeout),o.resolve(n))}else this.emit("event",s)}catch(s){console.error("[pi-agent] Failed to parse JSON line:",i,s)}}}async sendCommand(t){if(!this.process||this.process.killed)throw new Error("Process not running");let e=t.id||`cmd-${++this.nextId}`;return t.id=e,new Promise((i,s)=>{let n=window.setTimeout(()=>{this.pendingRequests.has(e)&&(this.pendingRequests.delete(e),s(new Error(`Command ${t.type} timed out`)))},6e4);this.pendingRequests.set(e,{resolve:i,reject:s,timeout:n});let o=JSON.stringify(t)+`
`;try{this.process.stdin.write(o)}catch(a){this.pendingRequests.delete(e),window.clearTimeout(n),s(a instanceof Error?a:new Error(String(a)))}})}sendFireAndForget(t){if(!this.process||this.process.killed){console.warn("[pi-agent] Cannot send, process not running");return}t.id||(t.id=`ff-${++this.nextId}`);try{this.process.stdin.write(JSON.stringify(t)+`
`)}catch(e){console.error("[pi-agent] Failed to send command:",e)}}async prompt(t,e){return this.sendCommand({type:"prompt",message:t,...e?.streamingBehavior&&{streamingBehavior:e.streamingBehavior},...e?.images&&{images:e.images}})}async steer(t,e){return this.sendCommand({type:"steer",message:t,...e?.images&&{images:e.images}})}async followUp(t,e){return this.sendCommand({type:"follow_up",message:t,...e?.images&&{images:e.images}})}abort(){this.sendFireAndForget({type:"abort"})}async getState(){return this.sendCommand({type:"get_state"})}async getMessages(){return this.sendCommand({type:"get_messages"})}async setModel(t,e){return this.sendCommand({type:"set_model",provider:t,modelId:e})}async setThinkingLevel(t){return this.sendCommand({type:"set_thinking_level",level:t})}async getAvailableModels(){return this.sendCommand({type:"get_available_models"})}async bash(t){return this.sendCommand({type:"bash",command:t})}async getSessionStats(){return this.sendCommand({type:"get_session_stats"})}async switchSession(t){return this.sendCommand({type:"switch_session",sessionPath:t})}async exportHtml(t){return this.sendCommand({type:"export_html",...t?{outputPath:t}:{}})}async getCommands(){return this.sendCommand({type:"get_commands"})}async getLastAssistantText(){return this.sendCommand({type:"get_last_assistant_text"})}async getForkMessages(){return this.sendCommand({type:"get_fork_messages"})}async fork(t){return this.sendCommand({type:"fork",entryId:t})}async clone(){return this.sendCommand({type:"clone"})}async promptAndWait(t){return await this.prompt(t),this.waitForAgentEnd().then(()=>this.getLastAssistantText())}waitForAgentEnd(t=12e4){return new Promise((e,i)=>{let s=window.setTimeout(()=>{this.off("event",n),i(new Error("Timed out waiting for assistant response"))},t),n=o=>{o.type==="agent_end"&&(window.clearTimeout(s),this.off("event",n),e())};this.on("event",n)})}async newSession(){return this.sendCommand({type:"new_session"})}async compact(t){let e={type:"compact"};return t&&(e.customInstructions=t),this.sendCommand(e)}sendUIResponse(t,e){this.sendFireAndForget({type:"extension_ui_response",id:t,...e})}async oauthLogin(t){return{type:"response",command:"oauth_login",success:!1,error:"oauth_login is not a Pi RPC command. Use the device-code login flow from the Pimate settings tab instead."}}isRunning(){return this.process!==null&&!this.process.killed}async restart(){await this.destroy(),this.destroyed=!1,await this.start()}async destroy(){if(!this.destroyed){this.destroyed=!0;for(let[,t]of this.pendingRequests)window.clearTimeout(t.timeout),t.reject(new Error("Client destroyed"));if(this.pendingRequests.clear(),this.process){let t=this.process;this.process=null,t.killed||(t.kill("SIGTERM"),await new Promise(e=>window.setTimeout(e,500)),t.killed||t.kill("SIGKILL"))}}}};var U="pimate-chat-view",Z=class extends h.ItemView{plugin;client=null;chatContainer=null;messageNavEl=null;inputEl=null;streamingTextEl=null;streamingCursorEl=null;sessionTabsEl=null;contextRowEl=null;imagePreviewEl=null;widgetEl=null;abortBtn=null;statusBar=null;speedEl=null;speedStartedAt=null;speedEstimatedTokens=0;speedTimer=null;speedHideTimer=null;footerModelLabel=null;footerModelDropdown=null;effortSelector=null;effortGearsEl=null;footerEffortCurrent=null;footerEffortOptions=null;compactedContextActive=!1;footerContextEl=null;footerContextFillEl=null;footerContextPercentEl=null;smartReviewToggleEl=null;smartReviewContinues=0;smartReviewOriginalGoal=null;renderedMessages=[];pendingUserImages=[];historyShownCount=0;historyTotalCount=0;historyBannerEl=null;tabs=[];activeTabId=null;historyPanelEl=null;modelPopupEl=null;effortPopupEl=null;isHistoryOpen=!1;nextTabNumber=1;contextItems=[];isStreaming=!1;currentAssistantMsg=null;currentTextBlock=null;currentThinkingBlock=null;currentThinkingContent=null;thinkingStartedAt=null;thinkingTimer=null;shouldAutoScroll=!0;pendingUIRequests=new Map;lastRenderTime=0;renderTimeout=null;currentRawText="";currentBlockRawText="";mentionDropdown=null;filteredMentionFiles=[];activeMentionIndex=0;mentionQueryStart=-1;commandDropdown=null;filteredCommands=[];activeCommandIndex=0;commandQueryStart=-1;availableCommands=[];constructor(t,e){super(t),this.plugin=e}setInputText(t){this.inputEl&&(this.inputEl.value=t,this.resizeInputEl(),this.inputEl.focus())}prependInputText(t){this.inputEl&&(this.inputEl.value=t+this.inputEl.value,this.resizeInputEl(),this.inputEl.focus())}appendInputText(t){if(!this.inputEl)return;let e=this.inputEl.value.length>0&&!/\s$/.test(this.inputEl.value);this.inputEl.value=`${this.inputEl.value}${e?" ":""}${t}`,this.resizeInputEl(),this.inputEl.focus()}resizeInputEl(){this.inputEl&&(this.inputEl.setCssProps({height:"auto"}),this.inputEl.setCssProps({height:`${Math.min(this.inputEl.scrollHeight,240)}px`}))}focusComposer(){this.inputEl?.focus()}runAsync(t){t().catch(e=>{console.error("[pimate] async action failed",e),new h.Notice(e instanceof Error?e.message:String(e))})}async newChatSession(){await this.newSession()}async closeActiveSessionTab(){this.activeTabId&&await this.closeTab(this.activeTabId)}async resumePreviousSession(){await this.showResumeSelector()}async forkFromPreviousPrompt(){await this.showForkSelector()}async cloneCurrentSessionBranch(){await this.cloneCurrentBranch()}scrollToPreviousMessage(){this.focusAdjacentMessage(-1)}scrollToNextMessage(){this.focusAdjacentMessage(1)}toggleLastToolBlock(){let t=Array.from(this.chatContainer?.querySelectorAll(".pi-agent-tool-output")||[]),e=t[t.length-1];e&&e.toggleClass("is-visible",!e.hasClass("is-visible"))}scrollToLastDiff(){Array.from(this.chatContainer?.querySelectorAll(".pi-agent-diff-pre")||[]).pop()?.scrollIntoView({block:"center",behavior:"smooth"})}addActiveFileContext(){this.addCurrentFileContext()}addExplorerSelectionContext(){let t=this.plugin.settings.language==="zh",e=this.plugin.getExplorerSelectionForContext();if(e.length===0){new h.Notice(t?"Pimate\uFF1A\u6CA1\u6709\u68C0\u6D4B\u5230\u6587\u4EF6\u7BA1\u7406\u5668\u9009\u4E2D\u9879\u3002\u8BF7\u5148\u5728\u5DE6\u4FA7\u6587\u4EF6\u7BA1\u7406\u5668\u4E2D\u591A\u9009\u6587\u4EF6/\u6587\u4EF6\u5939\u3002":"Pimate: no file-explorer selection detected. Select files/folders in the file explorer first.");return}let i=0;for(let s of e)s instanceof h.TFile?(this.addFileContextItem(s),i++):s instanceof h.TFolder&&(this.addFolderContextItem(s,!0),i++);new h.Notice(t?`Pimate\uFF1A\u5DF2\u9644\u52A0 ${i} \u4E2A\u9009\u4E2D\u9879\u5230\u4E0A\u4E0B\u6587`:`Pimate: attached ${i} selected item${i===1?"":"s"} to context`),this.inputEl?.focus()}openCommandsAndSkills(){this.runAsync(()=>this.showCommandSelector())}addSelectionContext(t){let e=t.trim();e&&(this.addContextItem({id:`ctx-sel-${Date.now()}-${Math.random().toString(36).slice(2)}`,type:"selection",label:`${e.slice(0,28)}${e.length>28?"\u2026":""}`,value:e}),this.inputEl?.focus())}getViewType(){return U}getDisplayText(){return"Pimate"}getIcon(){return"pimate-logo"}async onOpen(){let t=this.containerEl.children[1];t.empty(),t.addClass("pi-agent-container");let e=this.plugin.settings.language==="zh",i=t.createDiv("pi-agent-header"),s=i.createDiv("pi-agent-title");s.createSpan({text:"\u03C0",cls:"pi-agent-logo"}),s.createSpan({text:"Pimate"}),this.speedEl=i.createDiv("pi-agent-speed-indicator pi-agent-hidden"),this.speedEl.setAttribute("title",e?"\u5B9E\u65F6\u8F93\u51FA\u901F\u5EA6\uFF08\u4F30\u7B97\uFF09":"Realtime output speed (estimated)");let n=i.createDiv("pi-agent-header-actions"),o=n.createDiv("pi-agent-mini-action");(0,h.setIcon)(o,"more-horizontal"),o.setAttribute("title",e?"\u66F4\u591A\u64CD\u4F5C":"More actions"),o.onclick=f=>this.showMoreMenu(f);let a=n.createDiv("pi-agent-mini-action");(0,h.setIcon)(a,"settings"),a.setAttribute("title",e?"\u63D2\u4EF6\u8BBE\u7F6E":"Plugin settings"),a.onclick=()=>{let f=this.app.setting;f&&(f.open(),f.openTabById(this.plugin.manifest.id))},this.chatContainer=t.createDiv("pi-agent-chat"),this.renderEmptyState(),this.historyPanelEl=t.createDiv("pi-agent-history-panel"),this.historyPanelEl.addClass("pi-agent-hidden"),this.widgetEl=t.createDiv("pi-agent-widget"),this.widgetEl.addClass("pi-agent-hidden");let r=t.createDiv("pi-agent-composer-tools");this.sessionTabsEl=r.createDiv("pi-agent-session-tabs");let l=r.createDiv("pi-agent-composer-actions"),d=l.createDiv("pi-agent-mini-action");(0,h.setIcon)(d,"square-plus"),d.setAttribute("title",e?"\u65B0\u5EFA\u4F1A\u8BDD\u5361":"New tab"),d.onclick=()=>{let f=this.plugin.settings.maxTabs||3;this.tabs.length<f?this.runAsync(()=>this.createAndSwitchTab()):new h.Notice(e?`\u5DF2\u8FBE\u5230\u6700\u5927\u4F1A\u8BDD\u5361\u6570\u91CF\u9650\u5236 (${f})`:`Maximum tab count reached (${f})`)},d.addEventListener("contextmenu",f=>{f.preventDefault(),f.stopPropagation();let D=new h.Menu;D.addItem(O=>{O.setTitle(e?"\u91CD\u7F6E\u6240\u6709\u4F1A\u8BDD\u5361 (1, 2, 3)":"Reset all session tabs").setIcon("refresh-cw").onClick(()=>this.runAsync(async()=>{for(let F of this.tabs)await F.client?.destroy(),F.client=null,F.sessionFile=void 0,F.sessionId=void 0,F.restored=!1,F.label=F.id.split("-").pop()||"Tab";this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],this.renderEmptyState();let _=this.activeTab;_&&(await this.ensureTabClient(_),this.client=_.client,await this.refreshStateDisplay(),await this.loadAvailableCommands()),this.renderTabs(),this.updateButtons(),await this.persistSessionTabs(),new h.Notice(e?"\u6240\u6709\u4F1A\u8BDD\u5361\u5747\u5DF2\u91CD\u7F6E":"All session tabs reset")}))}),D.showAtMouseEvent(f)});let c=l.createDiv("pi-agent-mini-action");(0,h.setIcon)(c,"square-pen"),c.setAttribute("title",e?"\u65B0\u5EFA/\u91CD\u7F6E\u5F53\u524D\u4F1A\u8BDD":"New conversation"),c.onclick=()=>this.runAsync(()=>this.newSession()),c.addEventListener("contextmenu",f=>{f.preventDefault(),f.stopPropagation();let D=new h.Menu;D.addItem(O=>{O.setTitle(e?"\u5206\u652F\u5F53\u524D\u4F1A\u8BDD...":"Fork current conversation...").setIcon("git-fork").onClick(()=>this.runAsync(()=>this.showForkSelector()))}),D.addItem(O=>{O.setTitle(e?"\u514B\u9686\u5F53\u524D\u4F1A\u8BDD\u5206\u652F":"Clone current branch").setIcon("copy").onClick(()=>this.runAsync(()=>this.cloneCurrentBranch()))}),D.showAtMouseEvent(f)});let p=l.createDiv("pi-agent-mini-action");(0,h.setIcon)(p,"history"),p.setAttribute("title",e?"\u6062\u590D\u4F1A\u8BDD/\u5386\u53F2":"History sessions"),p.onclick=()=>this.runAsync(()=>this.toggleHistoryPanel()),p.addEventListener("contextmenu",f=>{f.preventDefault(),f.stopPropagation();let D=new h.Menu;D.addItem(O=>{O.setTitle(e?"\u6253\u5F00\u5386\u53F2\u4F1A\u8BDD\u4FDD\u5B58\u76EE\u5F55":"Open history sessions directory").setIcon("folder").onClick(()=>{try{let _=(0,B.join)((0,V.homedir)(),".pi","sessions");window.require?.("electron")?.shell?.openPath(_)}catch(_){new h.Notice(e?`\u65E0\u6CD5\u6253\u5F00\u76EE\u5F55: ${_.message}`:`Cannot open dir: ${_.message}`)}})}),D.showAtMouseEvent(f)});let m=t.createDiv("pi-agent-input-area");this.contextRowEl=m.createDiv("pi-agent-context-row"),this.imagePreviewEl=m.createDiv("pi-agent-image-preview");let v=m.createDiv("pi-agent-input-row");this.inputEl=v.createEl("textarea",{cls:"pi-agent-input",attr:{placeholder:"How can I help you today?",rows:"4"}});let T=v.createDiv("pi-agent-input-right").createDiv("pi-agent-message-nav"),k=(f,D,O,_)=>{let F=T.createDiv(`pi-agent-message-nav-btn ${f}`);return(0,h.setIcon)(F,D),F.setAttribute("title",O),F.onclick=_,F};k("is-first","chevrons-up","Jump to first user message",()=>this.focusEdgeMessage("first")),k("is-prev","chevron-up","Previous user message (Alt+\u2191)",()=>this.focusAdjacentMessage(-1)),k("is-next","chevron-down","Next user message (Alt+\u2193)",()=>this.focusAdjacentMessage(1)),k("is-last","chevrons-down","Jump to last user message",()=>this.focusEdgeMessage("last")),this.messageNavEl=T,this.inputEl.addEventListener("keydown",f=>{if(this.mentionDropdown&&this.filteredMentionFiles.length>0){if(f.key==="ArrowDown"){f.preventDefault(),this.activeMentionIndex=(this.activeMentionIndex+1)%this.filteredMentionFiles.length,this.renderMentionDropdownItems();return}else if(f.key==="ArrowUp"){f.preventDefault(),this.activeMentionIndex=(this.activeMentionIndex-1+this.filteredMentionFiles.length)%this.filteredMentionFiles.length,this.renderMentionDropdownItems();return}else if(f.key==="Enter"){f.preventDefault(),this.insertMentionSelection();return}else if(f.key==="Escape"){f.preventDefault(),this.closeMentionDropdown();return}}if(this.commandDropdown&&this.filteredCommands.length>0){if(f.key==="ArrowDown"){f.preventDefault(),this.activeCommandIndex=(this.activeCommandIndex+1)%this.filteredCommands.length,this.renderCommandDropdownItems();return}else if(f.key==="ArrowUp"){f.preventDefault(),this.activeCommandIndex=(this.activeCommandIndex-1+this.filteredCommands.length)%this.filteredCommands.length,this.renderCommandDropdownItems();return}else if(f.key==="Enter"){f.preventDefault(),this.insertCommandSelection();return}else if(f.key==="Escape"){f.preventDefault(),this.closeCommandDropdown();return}}f.key==="Enter"&&!f.shiftKey&&!f.isComposing?(f.preventDefault(),this.runAsync(()=>this.sendMessage())):f.key==="/"&&this.inputEl?.selectionStart===0&&!this.inputEl.value?window.setTimeout(()=>this.runAsync(()=>this.showCommandSelector()),0):(f.ctrlKey||f.metaKey)&&f.key.toLowerCase()==="k"?(f.preventDefault(),this.runAsync(()=>this.showCommandSelector())):(f.ctrlKey||f.metaKey)&&f.key.toLowerCase()==="n"?(f.preventDefault(),this.runAsync(()=>this.newSession())):f.altKey&&f.key==="ArrowUp"?(f.preventDefault(),this.scrollToPreviousMessage()):f.altKey&&f.key==="ArrowDown"?(f.preventDefault(),this.scrollToNextMessage()):(f.ctrlKey||f.metaKey)&&f.shiftKey&&f.key.toLowerCase()==="e"?(f.preventDefault(),this.toggleLastToolBlock()):(f.ctrlKey||f.metaKey)&&f.shiftKey&&f.key.toLowerCase()==="d"?(f.preventDefault(),this.scrollToLastDiff()):f.key==="Escape"&&this.isStreaming&&(f.preventDefault(),this.abortAgent())}),this.inputEl.addEventListener("paste",f=>{this.runAsync(()=>this.handlePaste(f))}),this.inputEl.addEventListener("dragover",f=>{f.preventDefault(),this.inputEl?.addClass("is-drag-over")}),this.inputEl.addEventListener("dragleave",()=>{this.inputEl?.removeClass("is-drag-over")}),this.inputEl.addEventListener("drop",f=>{this.runAsync(()=>this.handleDrop(f))}),this.inputEl.addEventListener("input",()=>{this.updateInputModeState(),this.handleMentionInput(),this.handleCommandInput(),this.resizeInputEl()});let M=m.createDiv("pi-agent-input-footer"),x=M.createDiv("pi-agent-input-footer-left"),y=x.createDiv("pi-agent-model-selector").createDiv("pi-agent-model-btn");this.footerModelLabel=y.createSpan("pi-agent-model-label"),this.footerModelLabel.setText(this.getModelShortName(this.plugin.settings.modelId||"Sonnet")),this.footerModelLabel.setAttribute("title",`${this.plugin.settings.provider||""}/${this.plugin.settings.modelId||""}`),y.onclick=f=>{f.stopPropagation(),this.runAsync(()=>this.toggleModelPopup(y))},this.effortSelector=x.createDiv("pi-agent-thinking-effort"),this.effortSelector.createSpan("pi-agent-thinking-label-text").setText("Effort:"),this.effortGearsEl=this.effortSelector.createDiv("pi-agent-thinking-gears"),this.footerEffortCurrent=this.effortGearsEl.createDiv("pi-agent-thinking-current"),this.footerEffortCurrent.setText(this.getThinkingLevelLabel(this.plugin.settings.thinkingLevel)),this.effortGearsEl.onclick=f=>{f.stopPropagation(),this.effortGearsEl&&this.runAsync(()=>this.toggleEffortPopup(this.effortGearsEl))};let S=x.createSpan({cls:"pi-agent-footer-folder-btn",attr:{title:e?"\u9009\u62E9\u6587\u4EF6\u4E0A\u4E0B\u6587":"Select file context"}});(0,h.setIcon)(S,"folder"),S.onclick=()=>this.runAsync(()=>this.addFileContext()),this.statusBar=x.createSpan({text:"Starting\u2026",cls:"pi-agent-status pi-agent-status-thinking"}),this.footerContextEl=x.createSpan({cls:"pi-agent-context-meter-inline",attr:{title:"Context usage"}});let P=this.footerContextEl.createSvg("svg",{attr:{viewBox:"0 0 24 24",width:"18",height:"18"}});P.createSvg("circle",{cls:"pi-agent-context-meter-bg",attr:{cx:"12",cy:"12",r:"8",fill:"none","stroke-width":"2"}}),this.footerContextFillEl=P.createSvg("circle",{cls:"pi-agent-context-meter-fill",attr:{cx:"12",cy:"12",r:"8",fill:"none","stroke-width":"2","stroke-linecap":"round"}}),this.footerContextPercentEl=this.footerContextEl.createSpan({text:"",cls:"pi-agent-context-meter-percent"});let L=M.createDiv("pi-agent-input-footer-right");this.smartReviewToggleEl=L.createSpan({cls:"pi-agent-smart-review-toggle"}),this.smartReviewToggleEl.onclick=()=>{this.runAsync(async()=>{this.plugin.settings.smartReviewEnabled=!this.plugin.settings.smartReviewEnabled,await this.plugin.saveSettings(),this.updateSmartReviewToggleUI()})},this.updateSmartReviewToggleUI(),this.abortBtn=L.createEl("button",{text:"\xD7",cls:"pi-agent-footer-btn pi-agent-abort-btn",attr:{title:"Abort"}}),this.abortBtn.addClass("pi-agent-hidden"),this.abortBtn.onclick=()=>this.abortAgent(),await this.restoreOrCreateInitialTab()}get activeTab(){return this.tabs.find(t=>t.id===this.activeTabId)??null}async restoreOrCreateInitialTab(){let t=this.plugin.settings.maxTabs||3,e=this.plugin.settings.sessionTabs||[];this.tabs=[];let i=e.length>0?Math.min(e.length,t):t;for(let n=1;n<=i;n++){let o=e[n-1];this.tabs.push({id:`tab-static-${n}`,label:String(n),client:null,isStreaming:!1,modelProvider:o?.modelProvider,modelId:o?.modelId,thinkingLevel:o?.thinkingLevel,sessionFile:o?.sessionFile,sessionId:o?.sessionId,restored:!!o?.sessionFile})}let s=this.tabs.find(n=>n.sessionFile?.toLowerCase()===this.plugin.settings.activeSessionFile?.toLowerCase())||this.tabs[0];this.activeTabId=s?.id||null,this.renderTabs(),s&&await this.switchToTab(s.id)}async createAndSwitchTab(){let t={id:`tab-${Date.now()}-${Math.random().toString(36).slice(2)}`,label:"",client:null,isStreaming:!1,modelProvider:this.plugin.settings.provider,modelId:this.plugin.settings.modelId,thinkingLevel:this.plugin.settings.thinkingLevel};this.tabs.push(t),this.activeTabId=t.id,this.renderTabs(),await this.ensureTabClient(t),await this.switchToTab(t.id),await this.persistSessionTabs()}renderTabs(){if(!this.sessionTabsEl)return;this.sessionTabsEl.empty();let t=this.plugin.settings.language==="zh";for(let e=0;e<this.tabs.length;e++){let i=this.tabs[e],s=this.sessionTabsEl.createSpan({cls:`pi-agent-session-tab ${i.id===this.activeTabId?"is-active":""}`,attr:{title:t?`\u4F1A\u8BDD\u5361 ${e+1}`:`Session ${e+1}`}});s.createSpan({text:String(e+1),cls:"pi-agent-session-tab-label"}),s.onclick=()=>this.runAsync(()=>this.switchToTab(i.id)),s.addEventListener("contextmenu",n=>{n.preventDefault(),n.stopPropagation(),this.runAsync(()=>this.closeTab(i.id))})}}async resetTabSession(t){let e=this.plugin.settings.language==="zh";if(t.isStreaming){new h.Notice(e?"\u8BE5\u4F1A\u8BDD\u6B63\u5728\u6D41\u5F0F\u4F20\u8F93\uFF0C\u8BF7\u5148\u505C\u6B62":"Streaming active, please stop first");return}await t.client?.destroy(),t.client=null,t.sessionFile=void 0,t.sessionId=void 0,t.restored=!1,t.label=t.id.split("-").pop()||"Tab",t.id===this.activeTabId&&(this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],this.renderEmptyState(),await this.ensureTabClient(t),this.client=t.client,await this.refreshStateDisplay(),await this.loadAvailableCommands()),this.renderTabs(),this.updateButtons(),await this.persistSessionTabs(),new h.Notice(e?`\u4F1A\u8BDD\u5361 ${t.label} \u5DF2\u91CD\u7F6E`:`Session tab ${t.label} reset`)}async switchToTab(t){let e=this.tabs.find(i=>i.id===t);e&&(this.activeTabId=e.id,this.client=e.client,this.isStreaming=e.isStreaming,this.renderTabs(),this.resetActiveRenderState(),this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],this.historyShownCount=0,this.historyTotalCount=0,this.historyBannerEl=null,this.renderEmptyState(),this.updateWidget("tasks",void 0),await this.ensureTabClient(e),this.client=e.client,this.renderActiveTabRuntimeStatus(),this.renderActiveTabSpeed(),this.refreshStateDisplay(),this.loadAvailableCommands(),await this.loadMessages(),this.renderActiveTabRuntimeStatus(),this.renderActiveTabSpeed(),this.renderActiveTabModelAndEffort(),this.updateButtons(),this.persistSessionTabs())}async closeTab(t){let e=this.tabs.findIndex(s=>s.id===t);if(e===-1)return;let[i]=this.tabs.splice(e,1);if(await i.client?.destroy(),i.client=null,this.tabs.length===0){this.activeTabId=null,this.client=null,await this.createAndSwitchTab();return}if(this.activeTabId===t){let s=this.tabs[Math.max(0,e-1)]||this.tabs[0];await this.switchToTab(s.id)}else this.renderTabs();await this.persistSessionTabs()}isSessionFileInCurrentWorkspace(t){if(!t)return!1;let e=this.app.vault.adapter.getBasePath?.()||"";if(!e)return!0;let i=this.encodeWorkspacePath(e).toLowerCase();return t.toLowerCase().replace(/\\/g,"/").includes(`/sessions/${i}/`)}async ensureTabClient(t){if(t.sessionFile&&!this.isSessionFileInCurrentWorkspace(t.sessionFile)&&(console.log(`[pi-agent] SessionFile ${t.sessionFile} belongs to another workspace, unbinding to start fresh.`),t.sessionFile=void 0,t.sessionId=void 0,t.restored=!1),t.client?.isRunning()){await this.applyTabRuntimePreferences(t);return}let e=this.createClient(t);t.client=e,e.on("event",i=>{this.recordTabRuntimeState(t,i),this.activeTabId===t.id&&this.handleEvent(i)}),e.on("error",i=>{this.activeTabId===t.id&&this.setStatus(`\u274C Error: ${i.message}`,"error")}),e.on("close",()=>{t.isStreaming=!1,this.activeTabId===t.id&&(this.setStatus("\u26A0\uFE0F Pi process disconnected","warning"),this.isStreaming=!1,this.updateButtons())});try{if(await e.start(),t.sessionFile){let i=await e.switchSession(t.sessionFile);(!i.success||i.data?.cancelled)&&new h.Notice(`Failed to restore session: ${t.label}`)}await this.applyTabRuntimePreferences(t),this.activeTabId===t.id&&(this.setStatus("Ready","ok"),this.loadAvailableCommands())}catch(i){this.activeTabId===t.id&&this.setStatus(`\u274C Failed to start pi: ${i.message}`,"error")}}createClient(t){let e=this.plugin.settings,i=this.app.vault.adapter,s=i instanceof h.FileSystemAdapter?i.getBasePath():void 0,n=t?.modelProvider||e.provider,o=t?.modelId||e.modelId,a=t?.thinkingLevel||e.thinkingLevel;return new Y({piPath:e.piPath,provider:n,modelId:o,thinkingLevel:a,apiKey:this.readProviderApiKey(n)||e.apiKey,cwd:s,noSession:!1})}readProviderApiKey(t){try{let e=(0,B.join)((0,V.homedir)(),".pi","agent","auth.json");if(!(0,A.existsSync)(e))return"";let s=JSON.parse((0,A.readFileSync)(e,"utf-8"))?.[t];return s&&s.type==="api_key"&&typeof s.key=="string"?s.key.trim():""}catch(e){return console.warn("[pimate] readProviderApiKey failed:",e),""}}async applyTabRuntimePreferences(t){if(t.client)try{t.modelProvider&&t.modelId&&await t.client.setModel(t.modelProvider,t.modelId),typeof t.thinkingLevel=="string"&&await t.client.setThinkingLevel(t.thinkingLevel)}catch(e){console.warn("[pimate] failed to apply tab runtime preferences",e)}finally{await this.syncTabStateFromPi(t)}}async updateActiveTabModel(t,e){let i=this.activeTab;if(!i?.client){i&&(i.modelProvider=t,i.modelId=e),this.plugin.settings.provider=t,this.plugin.settings.modelId=e,await this.plugin.saveSettings(),await this.persistSessionTabs(),this.updateModelDisplay(t,e);return}let s;try{s=await i.client.setModel(t,e)}catch(n){throw console.error("[pimate] setModel failed",n),n}if(!s?.success)throw new Error(s?.error||"setModel failed");i.piModelMeta=this.extractPiModelFromRpcData(s.data),await this.syncTabStateFromPi(i),this.effortPopupEl&&this.closeEffortPopup()}async updateActiveTabThinkingLevel(t){let e=this.activeTab;if(!e?.client){e&&(e.thinkingLevel=t),await this.persistSessionTabs(),this.footerEffortCurrent&&this.footerEffortCurrent.setText(this.getThinkingLevelLabel(t));return}let i;try{i=await e.client.setThinkingLevel(t)}catch(s){throw console.error("[pimate] setThinkingLevel failed",s),s}if(!i?.success)throw new Error(i?.error||"setThinkingLevel failed");await this.syncTabStateFromPi(e)}extractPiModelFromRpcData(t){if(!t||typeof t!="object")return null;let e=t;if(e.model&&typeof e.model=="object"){let s=e.model;if(typeof s.id=="string"&&typeof s.provider=="string")return s}let i=t;return typeof i.id=="string"&&typeof i.provider=="string"?i:null}async syncTabStateFromPi(t){if(!t.client)return;let e=t.client,i=(t.syncSeq??0)+1;t.syncSeq=i;let s;try{s=await e.getState()}catch(n){console.warn("[pimate] getState failed",n);return}t.syncSeq===i&&t.client===e&&(!s?.success||!s.data||this.applyAuthoritativePiState(t,s.data))}applyAuthoritativePiState(t,e){let i=t.modelProvider,s=t.modelId,n=t.thinkingLevel;e.model&&(t.piModelMeta=e.model,t.modelProvider=e.model.provider,t.modelId=e.model.id),typeof e.thinkingLevel=="string"?t.thinkingLevel=e.thinkingLevel:e.thinkingLevel==null&&t.piModelMeta?.reasoning===!1&&(t.thinkingLevel="");let o=i!==t.modelProvider||s!==t.modelId,a=n!==t.thinkingLevel,r=!1;o&&t.modelProvider&&t.modelId&&t===this.activeTab&&(this.plugin.settings.provider=t.modelProvider,this.plugin.settings.modelId=t.modelId,r=!0),a&&t.thinkingLevel!==void 0&&t===this.activeTab&&(this.plugin.settings.thinkingLevel=t.thinkingLevel,r=!0),(o||a)&&(this.persistSessionTabs(),r&&this.plugin.saveSettings(),o&&t.modelProvider&&t.modelId&&t===this.activeTab&&this.updateModelDisplay(t.modelProvider,t.modelId),a&&t===this.activeTab&&this.footerEffortCurrent&&this.footerEffortCurrent.setText(this.getThinkingLevelLabel(t.thinkingLevel??"")))}resetActiveRenderState(){this.currentAssistantMsg=null,this.currentTextBlock=null,this.currentThinkingBlock=null,this.currentThinkingContent=null,this.currentBlockRawText=""}getQueueTotal(t){let e=t.steering,i=t.followUp;return(e?.length||0)+(i?.length||0)}recordTabRuntimeState(t,e){switch(e.type){case"agent_start":t.isStreaming=!0;break;case"agent_end":t.isStreaming=!1;break;case"queue_update":t.queueCount=this.getQueueTotal(e);break;case"thinking_level_changed":case"model_changed":this.syncTabStateFromPi(t);break}}renderActiveTabRuntimeStatus(){let t=this.activeTab;if(!t){this.setStatus("\u2705 Ready","ok");return}let e=t.queueCount||0;e>0?this.setStatus(`\u{1F4CB} ${e} queued message(s)`,"thinking"):t.isStreaming?this.setStatus("\u{1F914} Thinking...","thinking"):this.setStatus("\u2705 Ready","ok")}handleEvent(t){switch(t.type){case"agent_start":this.isStreaming=!0,this.activeTab&&(this.activeTab.isStreaming=!0),this.startSpeedIndicator(),this.updateButtons(),this.setStatus("\u{1F914} Thinking...","thinking");break;case"agent_end":this.isStreaming=!1,this.activeTab&&(this.activeTab.isStreaming=!1),this.currentAssistantMsg=null,this.currentTextBlock=null,this.currentThinkingBlock=null,this.currentThinkingContent=null,this.stopSpeedIndicator(),this.updateButtons(),this.renderActiveTabRuntimeStatus(),this.refreshStateDisplay(),this.maybeAutoContinueSmartReview();break;case"message_start":this.handleMessageStart(t);break;case"message_update":this.handleMessageUpdate(t);break;case"message_end":this.handleMessageEnd(t);break;case"tool_execution_start":this.handleToolStart(t);break;case"tool_execution_update":this.handleToolUpdate(t);break;case"tool_execution_end":this.handleToolEnd(t);break;case"turn_start":this.setStatus("\u{1F504} Processing turn...","thinking");break;case"turn_end":this.renderActiveTabRuntimeStatus();break;case"queue_update":this.handleQueueUpdate(t);break;case"thinking_level_changed":case"model_changed":this.activeTab&&this.recordTabRuntimeState(this.activeTab,t);break;case"compaction_start":this.setStatus("\u{1F4E6} Compacting context...","thinking");break;case"compaction_end":this.compactedContextActive=!t.aborted,this.setStatus("\u2705 Compaction complete","ok");break;case"extension_ui_request":this.handleExtensionUIRequest(t);break;default:console.log("[pi-agent] Unhandled event:",t.type,t)}}handleMessageStart(t){let e=t.message;if(e)if(e.role==="user"){let i=typeof e.content=="string"?e.content:e.content?.map(n=>n.text||n.thinking||"").join("")||"",s=this.addMessage("user",this.stripRecentContextGuard(i));this.pendingUserImages.length>0&&(this.renderUserMessageImages(s,this.pendingUserImages),this.pendingUserImages=[])}else e.role==="assistant"?(this.currentAssistantMsg=this.addMessage("assistant",""),this.currentTextBlock=null,this.currentThinkingBlock=null,this.currentThinkingContent=null,this.currentRawText="",this.currentBlockRawText="",this.lastRenderTime=0,this.renderTimeout&&(window.clearTimeout(this.renderTimeout),this.renderTimeout=null),this.scrollToBottom(!0,!0)):e.role}ensureAssistantStreamMessage(){return this.currentAssistantMsg||(this.currentAssistantMsg=this.addMessage("assistant",""),this.currentTextBlock=null,this.currentThinkingBlock=null,this.currentThinkingContent=null,this.currentRawText="",this.currentBlockRawText="",this.lastRenderTime=0),this.currentAssistantMsg}handleMessageUpdate(t){let e=t.assistantMessageEvent;if(e)switch(e.type){case"text_start":this.currentBlockRawText="",this.currentTextBlock=null,this.streamingTextEl=null,this.streamingCursorEl=null;break;case"text_delta":{let i=this.ensureAssistantStreamMessage();if(!this.currentTextBlock){let o=this.shouldUsePrettyStreaming(0);this.currentTextBlock=i.contentEl.createDiv(o?"pi-agent-text-block markdown-preview-view markdown-rendered":"pi-agent-text-block pi-agent-streaming-block"),o||(this.streamingTextEl=this.currentTextBlock.createDiv("pi-agent-streaming-text"),this.streamingCursorEl=this.currentTextBlock.createSpan("pi-agent-streaming-cursor"))}let s=e.delta||"";this.currentBlockRawText+=s,this.currentRawText+=s,this.addSpeedDelta(s),this.currentTextBlock.setAttribute("data-stream-raw",this.currentBlockRawText),this.shouldUsePrettyStreaming(this.currentBlockRawText.length)?this.throttleRender(this.currentBlockRawText,this.currentTextBlock):(this.currentTextBlock.classList.contains("pi-agent-streaming-block")||this.convertCurrentTextBlockToFastStreaming(),this.appendStreamingDelta(this.currentBlockRawText,s));break}case"thinking_start":if(this.plugin.settings.showThinking){let i=this.ensureAssistantStreamMessage();this.thinkingStartedAt=Date.now(),this.currentThinkingBlock=i.contentEl.createDiv("pi-agent-thinking-block");let s=this.currentThinkingBlock.createDiv("pi-agent-thinking-header"),n=s.createSpan("pi-agent-thinking-icon");(0,h.setIcon)(n,"brain"),s.createSpan("pi-agent-thinking-text").setText(" Thinking (1s)..."),this.currentThinkingContent=this.currentThinkingBlock.createDiv("pi-agent-thinking-content");let a=this.currentThinkingBlock;s.onclick=()=>{a.toggleClass("is-collapsed",!a.hasClass("is-collapsed"))},this.thinkingTimer&&window.clearInterval(this.thinkingTimer),this.thinkingTimer=window.setInterval(()=>{let r=this.thinkingStartedAt?Math.max(1,Math.round((Date.now()-this.thinkingStartedAt)/1e3)):1,l=s.querySelector(".pi-agent-thinking-text");l&&l.setText(` Thinking (${r}s)...`)},1e3)}break;case"thinking_delta":if(this.currentThinkingContent){let i=this.isNearBottom();this.currentThinkingContent.appendText(e.delta||""),i&&this.scrollToBottom(!0,!0)}break;case"thinking_end":if(this.thinkingTimer&&(window.clearInterval(this.thinkingTimer),this.thinkingTimer=null),this.currentThinkingBlock){this.currentThinkingBlock.addClass("is-collapsed");let i=this.currentThinkingBlock.querySelector(".pi-agent-thinking-header");if(i){let s=this.thinkingStartedAt?Math.max(1,Math.round((Date.now()-this.thinkingStartedAt)/1e3)):0,n=i.querySelector(".pi-agent-thinking-text");n&&n.setText(s>0?` Thought for ${s}s`:" Thought")}}break;case"toolcall_start":break;case"done":break;case"error":{let i=this.ensureAssistantStreamMessage();i.contentEl.createDiv("pi-agent-error-block").textContent=`\u26A0\uFE0F Error: ${e.reason||"Unknown error"}`;break}}}handleMessageEnd(t){if(this.thinkingTimer&&(window.clearInterval(this.thinkingTimer),this.thinkingTimer=null),this.renderTimeout&&(window.clearTimeout(this.renderTimeout),this.renderTimeout=null),this.currentAssistantMsg){this.currentAssistantMsg.el.setAttribute("data-raw-content",this.currentRawText);let e=this.isNearBottom(),i=[];this.currentAssistantMsg.contentEl.querySelectorAll(".pi-agent-text-block").forEach(o=>{let a=o.querySelector(".pi-agent-streaming-text"),r=o.getAttribute("data-stream-raw")||a?.textContent||"";r.trim().length>0?(o.classList.remove("pi-agent-streaming-block"),o.classList.add("markdown-preview-view","markdown-rendered"),o.empty(),i.push(h.MarkdownRenderer.render(this.app,this.normalizeAssistantMarkdown(r),o,"",this))):o.remove()}),this.streamingTextEl=null,this.streamingCursorEl=null;let n=this.parseOptionsFromMessage(this.currentRawText);n&&n.options.length>=2&&this.renderOptionChips(this.currentAssistantMsg,n.options,n.isQuestion),this.finalizeAssistantMessageVisibility(this.currentAssistantMsg),e&&(this.scrollToBottom(!0,!0),Promise.all(i).then(()=>this.scrollToBottom(!0,!0)))}else this.scrollToBottom()}parseOptionsFromMessage(t){if(!t)return null;let e=t.split(`
`).map(l=>l.trim()),i=/^(?:\d+[.)]|[一二三四五六七八九十]+[、.)]|[a-zA-Z][.)])\s+(.+)$/,s=[],n=null;for(let l=0;l<e.length;l++){let d=e[l];if(d===""){n&&n.options.length>=2&&s.push(n),n=null;continue}let c=d.match(i);c?(n||(n={startIdx:l,endIdx:l,options:[]}),n.endIdx=l,n.options.push(c[1].trim())):(n&&n.options.length>=2&&s.push(n),n=null)}if(n&&n.options.length>=2&&s.push(n),s.length===0)return null;let o=s[s.length-1],a=null;for(let l=o.endIdx+1;l<e.length;l++)if(e[l]!==""){a=e[l];break}return a===null||!(/[?]\s*$/.test(a)||/请选择|请告诉我|选哪个|用哪个|choose|pick|select/i.test(a))?null:{options:o.options.slice(0,8),isQuestion:!0}}renderOptionChips(t,e,i){if(t.contentEl.querySelector(".pi-agent-option-chips"))return;let s=this.plugin.settings.language==="zh",n=t.contentEl.createDiv("pi-agent-option-chips");n.createDiv("pi-agent-option-chips-label").setText(s?"\u5FEB\u6377\u9009\u9879\uFF08\u4E5F\u53EF\u76F4\u63A5\u5728\u4E0B\u65B9\u8F93\u5165\u6846\u81EA\u884C\u56DE\u590D\uFF09\uFF1A":"Quick options (or just type your answer in the input below):");let a=new Set,r=[];for(let m of e){let v=n.createEl("button",{text:m,cls:"pi-agent-option-chip",attr:{type:"button"}});r.push(v),v.onclick=()=>{a.has(m)?(a.delete(m),v.removeClass("is-selected")):(a.add(m),v.addClass("is-selected")),p()}}let l=n.createEl("button",{text:s?"\u63D0\u4EA4 (0)":"Submit (0)",cls:"pi-agent-option-submit is-disabled",attr:{type:"button"}});l.onclick=()=>{if(a.size===0)return;let m=Array.from(a).join(`
`);this.setInputText(m),this.inputEl?.focus(),this.runAsync(()=>this.sendMessage())};let d=n.createEl("button",{text:s?"\u270E \u81EA\u884C\u8F93\u5165":"\u270E Type your own",cls:"pi-agent-option-custom",attr:{type:"button"}});d.onclick=()=>{this.inputEl?.focus(),this.inputEl?.scrollIntoView({block:"center",behavior:"smooth"})};let c=n.createEl("button",{text:s?"\u6E05\u7A7A":"Clear",cls:"pi-agent-option-clear",attr:{type:"button"}});c.onclick=()=>{a.clear(),r.forEach(m=>m.removeClass("is-selected")),p()};let p=()=>{let m=a.size;l.setText(s?`\u63D0\u4EA4 (${m})`:`Submit (${m})`),l.toggleClass("is-disabled",m===0)}}handleToolStart(t){let e=t.toolName,i=t.toolCallId,s=t.args;this.currentAssistantMsg||(this.currentAssistantMsg=this.addMessage("assistant",""));let n=this.currentAssistantMsg.contentEl.createDiv("pi-agent-tool-block"),o=n.createDiv("pi-agent-tool-header");if(o.createSpan({text:this.getToolIcon(e),cls:"pi-agent-tool-icon"}),o.createSpan({text:this.toTitleCase(e),cls:"pi-agent-tool-name"}),s){let r=this.formatToolArgs(e,s);if(r){let l=o.createSpan({text:r,cls:"pi-agent-tool-args"}),d=(typeof s.path=="string"?s.path:"")||(typeof s.TargetFile=="string"?s.TargetFile:"")||(typeof s.target=="string"?s.target:"");if(d)l.addClass("is-clickable"),l.setAttribute("title",`${d} (Click to open)`),l.onclick=c=>{c.stopPropagation();let p=this.app.vault.getAbstractFileByPath(d);p instanceof h.TFile&&this.app.workspace.getLeaf(!1).openFile(p).catch(m=>{console.error("[pimate] open file failed",m)})};else if(e==="bash"&&s.command){l.addClass("is-clickable");let c=s.command,p=this.plugin.settings.language==="zh";l.setAttribute("title",`${c} (Click to copy)`),l.onclick=m=>{m.stopPropagation(),navigator.clipboard.writeText(c).then(()=>{new h.Notice(p?"\u547D\u4EE4\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F":"Command copied to clipboard")}).catch(v=>{new h.Notice(`Failed to copy: ${v}`)})}}}}o.createSpan({text:"...",cls:"pi-agent-tool-close is-loading"});let a=n.createDiv("pi-agent-tool-output");o.onclick=()=>a.toggleClass("is-visible",!a.hasClass("is-visible")),n.setAttribute("data-tool-id",i),n.__outputEl=a,n.__startedAt=Date.now()}shouldWarnToolExecution(t,e){if(["write","edit"].includes(t))return!0;if(t==="bash"){let i=String(e?.command||"");return this.isDangerousBashCommand(i)}return!1}handleToolUpdate(t){let e=t.toolCallId,i=t.partialResult,s=this.chatContainer?.querySelector(`[data-tool-id="${e}"]`);if(s&&i?.content){let n=s.__outputEl;if(n){let a=i.content.map(r=>r.text).join("").trim();n.setText(a.length>1200?a.slice(0,1200)+`
\u2026`:a),n.toggleClass("is-visible",a.length>0),this.scrollToBottom()}}}handleToolEnd(t){let e=t.toolCallId,i=t.result,s=t.isError,n=this.chatContainer?.querySelector(`[data-tool-id="${e}"]`);if(n){n.addClass(s?"is-error":"is-success");let o=n.querySelector(".pi-agent-tool-close");o&&(o.removeClass("is-loading"),o.textContent=s?"\xD7":"\u2713");let a=t.result?.details,r=this.getDiffText(a),l=this.getDiffStats(a);if(l){let c=n.querySelector(".pi-agent-tool-close"),p=activeDocument.createElement("span");p.className="pi-agent-tool-diff";let m=activeDocument.createElement("span");m.className="pi-agent-tool-add",m.textContent=`+${l.added}`;let v=activeDocument.createElement("span");v.className="pi-agent-tool-remove",v.textContent=`\u2212${l.removed}`,p.append(m,v),c?.parentElement?.insertBefore(p,c)}let d=n.__outputEl;if(d&&i?.content){let c=i.content.map(p=>p.text).join("").trim();if(d.empty(),s)d.createSpan({text:c,cls:"pi-agent-tool-error"}),d.addClass("is-visible");else if(r&&["edit","write"].includes(t.toolName))this.renderDiffOutput(d,r);else if(c&&["bash","grep","find","ls"].includes(t.toolName)){let p=c.length>1600?c.slice(0,1600)+`
\u2026`:c;d.createEl("pre").setText(p),this.renderDetectedFiles(d,c),s&&d.addClass("is-visible")}}}}handleQueueUpdate(t){let e=this.getQueueTotal(t);this.activeTab&&(this.activeTab.queueCount=e),this.renderActiveTabRuntimeStatus()}handleExtensionUIRequest(t){let e=t.id,i=t.method;if(i==="confirm"){let s=t.title,n=t.message;new J(this.app,s,n,o=>{this.client?.sendUIResponse(e,{confirmed:o})}).open()}else if(i==="select"){let s=t.title,n=t.options;new de(this.app,s,n,o=>{o?this.client?.sendUIResponse(e,{value:o}):this.client?.sendUIResponse(e,{cancelled:!0})}).open()}else if(i==="input"){let s=t.title,n=t.placeholder;new pe(this.app,s,n||"",o=>{o!==null?this.client?.sendUIResponse(e,{value:o}):this.client?.sendUIResponse(e,{cancelled:!0})}).open()}else if(i==="editor"){let s=t.title,n=t.prefill;this.openEditorModal(e,s,n)}else if(i==="notify")new h.Notice(`\u{1F514} ${t.message||""}`);else if(i==="setWidget"){console.log("[pimate] setWidget event received:",t);let s=t.widgetKey,n=t.widgetLines;this.updateWidget(s,n)}}async openEditorModal(t,e,i){let s=await new Promise(n=>{new X(this.app,e,i||"",n).open()});s===null?this.client?.sendUIResponse(t,{cancelled:!0}):this.client?.sendUIResponse(t,{value:s})}addMessage(t,e){if(!this.chatContainer)throw new Error("Chat container not initialized");this.clearEmptyState();let i=this.chatContainer.createDiv(`pi-agent-message pi-agent-message-${t}`),s=i.createDiv("pi-agent-message-badge");switch(t){case"user":s.setText("\u{1F464} You");break;case"assistant":s.setText("\u03C0 Pi");break;case"system":s.setText("\u2139\uFE0F System");break;default:s.setText(t)}let n=i.createDiv("pi-agent-message-content");if(t==="user"&&e){let r=this.stripRecentContextGuard(e);n.createSpan({text:r}),i.setAttribute("data-raw-content",r)}if(t==="user"||t==="assistant"){let r=i.createDiv("pi-agent-msg-actions"),l=r.createEl("button",{cls:"pi-agent-action-btn",attr:{title:"Copy message"}});if(l.setText("\u{1F4CB}"),l.onclick=d=>{d.stopPropagation();let c=i.getAttribute("data-raw-content")||i.textContent||"";navigator.clipboard.writeText(c).then(()=>{new h.Notice("Copied to clipboard")}).catch(p=>{console.error("[pimate] copy message failed",p)})},t==="assistant"){let d=r.createEl("button",{cls:"pi-agent-action-btn",attr:{title:"Insert into active note"}});d.setText("\u21B5"),d.onclick=c=>{c.stopPropagation();let p=i.getAttribute("data-raw-content")||i.textContent||"",v=this.app.workspace.getActiveViewOfType(h.MarkdownView)?.editor;if(!v){new h.Notice("Please open a markdown note first");return}v.replaceSelection(p),new h.Notice("Inserted response into note")}}if(t==="user"){let d=r.createEl("button",{cls:"pi-agent-action-btn",attr:{title:"Reuse and edit message"}});d.setText("\u270F\uFE0F"),d.onclick=c=>{c.stopPropagation();let p=i.getAttribute("data-raw-content")||"";this.setInputText(p)},i.ondblclick=c=>{c.stopPropagation();let p=i.getAttribute("data-raw-content")||"";this.setInputText(p)}}}let o={id:`msg-${Date.now()}-${Math.random().toString(36).slice(2)}`,role:t,el:i,contentEl:n};this.renderedMessages.push(o);let a=this.plugin.settings.maxHistoryDisplay;for(;this.renderedMessages.length>a;){let r=this.renderedMessages.shift();r&&r.el.remove()}return this.scrollToBottom(!0,!0),o}addSystemMessage(t){if(!this.chatContainer)return;this.clearEmptyState(),this.chatContainer.createDiv("pi-agent-system-msg").setText(t),this.scrollToBottom(!0,!0)}addCompactionSummaryMessage(t,e,i="Context compacted"){if(!this.chatContainer)return;this.clearEmptyState();let s=this.chatContainer.createDiv("pi-agent-compaction-summary");if(s.createDiv("pi-agent-compaction-header").setText(e?`\u{1F4E6} ${i} \xB7 ${e.toLocaleString()} tokens summarized`:`\u{1F4E6} ${i}`),t&&t.trim()){let o=s.createDiv("pi-agent-compaction-body markdown-preview-view markdown-rendered");h.MarkdownRenderer.render(this.app,t,o,"",this)}this.scrollToBottom(!0,!0)}renderEmptyState(){if(!this.chatContainer||this.chatContainer.querySelector(".pi-agent-empty-state"))return;let t=this.chatContainer.createDiv("pi-agent-empty-state");t.createDiv({text:"\u03C0",cls:"pi-agent-empty-logo"}),t.createDiv({text:"Pimate",cls:"pi-agent-empty-title"}),t.createDiv({text:"Ask Pi to read, write, explain, or refactor your vault.",cls:"pi-agent-empty-subtitle"});let e=t.createDiv("pi-agent-empty-prompts");for(let i of["\u603B\u7ED3\u5F53\u524D\u7B14\u8BB0","\u628A\u9009\u4E2D\u5185\u5BB9\u6539\u5F97\u66F4\u514B\u5236","\u641C\u7D22\u8FD9\u4E2A vault \u91CC\u7684\u76F8\u5173\u5185\u5BB9","\u89E3\u91CA\u6211\u7C98\u8D34\u7684\u622A\u56FE"]){let s=e.createSpan({text:i,cls:"pi-agent-empty-prompt"});s.onclick=()=>this.setInputText(i)}}clearEmptyState(){this.chatContainer?.querySelector(".pi-agent-empty-state")?.remove()}startSpeedIndicator(){this.speedHideTimer&&(window.clearTimeout(this.speedHideTimer),this.speedHideTimer=null),this.speedTimer&&(window.clearInterval(this.speedTimer),this.speedTimer=null);let t=this.activeTab;t&&(t.speedStartedAt=null,t.speedEstimatedTokens=0,t.speedHideAt=null),this.speedStartedAt=null,this.speedEstimatedTokens=0,this.speedEl&&(this.speedEl.addClass("pi-agent-hidden"),this.speedEl.setText("\u2026"))}estimateTokenCount(t){if(!t)return 0;let e=0,i=0;for(let s of t)/\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}|\p{Script=Hangul}/u.test(s)?e++:/\s/.test(s)||i++;return e+i/4}addSpeedDelta(t){if(!t)return;let e=this.estimateTokenCount(t),i=this.activeTab;i&&(i.speedStartedAt||(i.speedStartedAt=Date.now()),i.speedEstimatedTokens=(i.speedEstimatedTokens||0)+e,i.speedHideAt=null),this.speedStartedAt||(this.speedStartedAt=Date.now()),this.speedEstimatedTokens+=e,this.speedEl&&this.speedEl.removeClass("pi-agent-hidden"),this.speedTimer||(this.speedTimer=window.setInterval(()=>this.updateSpeedIndicator(!1),750)),this.updateSpeedIndicator(!1)}updateSpeedIndicator(t){if(!this.speedEl)return;let e=this.activeTab,i=e?.speedStartedAt??this.speedStartedAt,s=e?.speedEstimatedTokens??this.speedEstimatedTokens;if(!i||s<=0)return;this.speedEl.removeClass("pi-agent-hidden");let n=Math.max(.1,(Date.now()-i)/1e3),o=s/n,a=o>=10?Math.round(o):Number(o.toFixed(1)),r=t?"":"~";this.speedEl.setText(`${r}${a} tok/s`),this.speedEl.setAttribute("title",`Estimated output speed: ${a} tok/s \xB7 ${Math.round(s)} tokens \xB7 ${n.toFixed(1)}s`)}stopSpeedIndicator(){this.speedTimer&&(window.clearInterval(this.speedTimer),this.speedTimer=null);let t=this.activeTab;t&&(t.speedHideAt=Date.now()+8e3),this.updateSpeedIndicator(!0),this.speedHideTimer&&window.clearTimeout(this.speedHideTimer),this.speedHideTimer=window.setTimeout(()=>{this.speedEl?.addClass("pi-agent-hidden"),this.speedHideTimer=null},8e3)}renderActiveTabSpeed(){if(!this.speedEl)return;this.speedTimer&&(window.clearInterval(this.speedTimer),this.speedTimer=null),this.speedHideTimer&&(window.clearTimeout(this.speedHideTimer),this.speedHideTimer=null);let t=this.activeTab;if(!t){this.speedEl.addClass("pi-agent-hidden");return}let e=t.speedStartedAt||null,i=t.speedEstimatedTokens||0;if(this.speedStartedAt=e,this.speedEstimatedTokens=i,!e||i<=0){this.speedEl.addClass("pi-agent-hidden");return}if(this.speedEl.removeClass("pi-agent-hidden"),this.updateSpeedIndicator(!0),t.isStreaming)this.speedTimer=window.setInterval(()=>this.updateSpeedIndicator(!1),750);else{let s=t.speedHideAt||0;if(s<=Date.now()){this.speedEl.addClass("pi-agent-hidden");return}this.speedHideTimer=window.setTimeout(()=>{this.activeTab?.isStreaming||this.speedEl?.addClass("pi-agent-hidden"),this.speedHideTimer=null},s-Date.now())}}renderActiveTabModelAndEffort(){let t=this.activeTab;if(!t)return;let e=t.modelProvider||this.plugin.settings.provider||"",i=t.modelId||this.plugin.settings.modelId||"",s=t.thinkingLevel??this.plugin.settings.thinkingLevel??"";this.updateModelDisplay(e,i),this.footerEffortCurrent&&this.footerEffortCurrent.setText(this.getThinkingLevelLabel(s))}isNearBottom(t=80){return this.chatContainer?this.chatContainer.scrollHeight-this.chatContainer.scrollTop-this.chatContainer.clientHeight<=t:!0}scrollToBottom(t=!0,e=!1){!this.chatContainer||!this.plugin.settings.autoScroll||!e&&this.chatContainer.scrollHeight-this.chatContainer.scrollTop-this.chatContainer.clientHeight>=50||(t&&(this.chatContainer.scrollTop=this.chatContainer.scrollHeight),window.setTimeout(()=>{if(this.chatContainer){if(!e&&this.chatContainer.scrollHeight-this.chatContainer.scrollTop-this.chatContainer.clientHeight>=50)return;this.chatContainer.scrollTop=this.chatContainer.scrollHeight}},50),window.setTimeout(()=>{if(this.chatContainer){if(!e&&this.chatContainer.scrollHeight-this.chatContainer.scrollTop-this.chatContainer.clientHeight>=50)return;this.chatContainer.scrollTop=this.chatContainer.scrollHeight}},150))}focusAdjacentMessage(t){let e=Array.from(this.chatContainer?.querySelectorAll(".pi-agent-message-user")||[]);if(e.length===0)return;let i=this.chatContainer?.getBoundingClientRect();if(!i)return;let s=i.top+i.height/2,n=0,o=1/0;e.forEach((r,l)=>{let d=r.getBoundingClientRect(),c=d.top+d.height/2,p=Math.abs(c-s);p<o&&(o=p,n=l)});let a=Math.max(0,Math.min(e.length-1,n+t));a!==n&&e[a]?.scrollIntoView({block:"center",behavior:"smooth"})}focusEdgeMessage(t){let e=Array.from(this.chatContainer?.querySelectorAll(".pi-agent-message-user")||[]);if(e.length===0)return;(t==="first"?e[0]:e[e.length-1])?.scrollIntoView({block:"start",behavior:"smooth"})}setStatus(t,e){if(this.statusBar&&(this.statusBar.empty(),this.statusBar.removeAttribute("title"),this.statusBar.className=`pi-agent-status pi-agent-status-${e}`,e!=="ok")){if(e==="error"){(0,h.setIcon)(this.statusBar,"alert-circle"),this.statusBar.setAttribute("title",t);return}if(e==="warning"){(0,h.setIcon)(this.statusBar,"alert-triangle"),this.statusBar.setAttribute("title",t);return}if(e==="thinking"){let i=t.toLowerCase();i.includes("thinking")?((0,h.setIcon)(this.statusBar,"brain"),this.statusBar.setAttribute("title","Thinking...")):i.includes("compact")?((0,h.setIcon)(this.statusBar,"shrink"),this.statusBar.setAttribute("title","Compacting memory...")):i.includes("queue")?((0,h.setIcon)(this.statusBar,"list-ordered"),this.statusBar.setAttribute("title",t)):((0,h.setIcon)(this.statusBar,"loader-2"),this.statusBar.setAttribute("title","Running..."))}}}renderDetectedFiles(t,e){let i=/[a-zA-Z0-9_\-\/\\.]+\.[a-zA-Z]{2,10}/g,s=e.match(i)||[];if(s.length===0)return;let n=new Set;for(let o of s){if(o.includes("node_modules")||o.includes(".git")||o.startsWith("http"))continue;let a=this.getBasename(o);if(!a||a.length<4)continue;let r=this.app.metadataCache.getFirstLinkpathDest(a,"");r instanceof h.TFile&&n.add(r)}if(n.size>0){let o=activeDocument.createElement("div");o.className="pi-agent-detected-files",o.createSpan({text:"Detected files: ",cls:"pi-agent-detected-label"}),n.forEach(a=>{let r=o.createSpan({text:a.name,cls:"pi-agent-file-chip is-clickable",attr:{title:`${a.path} (Click to open)`}});r.onclick=l=>{l.stopPropagation(),this.app.workspace.getLeaf(!1).openFile(a).catch(d=>{console.error("[pimate] open linked file failed",d)})}}),t.insertBefore(o,t.firstChild)}}updateWidget(t,e){if(this.widgetEl)try{if(!e||e.length===0){this.widgetEl.empty(),this.widgetEl.addClass("pi-agent-hidden");return}this.widgetEl.empty(),this.widgetEl.removeClass("pi-agent-hidden"),this.widgetEl.className=`pi-agent-widget pi-agent-widget-${t}`;let i=e[0],s=e.slice(1),n=this.widgetEl.createDiv("pi-agent-widget-header"),o=n.createSpan("pi-agent-widget-icon");try{(0,h.setIcon)(o,"list-todo")}catch{o.setText("\u{1F4CB}")}n.createSpan({text:i,cls:"pi-agent-widget-title"});let a=this.widgetEl.createDiv("pi-agent-widget-list"),r=!1;for(let l of s){let d=a.createDiv("pi-agent-widget-item"),c=l.trim(),p="pending";c.startsWith("\u2713")?(p="done",c=c.slice(1).trim()):(r?p="pending":(p="active",r=!0),c.startsWith("\u25CF")&&(c=c.slice(1).trim())),d.createSpan(`pi-agent-widget-item-icon pi-status-${p}`).setText(p==="done"?"\u2713":"\u25CF"),d.createSpan(`pi-agent-widget-item-text pi-status-${p}`).setText(c)}}catch(i){console.error("[pimate] updateWidget error:",i)}}showMoreMenu(t){let e=new h.Menu,i=this.plugin.settings.language==="zh";e.addItem(n=>n.setTitle(i?"\u6307\u4EE4 / \u6280\u80FD":"Commands / Skills").setIcon("terminal").onClick(()=>this.runAsync(()=>this.showCommandSelector()))),e.addItem(n=>n.setTitle(i?"\u9644\u52A0\u5F53\u524D\u6253\u5F00\u7684\u7B14\u8BB0":"Attach current open note").setIcon("file-plus").onClick(()=>this.addCurrentFileContext())),e.addItem(n=>n.setTitle(i?"\u9644\u52A0\u6587\u4EF6\u7BA1\u7406\u5668\u9009\u4E2D\u9879":"Attach file explorer selection").setIcon("list-plus").onClick(()=>this.addExplorerSelectionContext())),e.addItem(n=>n.setTitle(i?"\u63D2\u5165\u6700\u540E\u4E00\u6761\u56DE\u590D":"Insert last response").setIcon("pencil").onClick(()=>this.insertLastAssistantIntoActiveNote()));let s=this.getParsedSnippets();if(s.length>0){e.addSeparator();for(let n of s.slice(0,12)){let o=n.group?`${n.group} / ${n.title}`:n.title,a=i?"\u7247\u6BB5":"Snippet";e.addItem(r=>r.setTitle(`${a}: ${o.slice(0,42)}${o.length>42?"\u2026":""}`).setIcon("text-cursor-input").onClick(()=>this.appendInputText(this.expandSnippet(n.content))))}}e.addSeparator(),e.addItem(n=>n.setTitle(i?"\u6062\u590D\u4F1A\u8BDD...":"Resume session\u2026").setIcon("history").onClick(()=>this.showResumeSelector())),e.addItem(n=>n.setTitle(i?"\u4ECE\u63D0\u793A\u8BCD\u5206\u53C9...":"Fork from prompt\u2026").setIcon("git-fork").onClick(()=>this.showForkSelector())),e.addItem(n=>n.setTitle(i?"\u514B\u9686\u5F53\u524D\u5206\u652F":"Clone current branch").setIcon("copy").onClick(()=>this.cloneCurrentBranch())),e.addSeparator(),e.addItem(n=>n.setTitle(i?"\u538B\u7F29\u4E0A\u4E0B\u6587":"Compact context").setIcon("archive").onClick(()=>this.runAsync(()=>this.compactSession()))),e.addItem(n=>n.setTitle(i?"\u5BFC\u51FA HTML":"Export HTML").setIcon("download").onClick(()=>this.runAsync(()=>this.exportSessionHtml()))),e.addItem(n=>n.setTitle(i?"\u4F1A\u8BDD\u7EDF\u8BA1":"Session stats").setIcon("bar-chart-2").onClick(()=>this.runAsync(()=>this.showStats()))),e.addItem(n=>n.setTitle(i?"Token \u7528\u91CF...":"Token Usage\u2026").setIcon("bar-chart-3").onClick(()=>this.showUsageStats())),e.addSeparator(),e.addItem(n=>n.setTitle(i?"\u4E0A\u4E00\u6761\u6D88\u606F":"Previous message").setIcon("arrow-up").onClick(()=>this.scrollToPreviousMessage())),e.addItem(n=>n.setTitle(i?"\u4E0B\u4E00\u6761\u6D88\u606F":"Next message").setIcon("arrow-down").onClick(()=>this.scrollToNextMessage())),e.addItem(n=>n.setTitle(i?"\u5207\u6362\u6700\u540E\u4E00\u6761\u5DE5\u5177\u8F93\u51FA":"Toggle last tool output").setIcon("panel-bottom-close").onClick(()=>this.toggleLastToolBlock())),e.addItem(n=>n.setTitle(i?"\u8DF3\u5230\u6700\u540E\u4E00\u6B21 diff":"Jump to last diff").setIcon("git-compare").onClick(()=>this.scrollToLastDiff())),e.showAtMouseEvent(t)}getParsedSnippets(){return(this.plugin.settings.snippets||[]).map(t=>this.parseSnippet(t)).filter(t=>!!t?.content)}parseSnippet(t){let e=t.trim();if(!e)return null;let[i,...s]=e.split("::");if(s.length===0)return{title:e.slice(0,36),content:e};let n=s.join("::").trim();if(!n)return null;let o=i.split("/").map(l=>l.trim()).filter(Boolean),a=o.pop()||n.slice(0,36),r=o.join(" / ")||void 0;return{title:a,group:r,content:n}}expandSnippet(t){let e=this.app.workspace.getActiveFile(),i=this.contextItems.find(s=>s.type==="selection")?.value||"";return t.replace(/\{\{selection\}\}/g,i).replace(/\{\{current_file\}\}/g,e?.path||"").replace(/\{\{current_title\}\}/g,e?.basename||"").replace(/\{\{date\}\}/g,new Date().toISOString().slice(0,10))}updateInputModeState(){if(!this.inputEl)return;let t=this.inputEl.value.trimStart().startsWith("!");this.inputEl.toggleClass("is-bash-mode",t),this.inputEl.setAttribute("placeholder",t?"Bash mode \u2014 command will run locally":"How can I help you today?"),this.statusBar?.toggleClass("is-bash-mode",t),t&&this.statusBar&&this.statusBar.setText("Bash mode")}async sendMessage(){if(!this.client||!this.inputEl)return;let t=this.inputEl.value.trim(),e=this.buildContextPrefix(),i=this.getImagePayloads(),s=t||(i.length?"Please analyze the attached image(s).":""),n=`${e}${s}`.trim();if(!n&&i.length===0)return;let o=this.applySystemPrompt(n);this.maybeTitleActiveTab(t||o),this.pendingUserImages=i.map(a=>({data:a.data,mimeType:a.mimeType})),this.inputEl.value="",this.inputEl.setCssProps({height:"auto"}),this.updateInputModeState(),this.clearContextItems(),this.smartReviewContinues=0,this.smartReviewOriginalGoal=t||o;try{o.startsWith("!")?(this.smartReviewOriginalGoal=null,await this.runBashMode(o)):this.isStreaming?await this.client.steer(o,{images:i}):await this.client.prompt(o,{images:i})}catch(a){this.addSystemMessage(`\u274C Failed to send: ${a.message}`)}}applySystemPrompt(t){if(t.startsWith("!"))return t;let e=[],i=(this.plugin.settings.systemPrompt||"").trim();i&&e.push(i);let s=this.getSmartReviewPrompt();return s&&e.push(s),e.length===0?t:["System instruction for this Pimate turn:",e.join(`
`),"","User request:",t].join(`
`)}getSmartReviewPrompt(){return this.plugin.settings.smartReviewEnabled!==!0?"":this.plugin.settings.language!=="en"?"\u667A\u80FD\u5BA1\u6838\u5DF2\u5F00\u542F\u3002\u4EFB\u52A1\u5B8C\u6210\u540E\u8BF7\u660E\u786E\u56DE\u590D\u201C\u5DF2\u5B8C\u6210\u201D\uFF1B\u82E5\u672A\u5B8C\u6210\uFF0C\u8BF7\u7B80\u8981\u8BF4\u660E\u8FD8\u5DEE\u4EC0\u4E48\u3002":'Smart review is on. When the task is complete, reply exactly with "Done". If not yet complete, briefly state what is still missing.'}shouldAutoContinueFromAssistantText(t){let e=(t||"").trim();if(!e)return!1;let i=e.toLowerCase();return[/已完成/,/已经完成/,/任务完成/,/全部完成/,/最终结果/,/已经修复/,/已经通过/,/测试通过/,/build (?:passes|succeeded|ok)/i,/all (?:tests|checks?) pass/i,/task (?:is )?(?:complete|done|finished)/i,/no further (?:changes?|actions?) (?:needed|required)/i,/lgtm/i].some(o=>o.test(e))?!1:!!([/我将继续/,/接下来我会/,/下一步我会/,/现在去/,/我去/,/正在修复/,/尚未完成/,/还没有完成/,/未完成/,/还没修复/,/需要继续/,/需要进一步/,/还需要/,/仍然存在/,/测试失败/,/failed/i,/will (?:now |then )?(?:continue|fix|verify|run|check|proceed)/i,/next[, ]? i (?:will|'ll)/i,/todo:/i,/not (?:yet )?(?:complete|done|finished|fixed)/i,/still (?:need|needs|failing|pending)/i].some(o=>o.test(e))||/[。.…]{1,3}$/.test(e)&&/(我|我们|i|we)\s*(?:将|会|'ll|will)/.test(i))}getSmartReviewMaxContinues(){let t=this.plugin.settings.smartReviewMaxContinues;return typeof t!="number"||isNaN(t)?3:Math.max(1,Math.min(10,Math.floor(t)))}async maybeAutoContinueSmartReview(){if(this.plugin.settings.smartReviewEnabled!==!0||!this.client||this.isStreaming||this.smartReviewOriginalGoal==null)return;let t=this.getSmartReviewMaxContinues();if(this.smartReviewContinues>=t){this.setStatus(`\u2705 Smart review limit reached (${this.smartReviewContinues}/${t})`,"ok"),this.smartReviewOriginalGoal=null;return}let e;try{e=await this.client.getLastAssistantText()}catch(n){console.warn("[pimate] smart review: failed to fetch last assistant text",n);return}if(!e.success)return;let i=e.data?.text??"";if(!i.trim())return;if(!this.shouldAutoContinueFromAssistantText(i)){this.smartReviewOriginalGoal=null;return}this.smartReviewContinues+=1;let s=this.buildSmartReviewContinuePrompt();this.setStatus(`\u{1F501} Smart review continue ${this.smartReviewContinues}/${t}`,"thinking"),this.addSystemMessage(`\u{1F501} Smart review auto-continue (${this.smartReviewContinues}/${t})`);try{this.isStreaming?await this.client.steer(s):await this.client.prompt(s)}catch(n){this.addSystemMessage(`\u274C Smart review continue failed: ${n.message}`),this.smartReviewOriginalGoal=null}}buildSmartReviewContinuePrompt(){let t=this.plugin.settings.language!=="en",e=(this.smartReviewOriginalGoal||"").trim(),i=e?`${t?"\u539F\u59CB\u76EE\u6807":"Original goal"}: ${e.slice(0,400)}
`:"";return t?["\u667A\u80FD\u5BA1\u6838\u81EA\u52A8\u7EE7\u7EED\u6307\u4EE4\uFF1A",i,"\u4F60\u6700\u8FD1\u4E00\u8F6E\u56DE\u590D\u770B\u8D77\u6765\u5C1A\u672A\u771F\u6B63\u5B8C\u6210\u539F\u59CB\u76EE\u6807\uFF0C\u6216\u8005\u663E\u793A\u51FA\u8FD8\u9700\u8981\u7EE7\u7EED/\u4FEE\u590D/\u9A8C\u8BC1\u7684\u4FE1\u53F7\u3002","\u8BF7\u7ACB\u5373\u7EE7\u7EED\u6267\u884C\uFF1A\u4E0D\u8981\u518D\u6B21\u590D\u8FF0\u76EE\u6807\uFF0C\u4E0D\u8981\u505A\u65B0\u4E00\u8F6E\u603B\u7ED3\u6027\u8F93\u51FA\u3002","\u4F18\u5148\uFF1A\u5B8C\u6210\u672A\u5B8C\u6210\u7684\u6B65\u9AA4\u3001\u8FD0\u884C\u5DF2\u6709\u6D4B\u8BD5\u6216\u5DE5\u5177\u9A8C\u8BC1\u3001\u4FEE\u6B63\u4E0A\u4E00\u8F6E\u63D0\u5230\u7684\u95EE\u9898\u3002","\u5982\u679C\u76EE\u6807\u786E\u5B9E\u5DF2\u7ECF\u5168\u90E8\u5B8C\u6210\uFF0C\u8BF7\u660E\u786E\u56DE\u590D\u201C\u5DF2\u5B8C\u6210\u201D\u5E76\u505C\u6B62\u3002"].join(`
`):["Smart review auto-continue:",i,"Your previous reply suggests the original goal is not fully complete or contains signals that more work / verification is required.","Continue executing now. Do not restate the goal; do not produce another summary first.","Prioritize: finish remaining steps, run existing tests or tools to verify, fix issues called out last turn.",'If the goal is genuinely fully complete, reply exactly with "Done" and stop.'].join(`
`)}maybeTitleActiveTab(t){let e=this.activeTab;if(!e||!/^\d+$/.test(e.label))return;let i=t.replace(/@\S+/g,"").replace(/\s+/g," ").trim().slice(0,16);i&&(e.label=i,this.renderTabs(),this.persistSessionTabs())}abortAgent(){this.client?.abort(),this.isStreaming=!1,this.activeTab&&(this.activeTab.isStreaming=!1),this.stopSpeedIndicator(),this.updateButtons(),this.smartReviewContinues=0,this.smartReviewOriginalGoal=null,this.setStatus("\u23F9 Aborted","warning")}async newSession(){let t=this.activeTab;if(!t)return;t.sessionFile=void 0,t.sessionId=void 0,t.restored=!1,t.client=null,t.isStreaming=!1,this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],this.renderEmptyState(),this.updateWidget("tasks",void 0),await this.ensureTabClient(t),this.client=t.client,await this.refreshStateDisplay(),await this.loadAvailableCommands(),this.updateButtons(),await this.persistSessionTabs();let e=this.plugin.settings.language==="zh";new h.Notice(e?"\u5DF2\u91CD\u7F6E\u5E76\u5F00\u542F\u65B0\u4F1A\u8BDD":"Session reset and new chat started")}async compactSession(){if(!this.client)return;let t=this.plugin.settings.language==="zh",e=window.setTimeout(()=>{this.setStatus("\u26A0\uFE0F Compaction stuck (no event)","warning")},6e4);try{let i=await this.client.compact();if(window.clearTimeout(e),this.setStatus("\u2705 Ready","ok"),i.success){this.compactedContextActive=!0;let s=i.data?.summary||"";this.addCompactionSummaryMessage(s,i.data?.tokensBefore),new h.Notice(t?"\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29\uFF1B\u53EF\u89C1\u5BF9\u8BDD\u5DF2\u4FDD\u7559":"Context compacted; visible chat preserved")}else new h.Notice(t?"\u4E0A\u4E0B\u6587\u538B\u7F29\u5931\u8D25":"Compaction failed")}catch(i){window.clearTimeout(e),this.setStatus("\u2705 Ready","ok"),new h.Notice(`Compaction failed: ${i.message}`)}}showUsageStats(){new me(this.app,this.plugin.settings.language).open()}async showStats(){if(this.client)try{let t=await this.client.getSessionStats();if(t.success&&t.data){let e=t.data,i=e.tokens||{},s=[`Messages: ${e.totalMessages||0}`,`Tokens: ${i.total||0} (in: ${i.input||0}, out: ${i.output||0})`,`Cost: $${(e.cost||0).toFixed(4)}`];e.contextUsage?.percent!=null&&s.push(`Context: ${e.contextUsage.percent}% (${e.contextUsage.tokens}/${e.contextUsage.contextWindow})`),new h.Notice(s.join(`
`),8e3)}}catch(t){new h.Notice(`Failed: ${t.message}`)}}async exportSessionHtml(){if(this.client)try{let t=await this.client.exportHtml();if(!t.success){new h.Notice(t.error||"Export failed");return}new h.Notice(`Exported: ${t.data?.path||"HTML file"}`)}catch(t){new h.Notice(`Export failed: ${t.message}`)}}async showResumeSelector(){let t=this.getSessionDirectory();if(!t){new h.Notice("No session directory known yet. Send one message first.");return}try{let e=this.listResumeSessions(t);if(e.length===0){new h.Notice("No previous sessions found");return}new oe(this.app,e,async i=>{new ae(this.app,i,async s=>{s==="open"&&await this.openResumeSession(i),s==="delete"&&await this.deleteResumeSession(i)}).open()}).open()}catch(e){new h.Notice(`Resume failed: ${e.message}`)}}async openResumeSession(t){let e=this.activeTab;if(!e)return;let i=this.plugin.settings.language==="zh",s=this.tabs.find(o=>o.sessionFile?.toLowerCase()===t.path?.toLowerCase());if(s){await this.switchToTab(s.id);return}if(!this.isSessionFileInCurrentWorkspace(t.path)&&e.client&&(await e.client.destroy(),e.client=null),e.client&&e.client.isRunning())try{this.setStatus(i?"\u6B63\u5728\u8F7D\u5165\u5386\u53F2\u4F1A\u8BDD...":"Restoring session...","thinking");let o=await e.client.switchSession(t.path);if(!o.success||o.data?.cancelled){new h.Notice(i?"\u5207\u6362\u5386\u53F2\u4F1A\u8BDD\u5931\u8D25":"Failed to switch session");return}e.sessionFile=t.path,e.sessionId=void 0,e.restored=!0,await this.applyTabRuntimePreferences(e),this.resetActiveRenderState(),this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],await this.loadMessages(),await this.refreshStateDisplay(),this.setStatus("Ready","ok"),this.updateButtons(),await this.persistSessionTabs();return}catch(o){new h.Notice(i?`\u5207\u6362\u5386\u53F2\u4F1A\u8BDD\u51FA\u9519: ${o.message}`:`Switch error: ${o.message}`)}e.client&&(await e.client.destroy(),e.client=null),e.sessionFile=t.path,e.sessionId=void 0,e.restored=!0,this.resetActiveRenderState(),this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],await this.switchToTab(e.id)}async toggleModelPopup(t){if(this.modelPopupEl){this.closeModelPopup();return}if(this.closeEffortPopup(),!this.client)return;let e=this.plugin.settings.language==="zh";if(this.availableModelsCache&&this.availableModelsCache.length>0){this.renderModelPopup(t,this.availableModelsCache),this.client.getAvailableModels().then(s=>{if(s.success&&s.data){let n=s.data.models||[];n.length>0&&(this.availableModelsCache=n)}}).catch(s=>{console.warn("[pi-agent] Background model update failed:",s)});return}let i=t.parentElement;i&&(this.modelPopupEl=i.createDiv({cls:"pi-agent-model-popup"}),this.modelPopupEl.createDiv("pi-agent-model-popup-group-title").setText(e?"\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u5217\u8868...":"Loading models..."),this.modelOutsideClickHandler=n=>{this.modelPopupEl&&!this.modelPopupEl.contains(n.target)&&!t.contains(n.target)&&this.closeModelPopup()},window.setTimeout(()=>{activeDocument.addEventListener("pointerdown",this.modelOutsideClickHandler)},0));try{let s=await this.client.getAvailableModels();if(!s.success||!s.data){this.availableModelsCache||this.closeModelPopup();return}let n=s.data.models||[];if(n.length===0){new h.Notice(e?"\u6CA1\u6709\u53EF\u7528\u7684\u6A21\u578B":"No models available"),this.closeModelPopup();return}this.availableModelsCache=n,this.closeModelPopup(),this.renderModelPopup(t,n)}catch(s){this.closeModelPopup(),new h.Notice(e?`\u83B7\u53D6\u6A21\u578B\u5931\u8D25: ${s.message}`:`Failed to load models: ${s.message}`)}}closeModelPopup(){this.modelPopupEl&&(this.modelPopupEl.remove(),this.modelPopupEl=null),this.modelOutsideClickHandler&&(activeDocument.removeEventListener("pointerdown",this.modelOutsideClickHandler),this.modelOutsideClickHandler=null)}renderModelPopup(t,e){let i=t.parentElement;if(!i)return;let s=this.plugin.settings.language==="zh";this.modelPopupEl=i.createDiv({cls:"pi-agent-model-popup"});let n=new Map;for(let o of e){let a=o.provider.toUpperCase();(a==="ANTHROPIC"||a==="CLAUDE")&&(a="CLAUDE"),n.has(a)||n.set(a,[]),n.get(a).push(o)}for(let[o,a]of n.entries()){this.modelPopupEl.createDiv("pi-agent-model-popup-group-title").setText(o);let l=this.activeTab?.modelProvider||this.plugin.settings.provider||"",d=this.activeTab?.modelId||this.plugin.settings.modelId||"";for(let c of a){let p=d===c.id&&(!l||l===c.provider),m=this.modelPopupEl.createDiv({cls:`pi-agent-model-popup-item ${p?"is-active":""}`}),v=m.createDiv("pi-agent-model-popup-item-icon");(0,h.setIcon)(v,this.getProviderIconName(c.provider,c.id));let w=c.name||this.getModelShortName(c.id);m.createSpan({text:w,cls:"pi-agent-model-popup-item-name"}),m.onclick=T=>{T.stopPropagation(),this.runAsync(async()=>{await this.updateActiveTabModel(c.provider,c.id),new h.Notice(s?`\u6A21\u578B\u5DF2\u5207\u6362\u4E3A ${w}`:`Model set to ${w}`),this.closeModelPopup()})}}}this.modelOutsideClickHandler=o=>{this.modelPopupEl&&!this.modelPopupEl.contains(o.target)&&!t.contains(o.target)&&this.closeModelPopup()},window.setTimeout(()=>{activeDocument.addEventListener("pointerdown",this.modelOutsideClickHandler)},0)}async toggleEffortPopup(t){if(this.effortPopupEl){this.closeEffortPopup();return}this.closeModelPopup();let e=this.activeTab;e?.client&&await this.syncTabStateFromPi(e),this.renderEffortPopup(t)}closeEffortPopup(){this.effortPopupEl&&(this.effortPopupEl.remove(),this.effortPopupEl=null),this.effortOutsideClickHandler&&(activeDocument.removeEventListener("pointerdown",this.effortOutsideClickHandler),this.effortOutsideClickHandler=null)}getStaticLevelDescription(t,e){let s={off:{name:"off",zh:"\u5173\u95ED",en:"Reasoning Off"},minimal:{name:"minimal",zh:"\u6700\u4F4E",en:"Minimal Reasoning"},low:{name:"low",zh:"\u8F83\u4F4E",en:"Low Reasoning"},medium:{name:"medium",zh:"\u4E2D\u7B49",en:"Medium Reasoning"},high:{name:"high",zh:"\u8F83\u9AD8",en:"High Reasoning"},xhigh:{name:"xhigh",zh:"\u6781\u9AD8",en:"X-High Reasoning"},max:{name:"max",zh:"\u6781\u9650",en:"Max Reasoning"}}[t];return s?{name:s.name,desc:e?s.zh:s.en}:{name:t,desc:e?"\u5F53\u524D Pi \u6A21\u578B\u58F0\u660E\u7684\u6863\u4F4D":"Declared by current Pi model"}}buildThinkingLevelOptions(t){let e=this.plugin.settings.language==="zh",i=t?.piModelMeta;if(!i)return{options:[],note:e?"\u7B49\u5F85 Pi \u8FD4\u56DE\u5F53\u524D\u6A21\u578B\u80FD\u529B":"Awaiting Pi model capabilities"};if(i.reasoning!==!0)return{options:[],note:e?"\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u53EF\u914D\u7F6E\u63A8\u7406":"Current model does not expose configurable reasoning"};let s=["off","minimal","low","medium","high","xhigh","max"],n=new Set(["off","minimal","low","medium","high"]),o=i.thinkingLevelMap;if(o&&typeof o=="object"&&!Array.isArray(o))for(let[r,l]of Object.entries(o))l===null?n.delete(r):n.add(r);return{options:[...s.filter(r=>n.has(r)),...Array.from(n).filter(r=>!s.includes(r))].map(r=>({id:r,...this.getStaticLevelDescription(r,e)}))}}renderEffortPopup(t){let e=t.parentElement;if(!e)return;let i=this.plugin.settings.language==="zh",s=this.activeTab,{options:n,note:o}=this.buildThinkingLevelOptions(s);this.effortPopupEl=e.createDiv({cls:"pi-agent-effort-popup"});let a=s?.thinkingLevel??"",r=(l,d,c,p)=>{let m=a===l,v=this.effortPopupEl.createDiv({cls:`pi-agent-effort-popup-item ${m?"is-active":""}`}),w=v.createSpan({cls:"pi-agent-effort-popup-left"});w.createSpan({cls:"pi-agent-effort-popup-item-check"}).setText("\u2713"),w.createSpan({text:d,cls:"pi-agent-effort-popup-item-name"}),v.createSpan({text:c,cls:"pi-agent-effort-popup-item-desc"}),p?v.onclick=k=>{k.stopPropagation(),this.runAsync(async()=>{await p(),new h.Notice(i?`\u601D\u8003\u5F3A\u5EA6\u5DF2\u8BBE\u4E3A ${d}`:`Thinking level set to ${d}`),this.closeEffortPopup()})}:v.addClass("is-disabled")};if(n.length===0)this.effortPopupEl.createDiv({cls:"pi-agent-effort-popup-note"}).setText(o??"");else for(let l of n)r(l.id,l.name,l.desc,async()=>{await this.updateActiveTabThinkingLevel(l.id)});this.effortOutsideClickHandler=l=>{this.effortPopupEl&&!this.effortPopupEl.contains(l.target)&&!t.contains(l.target)&&this.closeEffortPopup()},window.setTimeout(()=>{activeDocument.addEventListener("pointerdown",this.effortOutsideClickHandler)},0)}async toggleHistoryPanel(){this.isHistoryOpen=!this.isHistoryOpen;let t=this.containerEl.querySelector(".pi-agent-mini-action:has(svg.svg-icon[class*='history'])")||this.containerEl.querySelector(".pi-agent-mini-action svg[class*='history']")?.parentElement;t&&t.toggleClass("is-active",this.isHistoryOpen),this.isHistoryOpen?(this.chatContainer&&this.chatContainer.addClass("pi-agent-hidden"),this.historyPanelEl&&(this.historyPanelEl.removeClass("pi-agent-hidden"),await this.renderHistoryPanel())):(this.chatContainer&&this.chatContainer.removeClass("pi-agent-hidden"),this.historyPanelEl&&this.historyPanelEl.addClass("pi-agent-hidden"))}getShortPath(t){if(!t)return"";let e=t.includes("/")?"/":"\\",i=t.split(e).filter(Boolean);return i.length<=2?t:".../"+i.slice(-2).join(e)}decodeWorkspaceDirName(t){if(t.startsWith("--")&&t.endsWith("--")){let e=t.slice(2,-2);if(e.includes("--")){let i=e.indexOf("--"),s=e.slice(0,i),n=e.slice(i+2).replace(/-/g,"/");return`${s}:/${n}`}return e.replace(/-/g,"/")}return t}listAllWorkspaceSessions(){let e=`${(0,V.homedir)().replace(/\\/g,"/")}/.pi/agent/sessions`;if(!(0,A.existsSync)(e))return[];let i=this.app.vault.adapter.getBasePath?.()||"",s=i?this.encodeWorkspacePath(i).toLowerCase():"",n=[],o=(0,A.readdirSync)(e);for(let a of o){let r=`${e}/${a}`;try{if(!(0,A.statSync)(r).isDirectory())continue;let d=this.listResumeSessions(r),c=a.toLowerCase()===s,p=a;if(a.startsWith("--")&&a.endsWith("--")){let m=a.slice(2,-2);if(m.includes("--")){let v=m.indexOf("--"),w=m.slice(0,v),T=m.slice(v+2).replace(/-/g,"/");p=`${w}:/${T}`}else p=m.replace(/-/g,"/")}n.push({pathName:p,rawDirName:a,dirPath:r,isCurrent:c,sessions:d})}catch(l){new h.Notice(`\u8BFB\u53D6\u76EE\u5F55 ${a} \u62A5\u9519: ${l.message}`),console.error("[pi-agent] listAllWorkspaceSessions error",l)}}return n.sort((a,r)=>a.isCurrent?-1:r.isCurrent?1:a.pathName.localeCompare(r.pathName))}async renderHistoryPanel(){if(!this.historyPanelEl)return;this.historyPanelEl.empty();let t=this.plugin.settings.language==="zh";this.historyPanelEl.createDiv("pi-agent-history-header").createDiv({text:"CONVERSATIONS",cls:"pi-agent-history-title"});try{let i=this.getSessionDirectory();if(!i){this.historyPanelEl.createDiv({text:t?"\u6682\u65E0\u4F1A\u8BDD\u5386\u53F2":"No conversation history",cls:"pi-agent-history-empty"});return}let s=this.listResumeSessions(i);if(s.length===0){this.historyPanelEl.createDiv({text:t?"\u6682\u65E0\u4F1A\u8BDD\u5386\u53F2":"No conversation history",cls:"pi-agent-history-empty"});return}let o=this.historyPanelEl.createDiv("pi-agent-history-search-wrap").createEl("input",{cls:"pi-agent-history-search",attr:{type:"search",placeholder:t?"\u641C\u7D22\u5386\u53F2\u4F1A\u8BDD...":"Search conversations..."}}),a=this.historyPanelEl.createDiv("pi-agent-history-list"),r=(l="")=>{a.empty();let d=l.trim().toLowerCase(),c=d?s.filter(m=>[m.label,m.preview,m.path].filter(Boolean).join(" ").toLowerCase().includes(d)):s;if(c.length===0){a.createDiv({text:t?"\u6CA1\u6709\u5339\u914D\u7684\u4F1A\u8BDD":"No matching conversations",cls:"pi-agent-history-empty"});return}let p=this.activeTab?.sessionFile?.replace(/\\/g,"/").toLowerCase();for(let m of c){let v=m.path?.replace(/\\/g,"/").toLowerCase(),w=!!p&&v===p,T=a.createDiv(w?"pi-agent-history-item is-current-session":"pi-agent-history-item"),k=T.createDiv("pi-agent-history-item-icon");(0,h.setIcon)(k,w?"message-square-dot":"message-square");let M=T.createDiv("pi-agent-history-item-content"),x=m.label||(t?"\u672A\u547D\u540D\u5BF9\u8BDD":"Untitled Session");if(M.createDiv({text:x,cls:"pi-agent-history-item-name"}),w)M.createDiv({text:"Current session",cls:"pi-agent-history-item-current"});else{let g=this.formatHistoryTime(m.mtime);M.createDiv({text:g,cls:"pi-agent-history-item-time"})}T.onclick=()=>{this.runAsync(async()=>{await this.openResumeSession(m),this.isHistoryOpen=!1,this.chatContainer&&this.chatContainer.removeClass("pi-agent-hidden"),this.historyPanelEl.addClass("pi-agent-hidden"),this.containerEl.querySelector(".pi-agent-mini-action.is-active")?.removeClass("is-active")})},T.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation();let y=new h.Menu;y.addItem(C=>{C.setTitle(t?"\u91CD\u547D\u540D":"Rename").setIcon("pencil").onClick(()=>this.runAsync(async()=>{await this.renameResumeSession(m),await this.renderHistoryPanel()}))}),y.addItem(C=>{C.setTitle(t?"\u5220\u9664\u6B64\u4F1A\u8BDD":"Delete session").setIcon("trash-2").onClick(()=>this.runAsync(async()=>{await this.deleteResumeSession(m),await this.renderHistoryPanel()}))}),y.showAtMouseEvent(g)})}};o.addEventListener("input",()=>r(o.value)),r()}catch(i){this.historyPanelEl.createDiv({text:`Failed to load: ${i.message}`,cls:"pi-agent-history-error"})}}formatHistoryTime(t){let e=this.plugin.settings.language==="zh",i=new Date(t),s=new Date;if(i.toDateString()===s.toDateString()){let r=String(i.getHours()).padStart(2,"0"),l=String(i.getMinutes()).padStart(2,"0");return`${r}:${l}`}let n=new Date(s);if(n.setDate(s.getDate()-1),i.toDateString()===n.toDateString())return e?"\u6628\u5929":"Yesterday";let o=i.getMonth()+1,a=i.getDate();return e?`${o}\u6708${a}\u65E5`:i.toLocaleDateString(void 0,{month:"short",day:"numeric"})}async renameResumeSession(t){let e=this.plugin.settings.language==="zh",i=this.plugin.settings.sessionTitles?.[t.path]||t.label||"",s=await new Promise(o=>{new X(this.app,e?"\u91CD\u547D\u540D\u4F1A\u8BDD":"Rename session",i,o).open()});if(s===null)return;let n=s.trim();this.plugin.settings.sessionTitles||(this.plugin.settings.sessionTitles={}),n?(this.plugin.settings.sessionTitles[t.path]=n,t.label=n):delete this.plugin.settings.sessionTitles[t.path],await this.plugin.saveSettings(),new h.Notice(e?"\u4F1A\u8BDD\u5DF2\u91CD\u547D\u540D":"Session renamed")}async deleteResumeSession(t){if(!await new Promise(s=>{new J(this.app,"Delete Pimate session?",`Delete this session file?
${t.path}
This cannot be undone from Pimate.`,s).open()}))return;let i=this.tabs.find(s=>s.sessionFile?.toLowerCase()===t.path?.toLowerCase());i&&await this.closeTab(i.id);try{(0,A.unlinkSync)(t.path),this.plugin.settings.sessionTitles?.[t.path]&&(delete this.plugin.settings.sessionTitles[t.path],await this.plugin.saveSettings()),new h.Notice("Session deleted")}catch(s){new h.Notice(`Failed to delete session: ${s.message}`)}}encodeWorkspacePath(t){let e=t.replace(/\\/g,"/");if(e.match(/^[A-Za-z]:/)){let i=e[0].toUpperCase(),s=e.slice(2);s.startsWith("/")&&(s=s.slice(1));let n=s.replace(/\//g,"-");return`--${i}--${n}--`}else return e.startsWith("/")&&(e=e.slice(1)),e.endsWith("/")&&(e=e.slice(0,-1)),`--${e.replace(/\//g,"-")}--`}getSessionDirectory(){try{let e=this.app.vault.adapter.getBasePath?.()||"";if(e){let i=this.encodeWorkspacePath(e),n=`${(0,V.homedir)().replace(/\\/g,"/")}/.pi/agent/sessions`,o=`${n}/${i}`;if((0,A.existsSync)(o))return o;if((0,A.existsSync)(n)){let a=i.toLowerCase(),l=(0,A.readdirSync)(n).find(d=>d.toLowerCase()===a);if(l)return`${n}/${l}`}}}catch(e){console.log("[pi-agent] Failed to auto detect workspace sessions dir, fallback to old logic",e)}let t=this.activeTab?.sessionFile||this.plugin.settings.activeSessionFile||this.plugin.settings.sessionTabs?.find(e=>e.sessionFile)?.sessionFile||"";return t?(0,B.dirname)(t):""}listResumeSessions(t){return(0,A.readdirSync)(t).filter(e=>e.endsWith(".jsonl")).map(e=>{let i=`${t}/${e}`,s=(0,A.statSync)(i),n=this.readSessionPreview(i),o=this.plugin.settings.sessionTitles?.[i];return{path:i,label:o||(n?n.slice(0,24):(0,B.basename)(e,".jsonl").slice(0,12)),mtime:s.mtimeMs,preview:n}}).sort((e,i)=>i.mtime-e.mtime).slice(0,200)}readSessionPreview(t){try{let e=(0,A.readFileSync)(t,"utf8");for(let i of e.split(/\r?\n/)){if(!i.trim())continue;let s=JSON.parse(i),n=s.message?.content??s.content;if((s.message?.role??s.role)==="user"){if(typeof n=="string")return n.replace(/\s+/g," ").trim();if(Array.isArray(n)){let a=n.find(r=>r?.type==="text"&&r.text);if(a?.text)return String(a.text).replace(/\s+/g," ").trim()}}}}catch{}return""}readLastMessagesFromFile(t,e){try{if(!(0,A.existsSync)(t))return{messages:[],total:0};let i=(0,A.readFileSync)(t,"utf8"),s=[];for(let a of i.split(/\r?\n/))if(a.trim())try{let r=JSON.parse(a);r?.type==="message"&&r.message&&s.push(r.message)}catch{}let n=s.length;return{messages:e>0?s.slice(-e):s,total:n}}catch(i){return console.warn("[pi-agent] readLastMessagesFromFile failed:",i),{messages:[],total:0}}}async showForkSelector(){if(this.client)try{let t=await this.client.getForkMessages(),e=(t.data?.messages||[]).filter(i=>i.entryId&&i.text);if(!t.success||e.length===0){new h.Notice("No previous user prompts available to fork");return}new re(this.app,e,async i=>{let s=await this.client?.fork(i.entryId);if(!s?.success||s.data?.cancelled){new h.Notice("Fork cancelled");return}this.setInputText((s.data?.text||i.text).trim()),this.resetActiveRenderState(),this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],await this.loadMessages(),new h.Notice("Fork created")}).open()}catch(t){new h.Notice(`Fork failed: ${t.message}`)}}async cloneCurrentBranch(){if(this.client)try{let t=await this.client.clone();if(!t.success||t.data?.cancelled){new h.Notice("Clone cancelled");return}this.resetActiveRenderState(),this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],await this.loadMessages(),new h.Notice("Current branch cloned")}catch(t){new h.Notice(`Clone failed: ${t.message}`)}}async runBashMode(t){if(!this.client)return;let e=t.replace(/^!+/,"").trim();if(!e)return;if(this.isDangerousBashCommand(e)&&!await new Promise(r=>{new J(this.app,"Dangerous bash command",`Pimate is about to run:
${e}
This looks destructive. Allow it?`,r).open()})){this.addSystemMessage("Dangerous bash command blocked");return}let s=this.addMessage("assistant","").contentEl.createDiv("pi-agent-tool-block"),n=s.createDiv("pi-agent-tool-header");n.createSpan({text:this.getToolIcon("bash"),cls:"pi-agent-tool-icon"}),n.createSpan({text:"Bash",cls:"pi-agent-tool-name"}),n.createSpan({text:e,cls:"pi-agent-tool-args"}),n.createSpan({text:"...",cls:"pi-agent-tool-close is-loading"});let o=s.createDiv("pi-agent-tool-output is-visible");n.onclick=()=>o.toggleClass("is-visible",!o.hasClass("is-visible"));try{let a=await this.client.bash(e),r=a.data,l=s.querySelector(".pi-agent-tool-close");l&&(l.removeClass("is-loading"),l.textContent=a.success?"\u2713":"\xD7"),o.setText((r?.output||"").slice(0,3e3)),a.success||o.addClass("pi-agent-tool-error")}catch(a){let r=s.querySelector(".pi-agent-tool-close");r&&(r.removeClass("is-loading"),r.textContent="\xD7"),o.setText(a.message),o.addClass("pi-agent-tool-error")}}isDangerousBashCommand(t){let e=t.toLowerCase().replace(/\s+/g," ").trim();return[/\brm\s+-[^\n]*r[^\n]*f\b/,/\brm\s+-rf\b/,/\bdel\s+\/s\b/,/\brmdir\s+\/s\b/,/\bformat\b/,/\bgit\s+reset\s+--hard\b/,/\bgit\s+clean\s+-[^\n]*f/,/\bmkfs\b/,/\bshutdown\b/,/\breboot\b/].some(i=>i.test(e))}async showCommandSelector(){if(this.client)try{let t=await this.client.getCommands();if(!t.success||!t.data)return;let e=t.data.commands||[];if(!e.length){new h.Notice("No Pi commands or skills available");return}new ne(this.app,e,i=>{this.prependInputText(`/${i.name} `)}).open()}catch(t){new h.Notice(`Failed: ${t.message}`)}}async showModelSelector(){if(this.client)try{let t=await this.client.getAvailableModels();if(!t.success||!t.data)return;let e=t.data.models||[];if(e.length===0){new h.Notice("No models available");return}new le(this.app,e,async i=>{await this.updateActiveTabModel(i.provider,i.id),new h.Notice(`Model set to ${i.provider}/${i.id}`)}).open()}catch(t){new h.Notice(`Failed: ${t.message}`)}}async inlineEditSelection(t,e){if(!this.client||!t.trim())return;let s=await new Promise(o=>{new he(this.app,o).open()});if(!s)return;this.addSystemMessage("Inline edit started\u2026");let n=1;try{for(;;){let o=await this.generateInlineReplacement(t,s,n);if(!o){new h.Notice("Pimate returned an empty replacement");return}let a=await new Promise(r=>{new ue(this.app,t,o,r).open()});if(a.action==="reject"){new h.Notice("Inline edit rejected");return}if(a.action==="regenerate"){n++,this.addSystemMessage(`Regenerating inline edit\u2026 (${n})`);continue}e((a.replacement||o).trim()),new h.Notice("Selection edited by Pimate");return}}catch(o){new h.Notice(`Inline edit failed: ${o.message}`)}}async generateInlineReplacement(t,e,i){if(!this.client)return"";let s=["You are editing a selected passage from an Obsidian markdown note.","Return ONLY the replacement text. Do not add explanations, markdown fences, or commentary.",`Instruction: ${e}`,i>1?`This is regeneration attempt ${i}. Produce a different, better version.`:"","Selected text:","```markdown",t,"```"].filter(Boolean).join(`
`);return((await this.client.promptAndWait(s)).data?.text||"").trim()}getAttachableFiles(){let t=new Set(["md","markdown","pdf","png","jpg","jpeg","gif","webp","svg","bmp","avif"]);return this.app.vault.getFiles().filter(e=>t.has(e.extension.toLowerCase()))}getFileTypeIcon(t){let e=t.toLowerCase();return e==="pdf"?"\u{1F4C4}":["png","jpg","jpeg","gif","webp","svg","bmp","avif"].includes(e)?"\u{1F5BC}":"\u{1F4DD}"}async addFileContext(){let t=this.getAttachableFiles();if(t.length===0){new h.Notice("No attachable files in this vault");return}new ce(this.app,t,e=>this.addFileContextItem(e)).open()}addCurrentFileContext(){let t=this.app.workspace.getActiveFile();if(!t){new h.Notice("No active file");return}this.addFileContextItem(t)}addFileContextItem(t){this.addContextItem({id:`ctx-${Date.now()}-${Math.random().toString(36).slice(2)}`,type:"file",label:t.basename,value:t.path})}addFolderContextItem(t,e){let i=t.path||"/";this.addContextItem({id:`ctx-${Date.now()}-${Math.random().toString(36).slice(2)}`,type:"folder",label:t.name||i,value:i,mimeType:e?"recursive":"files"})}async handlePaste(t){let i=Array.from(t.clipboardData?.items??[]).filter(s=>s.type.startsWith("image/"));if(i.length!==0){t.preventDefault();for(let s of i){let n=s.getAsFile();n&&await this.addImageContextFromFile(n,"pasted image")}}}async handleDrop(t){t.preventDefault(),this.inputEl?.removeClass("is-drag-over");let e=Array.from(t.dataTransfer?.files??[]),i=!1;for(let n of e)n.type.startsWith("image/")&&(await this.addImageContextFromFile(n,n.name||"dropped image"),i=!0);let s=t.dataTransfer?.getData("text/plain")||"";for(let n of this.extractVaultPaths(s)){let o=this.app.vault.getAbstractFileByPath(n);o instanceof h.TFile&&(this.addFileContextItem(o),i=!0)}i&&this.inputEl?.focus()}async addImageContextFromFile(t,e){let i=await this.readFileAsDataUrl(t),[,s=""]=i.split(",",2);this.addContextItem({id:`ctx-img-${Date.now()}-${Math.random().toString(36).slice(2)}`,type:"image",label:t.name&&t.name!=="image.png"?t.name:e,value:s,mimeType:t.type||"image/png"})}extractVaultPaths(t){if(!t)return[];let e=t.split(/\r?\n/).map(s=>s.trim().replace(/^obsidian:\/\/open\?/,"")).filter(Boolean),i=[];for(let s of e){let n=decodeURIComponent(s),o=n.match(/(?:^|[?&])file=([^&]+)/),a=o?decodeURIComponent(o[1]):n;this.app.vault.getAbstractFileByPath(a)instanceof h.TFile&&i.push(a)}return i}readFileAsDataUrl(t){return new Promise((e,i)=>{let s=new FileReader;s.onload=()=>e(String(s.result||"")),s.onerror=()=>i(s.error||new Error("Failed to read pasted image")),s.readAsDataURL(t)})}addContextItem(t){this.contextItems.some(e=>e.value===t.value)||(this.contextItems.push(t),this.renderContextItems())}removeContextItem(t){this.contextItems=this.contextItems.filter(e=>e.id!==t),this.renderContextItems()}clearContextItems(){this.contextItems=[],this.renderContextItems()}renderContextItems(){if(!this.contextRowEl)return;this.contextRowEl.empty(),this.imagePreviewEl&&this.imagePreviewEl.empty();let t=this.contextItems.filter(i=>i.type==="image"),e=this.contextItems.filter(i=>i.type!=="image");if(this.imagePreviewEl){this.imagePreviewEl.toggleClass("has-content",t.length>0);for(let i of t){let s=this.imagePreviewEl.createDiv("pi-agent-image-card"),n=s.createEl("img",{cls:"pi-agent-image-card-thumb",attr:{src:`data:${i.mimeType||"image/png"};base64,${i.value}`,title:i.label}});n.onclick=a=>{a.stopPropagation(),new Q(this.app,i).open()};let o=s.createSpan({text:"\xD7",cls:"pi-agent-image-card-remove"});o.onclick=a=>{a.stopPropagation(),this.removeContextItem(i.id)}}}this.contextRowEl.toggleClass("has-content",e.length>0);for(let i of e){let s=this.contextRowEl.createSpan({cls:"pi-agent-file-chip"});s.createSpan({text:i.type==="selection"?"\u25A4":i.type==="folder"?"\u25A6":"\u25A3",cls:"pi-agent-file-chip-icon"}),s.createSpan({text:i.label,cls:"pi-agent-file-chip-name"});let n=s.createSpan({text:"\xD7",cls:"pi-agent-file-chip-remove"});n.onclick=o=>{o.stopPropagation(),this.removeContextItem(i.id)},s.onclick=()=>{this.runAsync(async()=>{if(i.type==="file"){let o=this.app.vault.getAbstractFileByPath(i.value);o instanceof h.TFile&&await this.app.workspace.getLeaf(!1).openFile(o)}else if(i.type==="folder"){let o=this.app.vault.getMarkdownFiles(),a=i.value==="/"?"":i.value+"/",r=o.find(l=>{let d=l.parent;return d?i.value==="/"?!l.path.includes("/"):l.path.startsWith(a)||d.path===i.value:!1});if(r)await this.app.workspace.getLeaf(!1).openFile(r);else{let l=this.app.workspace.getLeavesOfType("file-explorer")[0];l&&this.app.workspace.setActiveLeaf(l)}}else new Q(this.app,i).open()})}}}renderUserMessageImages(t,e){let i=t.el.createDiv("pi-agent-message-attachments");t.el.insertBefore(i,t.contentEl);for(let s of e){let o=i.createDiv("pi-agent-message-image").createEl("img",{attr:{src:`data:${s.mimeType||"image/png"};base64,${s.data}`}});o.onclick=a=>{a.stopPropagation();let r=`data:${s.mimeType||"image/png"};base64,${s.data}`;window.open(r,"_blank")}}}stripRecentContextGuard(t){return t.replace(/<recent_context_guard>[\s\S]*?<\/recent_context_guard>\s*/g,"").trim()}buildContextPrefix(){let t=this.contextItems.filter(r=>r.type==="file"),e=this.contextItems.filter(r=>r.type==="folder"),i=this.contextItems.filter(r=>r.type==="selection"),s=t.map(r=>`@${r.value}`).join(" "),n=e.map(r=>`Folder @${r.value}`).join(`
`),o=i.map((r,l)=>`Selection ${l+1}:
${r.value}`).join(`
`),a=[s,n,o].filter(Boolean);return a.length?`${a.join(`
`)}
`:""}listFolderFiles(t,e){let i=this.app.vault.getMarkdownFiles(),s=[];for(let n of i){let o=n.parent;if(!o)continue;let a=o.path||"/";(a===t||e&&a.startsWith(t==="/"?"/":t+"/"))&&s.push(n.path)}return s}getImagePayloads(){return this.contextItems.filter(t=>t.type==="image").map(t=>({type:"image",data:t.value,mimeType:t.mimeType||"image/png"}))}async refreshStateDisplay(){if(this.client)try{this.activeTab&&await this.syncTabStateFromPi(this.activeTab),await this.refreshContextUsageDisplay(),this.client.getAvailableModels().then(t=>{t.success&&t.data&&(this.availableModelsCache=t.data.models||[])}).catch(()=>{})}catch{}}async refreshContextUsageDisplay(){if(!(!this.client||!this.footerContextEl))try{let t=await this.client.getSessionStats();t.success&&(this.updateActiveTabSessionInfo(t.data),await this.persistSessionTabs());let e=t.data?.contextUsage;t.success&&e?.percent!=null?this.updateContextMeter(Number(e.percent),`Context: ${e.tokens??"?"}/${e.contextWindow??"?"}`):this.updateContextMeter(null,"Context usage")}catch{this.updateContextMeter(null,"Context usage")}}updateContextMeter(t,e){if(!this.footerContextEl||!this.footerContextFillEl||!this.footerContextPercentEl)return;let i=2*Math.PI*8;if(this.footerContextFillEl.setAttribute("stroke-dasharray",`${i}`),t==null||Number.isNaN(t)){this.footerContextPercentEl.setText(""),this.footerContextFillEl.setAttribute("stroke-dashoffset",`${i}`),this.footerContextEl.removeClass("warning"),this.footerContextEl.removeClass("danger"),this.footerContextEl.setAttribute("title",e);return}let s=Math.max(0,Math.min(100,t));this.footerContextFillEl.setAttribute("stroke-dashoffset",`${i*(1-s/100)}`),this.footerContextPercentEl.setText(`${Math.round(s)}%`),this.footerContextEl.toggleClass("warning",s>=70&&s<85),this.footerContextEl.toggleClass("danger",s>=85),this.footerContextEl.setAttribute("title",e)}updateActiveTabSessionInfo(t){let e=this.activeTab;if(!e||!t)return;typeof t.sessionFile=="string"&&(e.sessionFile=t.sessionFile),typeof t.sessionId=="string"&&(e.sessionId=t.sessionId);let i=t.name||t.sessionName||t.title;typeof i=="string"&&i.trim()&&(e.label=i.trim().slice(0,24),this.renderTabs())}async persistSessionTabs(){this.plugin.settings.sessionTabs=this.tabs.map(t=>({label:t.label,sessionFile:t.sessionFile,sessionId:t.sessionId,modelProvider:t.modelProvider,modelId:t.modelId,thinkingLevel:t.thinkingLevel})),this.plugin.settings.activeSessionFile=this.activeTab?.sessionFile||"",await this.plugin.saveSettings()}restoreTabModelConfig(){let t=this.plugin.settings.sessionTabs||[];for(let e=0;e<this.tabs.length&&e<t.length;e++){let i=t[e];i&&(i.modelProvider&&(this.tabs[e].modelProvider=i.modelProvider),i.modelId&&(this.tabs[e].modelId=i.modelId),typeof i.thinkingLevel=="string"&&(this.tabs[e].thinkingLevel=i.thinkingLevel))}}updateModelDisplay(t,e){if(!this.footerModelLabel)return;let i=e.replace(/^claude-/,"").replace(/^gpt-/,"GPT-").replace(/^deepseek-/,"DeepSeek ").slice(0,18);this.footerModelLabel.setText(i||t),this.footerModelLabel.setAttribute("title",`${t}/${e}`)}refreshSmartReviewToggle(){this.updateSmartReviewToggleUI()}updateSmartReviewToggleUI(){if(!this.smartReviewToggleEl)return;let t=this.plugin.settings.smartReviewEnabled===!0,e=this.plugin.settings.language!=="en";this.smartReviewToggleEl.setText(e?"\u5BA1":"Review"),this.smartReviewToggleEl.setAttribute("title",t?e?"\u667A\u80FD\u5BA1\u6838\u5DF2\u5F00\u542F\uFF1A\u957F\u4EFB\u52A1\u4F1A\u81EA\u68C0\u5E76\u4F18\u5316\u540E\u518D\u8F93\u51FA":"Smart review on: long tasks self-check before replying":e?"\u667A\u80FD\u5BA1\u6838\u5DF2\u5173\u95ED":"Smart review off"),this.smartReviewToggleEl.toggleClass("is-enabled",t)}async insertLastAssistantIntoActiveNote(){if(!this.client)return;let e=(this.app.workspace.getActiveViewOfType(h.MarkdownView)||(this.app.workspace.getLeavesOfType("markdown").map(i=>i.view).find(i=>i instanceof h.MarkdownView)??null))?.editor;if(!e){new h.Notice("Open a markdown note first");return}try{let i=await this.client.getLastAssistantText(),s=i.data?.text;if(!i.success||!s){new h.Notice("No Pimate response to insert");return}e.replaceSelection(s),new h.Notice("Inserted last Pimate response")}catch(i){new h.Notice(`Insert failed: ${i.message}`)}}async refreshThinkingVisibility(){this.activeTab?.isStreaming||await this.reloadMessagesFromClient()}async reloadMessagesFromClient(){this.chatContainer&&this.chatContainer.empty(),this.renderedMessages=[],this.historyShownCount=0,this.historyTotalCount=0,this.historyBannerEl=null,this.renderEmptyState(),await this.loadMessages()}async loadMessages(){if(!this.client)return;let e=this.activeTab?.sessionFile,i=this.plugin.settings.maxHistoryDisplay,s=[],n=0,o=!1;if(e){let a=this.readLastMessagesFromFile(e,i);a.total>0&&(s=a.messages,n=a.total,o=!0)}if(!o)try{let a=await this.client.getMessages();if(a.success&&a.data){let r=a.data.messages||[];n=r.length,s=i>0?r.slice(-i):r}}catch{console.log("[pi-agent] No existing messages to load");return}this.historyShownCount=s.length,this.historyTotalCount=n;for(let a of s)this.renderMessageFromHistory(a);this.renderHistoryBanner(),this.scrollToBottom(!0,!0)}async loadMoreHistory(t){let e=this.activeTab;if(!e?.sessionFile)return;let i=this.historyShownCount+t,s=this.readLastMessagesFromFile(e.sessionFile,i);if(s.messages.length<=this.historyShownCount){new h.Notice("No more messages to load");return}let n=s.messages.slice(this.historyShownCount),o=this.chatContainer,a=o?.scrollHeight||0;for(let r of n)this.renderMessageFromHistory(r);if(this.historyShownCount=s.messages.length,this.historyTotalCount=s.total,this.renderHistoryBanner(),o){let r=o.scrollHeight;o.scrollTop=r-a+(o.scrollTop||0)}}renderHistoryBanner(){if(!this.chatContainer||(this.historyBannerEl&&this.historyBannerEl.remove(),this.historyBannerEl=null,this.historyTotalCount<=this.historyShownCount))return;let t=this.chatContainer.createDiv("pi-agent-history-banner");t.createSpan("pi-agent-history-banner-text").setText(`Showing the latest ${this.historyShownCount} of ${this.historyTotalCount} messages`);let i=t.createEl("button",{text:"Load 50 more",cls:"pi-agent-history-banner-btn"});i.onclick=()=>{i.setText("Loading\u2026"),i.disabled=!0,this.loadMoreHistory(50).finally(()=>{i.setText("Load 50 more"),i.disabled=!1})};let s=t.createEl("button",{text:"Load all",cls:"pi-agent-history-banner-btn pi-agent-history-banner-btn-secondary"});s.onclick=()=>{s.setText("Loading\u2026"),s.disabled=!0,this.loadMoreHistory(this.historyTotalCount).finally(()=>{s.setText("Load all"),s.disabled=!1})},this.chatContainer.prepend(t),this.historyBannerEl=t}finalizeAssistantMessageVisibility(t){let e=!!t.contentEl.querySelector(".pi-agent-text-block"),i=Array.from(t.contentEl.querySelectorAll(".pi-agent-thinking-block")),s=i.some(o=>!!o.querySelector(".pi-agent-thinking-content")?.textContent?.trim()),n=!!t.contentEl.querySelector(".pi-agent-tool-block");for(let o of i)o.querySelector(".pi-agent-thinking-content")?.textContent?.trim()||o.remove();if(!e&&!s&&!n){t.el.remove(),this.renderedMessages=this.renderedMessages.filter(o=>o!==t);return}t.el.toggleClass("is-tool-only",n&&!e&&!s)}renderMessageFromHistory(t){if(t.role==="user"){let e=typeof t.content=="string"?t.content:Array.isArray(t.content)?t.content.map(i=>i.text||"").join(""):"";this.addMessage("user",this.stripRecentContextGuard(e))}else if(t.role==="compactionSummary")this.addCompactionSummaryMessage(t.summary||"",t.tokensBefore);else if(t.role==="branchSummary")this.addCompactionSummaryMessage(t.summary||"",void 0,"Branch summary");else if(t.role==="assistant"){let e=Array.isArray(t.content)?t.content:[],i=e.some(a=>a.type==="text"&&String(a.text||"").trim()),s=e.some(a=>a.type==="thinking"&&String(a.thinking||"").trim()),n=e.some(a=>a.type==="toolCall");if(!i&&!s&&!n)return;let o=this.addMessage("assistant","");if(this.currentAssistantMsg=o,e.length>0)for(let a of e)if(a.type==="text"&&a.text){o.el.setAttribute("data-raw-content",a.text);let r=o.contentEl.createDiv("pi-agent-text-block markdown-preview-view markdown-rendered");h.MarkdownRenderer.render(this.app,this.normalizeAssistantMarkdown(a.text),r,"",this)}else if(a.type==="thinking"&&this.plugin.settings.showThinking&&String(a.thinking||"").trim()){let r=o.contentEl.createDiv("pi-agent-thinking-block is-collapsed"),l=r.createDiv("pi-agent-thinking-header"),d=l.createSpan("pi-agent-thinking-icon");(0,h.setIcon)(d,"brain"),l.createSpan("pi-agent-thinking-text").setText(" Thought"),r.createDiv("pi-agent-thinking-content").textContent=a.thinking||"",l.onclick=()=>{r.toggleClass("is-collapsed",!r.hasClass("is-collapsed"))}}else a.type==="toolCall"&&this.handleToolStart({type:"tool_execution_start",toolName:a.name,toolCallId:a.id,args:a.arguments});this.finalizeAssistantMessageVisibility(o),this.currentAssistantMsg=null}else t.role==="toolResult"&&this.handleToolEnd({type:"tool_execution_end",toolName:t.toolName,toolCallId:t.toolCallId,isError:t.isError,result:{content:t.content,isError:t.isError,details:t.details}})}updateButtons(){this.abortBtn&&(this.isStreaming?this.abortBtn.removeClass("pi-agent-hidden"):this.abortBtn.addClass("pi-agent-hidden")),this.containerEl.toggleClass("is-generating",this.isStreaming)}getBasename(t){if(!t)return"";let e=t.split(/[/\\]/);return e[e.length-1]||t}formatToolArgs(t,e){switch(t){case"read":{let i=e.path||e.TargetFile||e.target||"";return`${this.getBasename(i)}${e.offset?` (offset: ${e.offset})`:""}`}case"bash":{let i=e.command||"";return i.length>35?i.slice(0,35)+"...":i}case"write":{let i=e.path||e.TargetFile||e.target||"";return this.getBasename(i)}case"edit":{let i=e.path||e.TargetFile||e.target||"";return this.getBasename(i)}case"grep":return`${e.pattern||""}`;case"find":return`${e.pattern||""}`;case"ls":return this.getBasename(e.path||".");default:return JSON.stringify(e).slice(0,100)}}getToolIcon(t){switch(t){case"read":return"\u25C7";case"write":return"\u229E";case"edit":return"\u270E";case"bash":return"\u2318";case"grep":case"find":return"\u2315";case"ls":return"\u25A3";default:return"\u2727"}}toTitleCase(t){return t.charAt(0).toUpperCase()+t.slice(1)}renderDiffOutput(t,e){let s=t.createDiv("pi-agent-diff-actions").createEl("button",{text:"Copy diff"});s.onclick=a=>{a.stopPropagation(),navigator.clipboard.writeText(e).then(()=>{new h.Notice("Diff copied")}).catch(r=>{console.error("[pimate] copy diff failed",r)})};let n=t.createEl("pre",{cls:"pi-agent-diff-pre"}),o=e.length>12e3?e.slice(0,12e3)+`
\u2026`:e;for(let a of o.split(`
`)){let r=n.createSpan({text:`${a}
`});a.startsWith("+")&&!a.startsWith("+++")?r.addClass("pi-agent-diff-line-add"):a.startsWith("-")&&!a.startsWith("---")?r.addClass("pi-agent-diff-line-remove"):a.startsWith("@@")?r.addClass("pi-agent-diff-line-hunk"):(a.startsWith("diff ")||a.startsWith("+++")||a.startsWith("---"))&&r.addClass("pi-agent-diff-line-meta")}}getDiffText(t){if(!t||typeof t!="object")return"";let e=t;return typeof e.patch=="string"?e.patch:typeof e.diff=="string"?e.diff:""}getDiffStats(t){let e=this.getDiffText(t);if(!e)return null;let i=0,s=0;for(let n of e.split(`
`))n.startsWith("+++")||n.startsWith("---")||(n.startsWith("+")&&i++,n.startsWith("-")&&s++);return i||s?{added:i,removed:s}:null}async onClose(){this.thinkingTimer&&(window.clearInterval(this.thinkingTimer),this.thinkingTimer=null),this.renderTimeout&&(window.clearTimeout(this.renderTimeout),this.renderTimeout=null),this.speedTimer&&(window.clearInterval(this.speedTimer),this.speedTimer=null),this.speedHideTimer&&(window.clearTimeout(this.speedHideTimer),this.speedHideTimer=null),await this.persistSessionTabs();for(let t of this.tabs)await t.client?.destroy(),t.client=null;this.client=null}shouldUsePrettyStreaming(t){let e=this.plugin.settings.streamingRenderMode||"auto";return e==="pretty"}isAutoStreamingMode(){return(this.plugin.settings.streamingRenderMode||"auto")==="auto"}convertCurrentTextBlockToFastStreaming(){this.currentTextBlock&&(this.currentTextBlock.classList.remove("markdown-preview-view","markdown-rendered"),this.currentTextBlock.classList.add("pi-agent-streaming-block"),this.currentTextBlock.empty(),this.streamingTextEl=this.currentTextBlock.createDiv("pi-agent-streaming-text"),this.streamingCursorEl=this.currentTextBlock.createSpan("pi-agent-streaming-cursor"))}throttleRender(t,e){this.renderTimeout&&(window.clearTimeout(this.renderTimeout),this.renderTimeout=null);let s=this.isAutoStreamingMode()?140:150,n=Date.now();n-this.lastRenderTime>=s?(this.renderMarkdownWithCursor(t,e),this.lastRenderTime=n):this.renderTimeout=window.setTimeout(()=>{this.renderMarkdownWithCursor(t,e),this.lastRenderTime=Date.now()},s-(n-this.lastRenderTime))}appendStreamingDelta(t,e){this.renderTimeout&&(window.clearTimeout(this.renderTimeout),this.renderTimeout=null);let i=Date.now(),s=50,n=()=>{let o=this.isNearBottom();this.streamingTextEl&&(this.streamingTextEl.textContent=t),o&&this.scrollToBottom(!0,!0),this.lastRenderTime=Date.now()};i-this.lastRenderTime>=s?n():this.renderTimeout=window.setTimeout(n,s-(i-this.lastRenderTime)),this.isAutoStreamingMode()&&e&&e.includes(`
`)&&!this.isInsideUnclosedFence(t)&&this.flushPrettyIfNeeded()}isInsideUnclosedFence(t){let e=!1,i="",s=0;for(let n of t.split(/\r?\n/)){let o=n.match(/^\s*(`{3,}|~{3,})\s*([^\s`]*)\s*$/);if(!o)continue;let a=o[1],r=a[0];e?r===i&&a.length>=s&&(e=!1,i="",s=0):(e=!0,i=r,s=a.length)}return e}flushPrettyIfNeeded(){if(!this.isAutoStreamingMode()||!this.currentTextBlock||!this.streamingTextEl)return;let t=this.currentTextBlock.getAttribute("data-stream-raw")||this.streamingTextEl.textContent||"";t&&this.renderMarkdownWithCursor(t,this.currentTextBlock)}normalizeAssistantMarkdown(t){if(!t)return t;let e=[],i="@@PIMATE_CODE_BLOCK_";return t.replace(/```[\s\S]*?```/g,o=>{let a=`${i}${e.length}@@`;return e.push(o),a}).replace(/([^\n])([ \t]*#{2,6})(?=[\p{L}\p{N}])/gu,(o,a,r)=>`${a}
${r.trim()} `).replace(/^(#{1,6})(?!\s)([^#\s].*)$/gmu,(o,a,r)=>`${a} ${r}`).replace(/^(#{1,6}\s+[A-Za-z]\.)(?=\S)/gmu,"$1 ").replace(new RegExp(`${i}(\\d+)@@`,"g"),(o,a)=>e[Number(a)]||"")}renderMarkdownWithCursor(t,e){let i=this.isNearBottom();e.empty();let s=this.normalizeAssistantMarkdown(t),n=this.isInsideUnclosedFence(s),a=s+(n?" \u258A":' <span class="pi-agent-typing-cursor">\u258A</span>'),r=n?a+"\n```":a;h.MarkdownRenderer.render(this.app,r,e,"",this).then(()=>{i&&this.scrollToBottom(!0,!0)})}handleMentionInput(){if(!this.inputEl)return;let t=this.inputEl.value,e=this.inputEl.selectionStart,i=-1;for(let s=e-1;s>=0;s--){let n=t[s];if(n===" "||n===`
`)break;if(n==="@"&&(s===0||t[s-1]===" "||t[s-1]===`
`)){i=s;break}}if(i!==-1){let s=t.slice(i+1,e).toLowerCase();this.mentionQueryStart=i,this.showMentionDropdown(s)}else this.closeMentionDropdown()}showMentionDropdown(t){if(!this.inputEl)return;if(!this.mentionDropdown){let a=this.inputEl.parentElement;if(!a)return;this.mentionDropdown=a.createDiv({cls:"pi-agent-mention-dropdown"})}let e=t.toLowerCase(),i=this.getAttachableFiles(),s=this.app.vault.getAllFolders?this.app.vault.getAllFolders():this.collectAllFolders(),n=i.map(a=>this.createMentionEntry("file",a,e)).filter(a=>a!==null),o=s.map(a=>this.createMentionEntry("folder",a,e)).filter(a=>a!==null);this.filteredMentionFiles=[...o,...n].sort((a,r)=>r.score!==a.score?r.score-a.score:a.path.length!==r.path.length?a.path.length-r.path.length:a.path.localeCompare(r.path)).slice(0,20),this.renderMentionDropdownItems()}createMentionEntry(t,e,i){let s=e.path||"/",n=e instanceof h.TFile?e.basename:e.name||s,o=this.scoreMentionMatch(n,s,i);if(o<=0)return null;let a=this.app.workspace.getActiveFile(),r=e instanceof h.TFile&&a?.path===e.path?100:0,l=t==="folder"?20:0;return{kind:t,file:e instanceof h.TFile?e:void 0,folder:e instanceof h.TFolder?e:void 0,score:o+r+l,path:s,name:n}}scoreMentionMatch(t,e,i){if(!i)return 100;let s=i.toLowerCase(),n=t.toLowerCase(),o=e.toLowerCase();return n===s||o===s?1e3:n.startsWith(s)?800:o.startsWith(s)?700:n.includes(s)?600:o.includes(s)?400:0}collectAllFolders(){let t=[],e=this.app.vault.getRoot(),i=s=>{t.push(s);for(let n of s.children??[])n instanceof h.TFolder&&i(n)};return e&&i(e),t}renderMentionDropdownItems(){if(this.mentionDropdown){if(this.mentionDropdown.empty(),this.filteredMentionFiles.length===0){this.closeMentionDropdown();return}this.activeMentionIndex=Math.min(this.activeMentionIndex,this.filteredMentionFiles.length-1),this.activeMentionIndex<0&&(this.activeMentionIndex=0),this.filteredMentionFiles.forEach((t,e)=>{let i=this.mentionDropdown.createDiv({cls:`pi-agent-mention-item ${e===this.activeMentionIndex?"is-active":""}`}),s=t.kind==="folder"?"\u{1F4C1}":this.getFileTypeIcon(t.file.extension),n=t.kind==="folder"?t.path:t.name,o=t.kind==="folder"?"":t.path;i.createSpan({text:s+" ",cls:"pi-agent-mention-item-icon"});let a=i.createDiv({cls:"pi-agent-mention-item-text"});a.createSpan({text:n,cls:"pi-agent-mention-item-name"}),o&&o!==n&&a.createSpan({text:o,cls:"pi-agent-mention-item-path"}),i.onclick=r=>{r.stopPropagation(),this.activeMentionIndex=e,this.insertMentionSelection()}})}}insertMentionSelection(){if(!this.inputEl||this.mentionQueryStart===-1)return;let t=this.filteredMentionFiles[this.activeMentionIndex];if(!t)return;let e=this.inputEl.value,i=this.inputEl.selectionStart,s=e.slice(0,this.mentionQueryStart),n=e.slice(i),o;if(t.kind==="folder"){let r=t.folder;if(!r)return;o=`[[${r.path||"/"}/]]`,this.addFolderContextItem(r,!1)}else{let r=t.file;if(!r)return;o=`[[${r.basename}]]`,this.addFileContextItem(r)}this.inputEl.value=s+o+" "+n;let a=this.mentionQueryStart+o.length+1;this.inputEl.setSelectionRange(a,a),this.closeMentionDropdown(),this.inputEl.focus()}closeMentionDropdown(){this.mentionDropdown&&(this.mentionDropdown.remove(),this.mentionDropdown=null),this.mentionQueryStart=-1,this.filteredMentionFiles=[],this.activeMentionIndex=0}async loadAvailableCommands(){if(this.client)try{let t=await this.client.getCommands();t.success&&t.data&&(this.availableCommands=t.data.commands||[])}catch{}}handleCommandInput(){if(!this.inputEl)return;let t=this.inputEl.value,e=this.inputEl.selectionStart;if(t.startsWith("/")&&e>0&&!t.slice(0,e).includes(" ")){let i=t.slice(1,e).toLowerCase();this.commandQueryStart=0,this.showCommandDropdown(i)}else this.closeCommandDropdown()}showCommandDropdown(t){if(this.inputEl){if(!this.commandDropdown){let e=this.inputEl.parentElement;if(!e)return;this.commandDropdown=e.createDiv({cls:"pi-agent-command-dropdown"})}this.filteredCommands=this.availableCommands.filter(e=>e.name.toLowerCase().includes(t)||e.description&&e.description.toLowerCase().includes(t)).slice(0,5),this.renderCommandDropdownItems()}}renderCommandDropdownItems(){if(this.commandDropdown){if(this.commandDropdown.empty(),this.filteredCommands.length===0){this.closeCommandDropdown();return}this.activeCommandIndex=Math.min(this.activeCommandIndex,this.filteredCommands.length-1),this.activeCommandIndex<0&&(this.activeCommandIndex=0),this.filteredCommands.forEach((t,e)=>{let i=this.commandDropdown.createDiv({cls:`pi-agent-command-item ${e===this.activeCommandIndex?"is-active":""}`});i.createSpan({text:"\u26A1 ",cls:"pi-agent-command-item-icon"}),i.createSpan({text:`/${t.name}`,cls:"pi-agent-command-item-name"}),t.description&&i.createSpan({text:` - ${t.description}`,cls:"pi-agent-command-item-desc"}),i.onclick=s=>{s.stopPropagation(),this.activeCommandIndex=e,this.insertCommandSelection()}})}}insertCommandSelection(){if(!this.inputEl||this.commandQueryStart===-1)return;let t=this.filteredCommands[this.activeCommandIndex];if(!t)return;let e=this.inputEl.value,i=this.inputEl.selectionStart,s=e.slice(0,this.commandQueryStart),n=e.slice(i),o=`/${t.name}`;this.inputEl.value=s+o+" "+n;let a=this.commandQueryStart+o.length+1;this.inputEl.setSelectionRange(a,a),this.closeCommandDropdown(),this.resizeInputEl(),this.inputEl.focus()}closeCommandDropdown(){this.commandDropdown&&(this.commandDropdown.remove(),this.commandDropdown=null),this.commandQueryStart=-1,this.filteredCommands=[],this.activeCommandIndex=0}getThinkingLevelLabel(t){switch(t?.toLowerCase()||""){case"":case"auto":return"Auto";case"off":return"Off";case"minimal":return"Minimal";case"low":return"Low";case"medium":return"Medium";case"high":return"High";case"xhigh":return"XHigh";case"max":return"Max";default:return t||"Auto"}}async showThinkingLevelSelector(){let t=this.plugin.settings.language==="zh",e=this.activeTab;e?.client&&await this.syncTabStateFromPi(e);let{options:i,note:s}=this.buildThinkingLevelOptions(e),n;if(i.length===0){new h.Notice(s??(t?"\u5F53\u524D\u6A21\u578B\u6CA1\u6709\u53EF\u9009\u601D\u8003\u6863\u4F4D":"No selectable thinking level for current model"));return}else n=i.map(o=>({id:o.id,name:`${o.name} (${o.id})`,desc:o.desc}));new ge(this.app,n,t,async o=>{await this.updateActiveTabThinkingLevel(o.id),new h.Notice(t?`\u601D\u8003\u5F3A\u5EA6\u5DF2\u8BBE\u4E3A ${o.name}`:`Thinking level set to ${o.name}`)}).open()}async setupStaticTabs(){let t=this.plugin.settings.maxTabs||3;if(this.tabs.length>t)this.tabs=this.tabs.slice(0,t);else for(;this.tabs.length<t;){let e=this.tabs.length+1;this.tabs.push({id:`tab-static-${e}`,label:String(e),client:null,isStreaming:!1})}this.restoreTabModelConfig(),this.tabs.some(e=>e.id===this.activeTabId)||(this.activeTabId=this.tabs[0]?.id||null),this.renderTabs(),this.activeTabId&&await this.switchToTab(this.activeTabId)}activeDropdown=null;activeDropdownEl=null;availableModelsCache=null;modelOutsideClickHandler=null;effortOutsideClickHandler=null;getModelShortName(t){let e=t.toLowerCase();if(e.includes("opus"))return"Opus";if(e.includes("sonnet"))return"Sonnet";if(e.includes("haiku"))return"Haiku";if(e.includes("deepseek")){if(e.includes("reasoner")||e.includes("r1"))return"DeepSeek-R1";if(e.includes("chat")||e.includes("v3"))return"DeepSeek-V3";let i=t.split("/").pop()||t;return i.toLowerCase()==="deepseek"?"DeepSeek":i.split("-").map(s=>s.charAt(0).toUpperCase()+s.slice(1)).join("-")}return e.includes("gemini")?"Gemini":e.includes("gpt-4o")?"GPT-4o":e.includes("o1")?"o1":e.includes("o3")?"o3":t.split("/").pop()||t}getProviderIconName(t,e){let i=t.toLowerCase(),s=e.toLowerCase();return i.includes("xiaomi")||i.includes("\u5C0F\u7C73")||s.includes("xiaomi")||s.includes("milm")?"pi-agent-icon-xiaomi":i.includes("openai")||i.includes("gpt")||s.includes("gpt")?"pi-agent-icon-openai":i.includes("anthropic")||i.includes("claude")||s.includes("claude")?"pi-agent-icon-claude":i.includes("deepseek")||s.includes("deepseek")?"pi-agent-icon-deepseek":i.includes("minimax")||s.includes("minimax")?"pi-agent-icon-minimax":i.includes("google")||i.includes("gemini")||s.includes("gemini")?"pi-agent-icon-gemini":i.includes("volcengine")||i.includes("doubao")||i.includes("seed")||s.includes("doubao")||s.includes("seed")?"pi-agent-icon-volcengine":i.includes("siliconflow")||i.includes("siliconcloud")||s.includes("siliconflow")||s.includes("siliconcloud")?"pi-agent-icon-siliconflow":i.includes("zhipu")||i.includes("\u667A\u8C31")||s.includes("glm")||s.includes("zhipu")?"pi-agent-icon-zhipu":"pi-agent-icon-claude"}},ne=class extends h.SuggestModal{constructor(e,i,s){super(e);this.commands=i;this.onChoose=s;this.setPlaceholder("Search commands and skills...")}commands;onChoose;getSuggestions(e){let i=e.toLowerCase().trim();return i?this.commands.filter(s=>`${s.name} ${s.description||""} ${s.source||""}`.toLowerCase().includes(i)).slice(0,80):this.commands.slice(0,80)}renderSuggestion(e,i){i.addClass("pi-agent-suggestion"),i.createDiv({text:`/${e.name}`,cls:"pi-agent-suggestion-title"}),i.createDiv({text:`${e.source||"command"}${e.description?` \xB7 ${e.description}`:""}`,cls:"pi-agent-suggestion-note"})}onChooseSuggestion(e){this.onChoose(e)}},oe=class extends h.SuggestModal{constructor(e,i,s){super(e);this.sessions=i;this.onChoose=s;this.setPlaceholder("Resume which Pi session?")}sessions;onChoose;getSuggestions(e){let i=e.toLowerCase().trim();return i?this.sessions.filter(s=>`${s.label} ${s.preview||""} ${s.path}`.toLowerCase().includes(i)).slice(0,80):this.sessions.slice(0,80)}renderSuggestion(e,i){i.addClass("pi-agent-suggestion"),i.createDiv({text:e.label||(0,B.basename)(e.path),cls:"pi-agent-suggestion-title"});let s=new Date(e.mtime).toLocaleString();i.createDiv({text:`${s} \xB7 ${e.preview||e.path}`,cls:"pi-agent-suggestion-note"})}onChooseSuggestion(e){Promise.resolve(this.onChoose(e)).catch(i=>{console.error("[pimate] resume session selection failed",i)})}},ae=class extends h.Modal{constructor(e,i,s){super(e);this.session=i;this.done=s;this.titleEl.setText("Pimate session")}session;done;onOpen(){let{contentEl:e}=this;e.empty(),e.addClass("pi-agent-editor-modal"),e.createDiv({text:this.session.label,cls:"pi-agent-suggestion-title"}),e.createDiv({text:this.session.path,cls:"pi-agent-suggestion-note"}),this.session.preview&&e.createEl("pre",{cls:"pi-agent-context-preview-text"}).setText(this.session.preview);let i=e.createDiv("pi-agent-editor-modal-buttons"),s=i.createEl("button",{text:"Cancel"}),n=i.createEl("button",{text:"Delete"}),o=i.createEl("button",{text:"Open",cls:"mod-cta"});s.onclick=()=>{Promise.resolve(this.done("cancel")).catch(a=>console.error("[pimate] resume action failed",a)),this.close()},n.onclick=()=>{Promise.resolve(this.done("delete")).catch(a=>console.error("[pimate] resume action failed",a)),this.close()},o.onclick=()=>{Promise.resolve(this.done("open")).catch(a=>console.error("[pimate] resume action failed",a)),this.close()}}onClose(){this.contentEl.empty()}},re=class extends h.SuggestModal{constructor(e,i,s){super(e);this.messages=i;this.onChoose=s;this.setPlaceholder("Fork from which previous prompt?")}messages;onChoose;getSuggestions(e){let i=e.toLowerCase().trim();return i?this.messages.filter(s=>s.text.toLowerCase().includes(i)).reverse().slice(0,80):this.messages.slice().reverse().slice(0,80)}renderSuggestion(e,i){i.addClass("pi-agent-suggestion"),i.createDiv({text:e.text.split(`
`)[0].slice(0,90)||"Untitled prompt",cls:"pi-agent-suggestion-title"}),i.createDiv({text:e.entryId,cls:"pi-agent-suggestion-note"})}onChooseSuggestion(e){Promise.resolve(this.onChoose(e)).catch(i=>{console.error("[pimate] fork message selection failed",i)})}},le=class extends h.SuggestModal{constructor(e,i,s){super(e);this.models=i;this.onChoose=s;this.setPlaceholder("Search model, e.g. deepseek / claude / gpt...")}models;onChoose;getSuggestions(e){let i=e.toLowerCase().trim();return i?this.models.filter(s=>`${s.provider}/${s.id} ${s.name||""}`.toLowerCase().includes(i)).slice(0,80):this.models.slice(0,80)}renderSuggestion(e,i){i.addClass("pi-agent-suggestion"),i.createDiv({text:e.name||e.id,cls:"pi-agent-suggestion-title"}),i.createDiv({text:`${e.provider}/${e.id}`,cls:"pi-agent-suggestion-note"})}onChooseSuggestion(e){Promise.resolve(this.onChoose(e)).catch(i=>{console.error("[pimate] model selection failed",i)})}},ce=class extends h.SuggestModal{constructor(e,i,s){super(e);this.files=i;this.onChoose=s;this.setPlaceholder("Search file to attach as @context...")}files;onChoose;getSuggestions(e){let i=e.toLowerCase().trim();return i?this.files.filter(s=>s.path.toLowerCase().includes(i)).slice(0,80):this.files.slice(0,80)}renderSuggestion(e,i){i.addClass("pi-agent-suggestion"),i.createDiv({text:e.basename,cls:"pi-agent-suggestion-title"}),i.createDiv({text:e.path,cls:"pi-agent-suggestion-note"})}onChooseSuggestion(e){this.onChoose(e)}},de=class extends h.SuggestModal{constructor(e,i,s,n){super(e);this.modalTitle=i;this.options=s;this.done=n;this.setPlaceholder(i||"Select an option")}modalTitle;options;done;answered=!1;getSuggestions(e){let i=e.toLowerCase();return this.options.filter(s=>s.toLowerCase().includes(i))}renderSuggestion(e,i){i.setText(e)}onChooseSuggestion(e){this.answered=!0,this.done(e)}onClose(){super.onClose(),this.answered||this.done(null)}},pe=class extends h.Modal{constructor(e,i,s,n){super(e);this.placeholder=s;this.done=n;this.titleEl.setText(i||"Pimate input")}placeholder;done;answered=!1;inputEl;onOpen(){let{contentEl:e}=this;e.empty(),e.addClass("pi-agent-editor-modal"),this.inputEl=e.createEl("input",{cls:"pi-agent-input-modal-input",attr:{type:"text",placeholder:this.placeholder}}),this.inputEl.value=this.placeholder||"",this.inputEl.focus(),this.inputEl.addEventListener("keydown",s=>{s.key==="Enter"&&this.submit(),s.key==="Escape"&&this.cancel()});let i=e.createDiv("pi-agent-editor-modal-buttons");i.createEl("button",{text:"Cancel"}).onclick=()=>this.cancel(),i.createEl("button",{text:"OK",cls:"mod-cta"}).onclick=()=>this.submit()}submit(){this.answered=!0,this.done(this.inputEl.value),this.close()}cancel(){this.answered=!0,this.done(null),this.close()}onClose(){this.contentEl.empty(),this.answered||this.done(null)}},J=class extends h.Modal{constructor(e,i,s,n){super(e);this.message=s;this.done=n;this.titleEl.setText(i||"Pimate confirmation")}message;done;answered=!1;onOpen(){let{contentEl:e}=this;e.empty(),e.addClass("pi-agent-editor-modal"),e.createEl("pre",{cls:"pi-agent-context-preview-text"}).setText(this.message||"Allow this action?");let s=e.createDiv("pi-agent-editor-modal-buttons"),n=s.createEl("button",{text:"Deny"}),o=s.createEl("button",{text:"Allow",cls:"mod-cta"});n.onclick=()=>{this.answered=!0,this.done(!1),this.close()},o.onclick=()=>{this.answered=!0,this.done(!0),this.close()}}onClose(){this.contentEl.empty(),this.answered||this.done(!1)}},Q=class extends h.Modal{constructor(e,i){super(e);this.item=i;this.titleEl.setText(this.item.label||"Context preview")}item;onOpen(){let{contentEl:e}=this;if(e.empty(),e.addClass("pi-agent-context-preview-modal"),this.item.type==="image"){e.createEl("img",{cls:"pi-agent-context-preview-image",attr:{src:`data:${this.item.mimeType||"image/png"};base64,${this.item.value}`}});return}e.createEl("pre",{cls:"pi-agent-context-preview-text"}).setText(this.item.value)}onClose(){this.contentEl.empty()}},he=class extends h.Modal{done;submitted=!1;constructor(t,e){super(t),this.titleEl.setText("Inline edit with Pimate"),this.done=e}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("pi-agent-editor-modal"),t.createDiv({text:"Describe how Pimate should rewrite the selected text.",cls:"pi-agent-suggestion-note"});let e=t.createEl("textarea",{cls:"pi-agent-editor-modal-textarea",attr:{placeholder:"Make it clearer, shorter, more direct..."}});e.addClass("pi-agent-textarea-min-height"),e.focus();let i=t.createDiv("pi-agent-editor-modal-buttons"),s=i.createEl("button",{text:"Cancel"}),n=i.createEl("button",{text:"Apply",cls:"mod-cta"});s.onclick=()=>{this.submitted=!0,this.done(null),this.close()},n.onclick=()=>{this.submitted=!0,this.done(e.value.trim()||null),this.close()}}onClose(){this.contentEl.empty(),this.submitted||this.done(null)}},ue=class extends h.Modal{constructor(e,i,s,n){super(e);this.original=i;this.replacement=s;this.titleEl.setText("Review Pimate inline edit"),this.done=n}original;replacement;done;answered=!1;renderSimpleDiff(e,i,s){e.empty();let n=this.computeSimpleDiff(i,s);for(let o=0;o<n.length;o++){let a=n[o];e.createSpan({text:a.text,cls:a.cls}),o<n.length-1&&e.appendText(`
`)}}computeSimpleDiff(e,i){let s=e.split(`
`),n=i.split(`
`),o=Array(s.length+1).fill(null).map(()=>Array(n.length+1).fill(0));for(let d=1;d<=s.length;d++)for(let c=1;c<=n.length;c++)s[d-1]===n[c-1]?o[d][c]=o[d-1][c-1]+1:o[d][c]=Math.max(o[d-1][c],o[d][c-1]);let a=s.length,r=n.length,l=[];for(;a>0||r>0;)a>0&&r>0&&s[a-1]===n[r-1]?(l.unshift({text:s[a-1]}),a--,r--):r>0&&(a===0||o[a][r-1]>=o[a-1][r])?(l.unshift({text:`+ ${n[r-1]}`,cls:"pi-diff-ins"}),r--):(l.unshift({text:`- ${s[a-1]}`,cls:"pi-diff-del"}),a--);return l}onOpen(){let{contentEl:e}=this;e.empty(),e.addClass("pi-agent-editor-modal"),e.createDiv({text:"Changes Preview (\u7EA2\u7EFF\u5DEE\u5F02\u6BD4\u5BF9)",cls:"pi-agent-suggestion-title"});let i=e.createEl("pre",{cls:"pi-agent-diff-view-pre"});this.renderSimpleDiff(i,this.original,this.replacement),e.createDiv({text:"Edit Replacement (\u53EF\u9009\uFF1A\u5FAE\u8C03\u4FEE\u6539\u6587)",cls:"pi-agent-suggestion-title"});let s=e.createEl("textarea",{cls:"pi-agent-editor-modal-textarea"});s.value=this.replacement,s.addClass("pi-agent-textarea-min-height"),s.focus(),s.addEventListener("input",()=>{this.renderSimpleDiff(i,this.original,s.value)});let n=e.createDiv("pi-agent-editor-modal-buttons"),o=n.createEl("button",{text:"Reject"}),a=n.createEl("button",{text:"Regenerate"}),r=n.createEl("button",{text:"Apply",cls:"mod-cta"});o.onclick=()=>{this.answered=!0,this.done({action:"reject"}),this.close()},a.onclick=()=>{this.answered=!0,this.done({action:"regenerate"}),this.close()},r.onclick=()=>{this.answered=!0,this.done({action:"apply",replacement:s.value}),this.close()}}onClose(){this.contentEl.empty(),this.answered||this.done({action:"reject"})}},X=class extends h.Modal{value;done;submitted=!1;constructor(t,e,i,s){super(t),this.titleEl.setText(e||"Edit response"),this.value=i,this.done=s}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("pi-agent-editor-modal");let e=t.createEl("textarea",{cls:"pi-agent-editor-modal-textarea"});e.value=this.value,e.focus();let i=t.createDiv("pi-agent-editor-modal-buttons"),s=i.createEl("button",{text:"Cancel"}),n=i.createEl("button",{text:"Submit",cls:"mod-cta"});s.onclick=()=>{this.submitted=!0,this.done(null),this.close()},n.onclick=()=>{this.submitted=!0,this.done(e.value),this.close()}}onClose(){this.contentEl.empty(),this.submitted||this.done(null)}},ge=class extends h.SuggestModal{constructor(e,i,s,n){super(e);this.options=i;this.isZh=s;this.onChoose=n;this.setPlaceholder(s?"\u641C\u7D22\u6216\u9009\u62E9\u601D\u8003\u5F3A\u5EA6...":"Search or select thinking level...")}options;isZh;onChoose;getSuggestions(e){let i=e.toLowerCase().trim();return i?this.options.filter(s=>s.name.toLowerCase().includes(i)||s.id.toLowerCase().includes(i)||s.desc.toLowerCase().includes(i)):this.options}renderSuggestion(e,i){i.addClass("pi-agent-suggestion"),i.createDiv({text:e.name,cls:"pi-agent-suggestion-title"}),i.createDiv({text:e.desc,cls:"pi-agent-suggestion-note"})}onChooseSuggestion(e){Promise.resolve(this.onChoose(e)).catch(i=>{console.error("[pimate] thinking level selection failed",i)})}};function j(u){let t=new Date(u);return t.setHours(0,0,0,0),t}function q(u){let t=new Date(u);return t.setHours(23,59,59,999),t}function xe(u){let t=e=>String(e).padStart(2,"0");return`${u.getFullYear()}-${t(u.getMonth()+1)}-${t(u.getDate())}T${t(u.getHours())}:${t(u.getMinutes())}`}function Se(u){return new Date(u)}function N(u){return u>=1e9?(u/1e9).toFixed(2)+"B":u>=1e6?(u/1e6).toFixed(2)+"M":u>=1e4?(u/1e3).toFixed(1)+"k":u>=1e3?(u/1e3).toFixed(2)+"k":String(u)}function Me(u){return u===0?"$0":u<1e-4?"<$0.0001":u<.01?"$"+u.toFixed(4):u<1?"$"+u.toFixed(3):"$"+u.toFixed(2)}function Pe(u){if(!u)return"\u2014";let t=new Date(u);return`${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`}function Ie(u,t){let e=u+t;return e<=0?null:t/e}function Ae(u){return u===null?"var(--text-muted)":u>=.7?"rgba(34, 197, 94, 0.95)":u>=.3?"rgba(234, 179, 8, 0.95)":"rgba(239, 68, 68, 0.95)"}function qe(u){return u===null?"\u2014":(u*100).toFixed(1)+"%"}function se(u,t,e){let i=new Date;switch(u){case"today":return{from:j(i).getTime(),to:q(i).getTime(),label:"\u4ECA\u5929 / Today"};case"yesterday":{let s=new Date(i);return s.setDate(s.getDate()-1),{from:j(s).getTime(),to:q(s).getTime(),label:"\u6628\u5929 / Yesterday"}}case"last7":{let s=new Date(i);return s.setDate(s.getDate()-6),{from:j(s).getTime(),to:q(i).getTime(),label:"\u6700\u8FD1 7 \u5929 / Last 7 days"}}case"last30":{let s=new Date(i);return s.setDate(s.getDate()-29),{from:j(s).getTime(),to:q(i).getTime(),label:"\u6700\u8FD1 30 \u5929 / Last 30 days"}}case"thisMonth":{let s=new Date(i.getFullYear(),i.getMonth(),1);return{from:j(s).getTime(),to:q(i).getTime(),label:"\u672C\u6708 / This month"}}case"all":return{from:null,to:null,label:"\u5168\u90E8 / All time"};case"custom":{let s=t?Se(t).getTime():j(i).getTime(),n=e?Se(e).getTime():i.getTime(),o=new Date(s),a=new Date(n),r=l=>`${l.getMonth()+1}/${l.getDate()}`;return{from:s,to:n,label:`${r(o)} \u2013 ${r(a)}`}}}}var De=1;function Je(){return(0,B.join)((0,V.homedir)(),".pi","agent","usage-cache.json")}function Ge(u){try{if(!(0,A.existsSync)(u))return null;let t=(0,A.readFileSync)(u,"utf8"),e=JSON.parse(t);return!e||e.version!==De||!e.perFile?null:e}catch{return null}}function Ye(u,t){try{(0,A.writeFileSync)(u,JSON.stringify(t),"utf8")}catch{}}function Ze(u,t,e){let i="";try{i=(0,A.readFileSync)(u,"utf8")}catch{return t??{size:0,mtimeMs:0,processedLines:0,records:[]}}let s=i.split(/\r?\n/),n=i.endsWith(`
`)?s.length-1:s.length,o=!!t&&e.size<t.size,a=t&&!o?t.processedLines:0,r=t&&!o?t.records.slice():[];for(let l=a;l<n;l++){let d=s[l];if(!d)continue;let c;try{c=JSON.parse(d)}catch{continue}if(c?.type!=="message")continue;let p=c.message;if(!p||p.role!=="assistant")continue;let m=p.usage;if(!m)continue;let v=typeof c.timestamp=="string"?Date.parse(c.timestamp):0,w=p.provider||c.provider||"unknown",T=p.model||c.model||"unknown",k=Number(m.input)||0,M=Number(m.output)||0,x=Number(m.cacheRead)||0,g=Number(m.cacheWrite)||0,y=Number(m.totalTokens)||k+M+x+g,C=Number(m.cost?.total)||0;r.push([v,w,T,k,M,x,g,y,C])}return{size:e.size,mtimeMs:e.mtimeMs,processedLines:n,records:r}}function Qe(u,t){let e=Ge(t);e||(e={version:De,perFile:{}});let i=!1;if((0,A.existsSync)(u)){let s=(0,A.readdirSync)(u).filter(n=>n.startsWith("--")&&n.endsWith("--")).map(n=>(0,B.join)(u,n));for(let n of s){let o=[];try{o=(0,A.readdirSync)(n).filter(a=>a.endsWith(".jsonl"))}catch{continue}for(let a of o){let r=(0,B.join)(n,a),l;try{let p=(0,A.statSync)(r);l={size:p.size,mtimeMs:p.mtimeMs}}catch{continue}let d=(0,B.relative)(u,r).replace(/\\/g,"/"),c=e.perFile[d];c&&c.size===l.size&&c.mtimeMs===l.mtimeMs||(e.perFile[d]=Ze(r,c,l),i=!0)}}}return i&&Ye(t,e),e}function Xe(u,t,e){let i=new Map,s={input:0,output:0,cacheRead:0,cacheWrite:0,cacheTotal:0,totalTokens:0,cost:0,messageCount:0},n=0;for(let a of Object.keys(u)){let r=u[a].records,l=!1;for(let d of r){let c=d[0];if(c&&(t!=null&&c<t||e!=null&&c>e))continue;let p=d[1],m=d[2],v=`${p}::${m}`,w=i.get(v);w||(w={provider:p,model:m,messageCount:0,input:0,output:0,cacheRead:0,cacheWrite:0,cacheTotal:0,totalTokens:0,cost:0,hitRate:null,firstUsed:null,lastUsed:null},i.set(v,w));let T=d[3],k=d[4],M=d[5],x=d[6],g=d[7],y=d[8];w.messageCount+=1,w.input+=T,w.output+=k,w.cacheRead+=M,w.cacheWrite+=x,w.cacheTotal+=M+x,w.totalTokens+=g,w.cost+=y,c&&((w.firstUsed==null||c<w.firstUsed)&&(w.firstUsed=c),(w.lastUsed==null||c>w.lastUsed)&&(w.lastUsed=c)),s.input+=T,s.output+=k,s.cacheRead+=M,s.cacheWrite+=x,s.totalTokens+=g,s.cost+=y,s.messageCount+=1,l=!0}l&&(n+=1)}for(let a of i.values())a.hitRate=Ie(a.input,a.cacheRead);s.cacheTotal=s.cacheRead+s.cacheWrite;let o=Array.from(i.values()).sort((a,r)=>r.totalTokens-a.totalTokens);return{from:t,to:e,sessionCount:n,byModel:o,totals:s}}function et(u,t,e){let i=Qe(u,Je());return Xe(i.perFile,t,e)}var me=class extends h.Modal{preset="last7";customFrom=xe(j(new Date(new Date().setDate(new Date().getDate()-6))));customTo=xe(new Date);data=null;loading=!1;error=null;sortKey="totalTokens";sortDir="desc";bodyEl=null;summaryEl=null;tableEl=null;statusEl=null;rangeLabelEl=null;reqId=0;lang="zh";constructor(t,e){super(t),this.lang=e==="zh"?"zh":"en"}onOpen(){let{contentEl:t,modalEl:e}=this;t.empty(),e.addClass("pi-agent-usage-modal"),t.addClass("pi-agent-usage-content"),this.render()}onClose(){this.contentEl.empty(),this.modalEl.removeClass("pi-agent-usage-modal")}render(){let{contentEl:t}=this;t.empty();let e=this.lang==="zh",i=se(this.preset,this.customFrom,this.customTo),s=t.createDiv("pi-agent-usage-header"),n=s.createDiv("pi-agent-usage-title"),o=n.createSpan();(0,h.setIcon)(o,"bar-chart-3"),n.createSpan({text:e?"Token \u7528\u91CF":"Token Usage"}).addClass("pi-agent-title-text-spaced"),this.rangeLabelEl=n.createSpan({text:" \xB7 "+i.label,cls:"pi-agent-usage-range-label"});let r=s.createEl("button",{cls:"pi-agent-usage-btn-icon",attr:{title:e?"\u5237\u65B0":"Refresh","aria-label":"Refresh"}});(0,h.setIcon)(r,"refresh-cw"),r.onclick=()=>this.scan();let l=s.createEl("button",{cls:"pi-agent-usage-btn-icon",attr:{title:e?"\u5173\u95ED":"Close","aria-label":"Close"}});(0,h.setIcon)(l,"x"),l.onclick=()=>this.close();let d=t.createDiv("pi-agent-usage-rangebar"),c=[{id:"today",label:e?"\u4ECA\u5929":"Today"},{id:"yesterday",label:e?"\u6628\u5929":"Yesterday"},{id:"last7",label:e?"\u6700\u8FD1 7 \u5929":"Last 7d"},{id:"last30",label:e?"\u6700\u8FD1 30 \u5929":"Last 30d"},{id:"thisMonth",label:e?"\u672C\u6708":"This month"},{id:"all",label:e?"\u5168\u90E8":"All time"},{id:"custom",label:e?"\u81EA\u5B9A\u4E49\u2026":"Custom\u2026"}];for(let m of c){let v=d.createEl("button",{text:m.label,cls:"pi-agent-usage-preset"+(this.preset===m.id?" is-active":"")});v.onclick=()=>{this.preset=m.id,this.render()}}if(this.preset==="custom"){let m=d.createDiv("pi-agent-usage-custom-range"),v=m.createEl("input",{attr:{type:"datetime-local",value:this.customFrom}});m.createSpan({text:"\u2192"});let w=m.createEl("input",{attr:{type:"datetime-local",value:this.customTo}});v.onchange=()=>{this.customFrom=v.value,this.scan()},w.onchange=()=>{this.customTo=w.value,this.scan()}}this.statusEl=d.createDiv("pi-agent-usage-status"),this.summaryEl=t.createDiv("pi-agent-usage-summary"),this.tableEl=t.createDiv("pi-agent-usage-table"),this.tableEl.addClass("pi-agent-usage-table-scroll");let p=t.createDiv("pi-agent-usage-footer");p.createSpan({text:e?"\u70B9\u51FB\u5217\u6807\u9898\u6392\u5E8F \xB7 \u6570\u636E\u6E90\uFF1A~/.pi/agent/sessions":"Click a column to sort \xB7 Data source: ~/.pi/agent/sessions"}),p.createSpan({text:"Esc",cls:"pi-agent-usage-foot-hint"}),this.scan()}scan(){let t=++this.reqId;this.loading=!0,this.error=null,this.updateStatus(),window.setTimeout(()=>{if(t===this.reqId)try{let i=`${(0,V.homedir)().replace(/\\/g,"/")}/.pi/agent/sessions`,s=se(this.preset,this.customFrom,this.customTo),n=et(i,s.from,s.to);if(t!==this.reqId)return;this.data=n,this.loading=!1,this.updateRangeLabel(),this.renderSummary(),this.renderTable(),this.updateStatus()}catch(e){if(t!==this.reqId)return;this.error=e.message,this.loading=!1,this.updateStatus()}},0)}updateRangeLabel(){if(!this.rangeLabelEl)return;let t=se(this.preset,this.customFrom,this.customTo);this.rangeLabelEl.setText(" \xB7 "+t.label)}updateStatus(){if(!this.statusEl)return;let t=this.lang==="zh";if(this.error){this.statusEl.setText(`\u274C ${this.error}`),this.statusEl.addClass("pi-agent-text-error");return}if(this.loading){this.statusEl.setText(t?"\u626B\u63CF\u4E2D\u2026":"Scanning\u2026"),this.statusEl.removeClass("pi-agent-text-error"),this.statusEl.addClass("pi-agent-text-muted");return}this.data&&(this.statusEl.setText(`${t?"\u5DF2\u626B\u63CF":"scanned"} ${this.data.sessionCount} ${t?"\u4E2A\u4F1A\u8BDD":"session"+(this.data.sessionCount===1?"":"s")}`),this.statusEl.removeClass("pi-agent-text-error"),this.statusEl.addClass("pi-agent-text-muted"))}renderSummary(){if(!this.summaryEl||(this.summaryEl.empty(),!this.data))return;let t=this.lang==="zh",e=this.data.totals,i=Ie(e.input,e.cacheRead),s=[{label:t?"\u603B Token":"Total tokens",value:N(e.totalTokens),sub:e.totalTokens.toLocaleString()},{label:t?"\u8F93\u5165":"Input",value:N(e.input),sub:e.input.toLocaleString()},{label:t?"\u8F93\u51FA":"Output",value:N(e.output),sub:e.output.toLocaleString()},{label:t?"\u7F13\u5B58 \u03A3":"Cache \u03A3",value:N(e.cacheTotal),sub:i===null?"\u2014":`${t?"\u547D\u4E2D\u7387":"hit"} ${(i*100).toFixed(1)}%`,subColor:Ae(i)},{label:t?"\u8D39\u7528":"Cost",value:Me(e.cost),sub:`${e.messageCount.toLocaleString()} ${t?"\u6761\u6D88\u606F":"msgs"}`}];for(let n of s){let o=this.summaryEl.createDiv("pi-agent-usage-card");o.createDiv({text:n.label,cls:"pi-agent-usage-card-label"}),o.createDiv({text:n.value,cls:"pi-agent-usage-card-value"});let a=o.createDiv({text:n.sub,cls:"pi-agent-usage-card-sub"});n.subColor&&a.setCssProps({color:n.subColor})}}renderTable(){if(!this.tableEl)return;this.tableEl.empty();let t=this.lang==="zh";if(this.error){this.tableEl.createDiv({text:`${t?"\u9519\u8BEF":"Error"}: ${this.error}`,cls:"pi-agent-usage-empty"}).addClass("pi-agent-text-error");return}if(!this.data){this.tableEl.createDiv({text:t?"\u52A0\u8F7D\u4E2D\u2026":"Loading\u2026",cls:"pi-agent-usage-empty"});return}if(this.data.byModel.length===0){this.tableEl.createDiv({text:t?"\u6B64\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u7528\u91CF\u6570\u636E":"No usage data in this range.",cls:"pi-agent-usage-empty"});return}let e=[...this.data.byModel].sort((c,p)=>{let m=c[this.sortKey]===null||c[this.sortKey]===void 0,v=p[this.sortKey]===null||p[this.sortKey]===void 0;if(m&&v)return 0;if(m)return 1;if(v)return-1;let w=c[this.sortKey],T=p[this.sortKey];return this.sortDir==="desc"?T-w:w-T}),i=Math.max(...e.map(c=>c.totalTokens)),s=this.data.totals.totalTokens||0,n=this.tableEl.createEl("table",{cls:"pi-agent-usage-table-el"}),a=n.createEl("thead").createEl("tr"),r=[{key:"model",label:t?"\u6A21\u578B":"Model",align:"left"},{key:"provider",label:t?"\u63D0\u4F9B\u65B9":"Provider",align:"left"},{key:"messageCount",label:t?"\u6D88\u606F":"Msgs",align:"right"},{key:"input",label:t?"\u8F93\u5165":"Input",align:"right"},{key:"output",label:t?"\u8F93\u51FA":"Output",align:"right"},{key:"cacheRead",label:t?"\u7F13\u5B58\u8BFB":"Cache R",align:"right"},{key:"cacheWrite",label:t?"\u7F13\u5B58\u5199":"Cache W",align:"right"},{key:"totalTokens",label:t?"\u603B\u8BA1":"Total",align:"right"},{key:"hitRate",label:t?"\u547D\u4E2D\u7387":"Hit",align:"right"},{key:"cost",label:t?"\u8D39\u7528":"Cost",align:"right"},{key:"share",label:t?"\u5360\u6BD4":"Share",align:"left"}],l=c=>this.sortKey===c?this.sortDir==="desc"?" \u2193":" \u2191":"";for(let c of r){let p=a.createEl("th",{text:c.label+(c.key===this.sortKey?l(c.key):""),attr:{title:c.label}});p.setCssProps({textAlign:c.align}),c.key!=="share"&&(p.addClass("is-sortable"),p.onclick=()=>{this.sortKey===c.key?this.sortDir=this.sortDir==="desc"?"asc":"desc":(this.sortKey=c.key,this.sortDir=c.key==="hitRate"?"asc":"desc"),this.renderTable()})}let d=n.createEl("tbody");for(let c of e){let p=d.createEl("tr"),m=p.createEl("td");m.addClass("pi-agent-text-left"),m.createDiv({cls:"pi-agent-usage-model-name",text:c.model}),m.createDiv({cls:"pi-agent-usage-model-time",text:`${Pe(c.firstUsed?new Date(c.firstUsed).toISOString():null)} \u2192 ${Pe(c.lastUsed?new Date(c.lastUsed).toISOString():null)}`});let v=p.createEl("td",{text:c.provider});v.addClass("pi-agent-text-left"),v.addClass("pi-agent-text-muted");let w=[[c.messageCount.toLocaleString(),"right"],[N(c.input),"right"],[N(c.output),"right"],[N(c.cacheRead),"right"],[N(c.cacheWrite),"right"],[N(c.totalTokens),"right"],[qe(c.hitRate),"right",Ae(c.hitRate)],[Me(c.cost),"right"]];for(let[y,C,S]of w){let P=p.createEl("td",{text:y});P.setCssProps({textAlign:C}),P.addClass("pi-agent-tabular-nums"),S&&P.setCssProps({color:S})}let T=p.createEl("td");T.addClass("pi-agent-text-left"),T.addClass("pi-agent-share-cell");let k=s>0?c.totalTokens/s*100:0,M=i>0?c.totalTokens/i*100:0;T.createDiv({cls:"pi-agent-usage-bar"}).createDiv({cls:"pi-agent-usage-bar-fill"}).setCssProps({width:`${M}%`}),T.createSpan({text:`${k.toFixed(1)}%`,cls:"pi-agent-usage-pct"})}}};var b=require("obsidian");var E=z(require("fs")),$=z(require("path")),K=z(require("os")),ve=require("child_process"),Le="app_EMoamEEZ73f0CkXaXp7hrann",tt="https://auth.openai.com/api/accounts/deviceauth/usercode",it="https://auth.openai.com/api/accounts/deviceauth/token",st="https://auth.openai.com/oauth/token",nt="https://auth.openai.com/codex/device",ot="https://auth.openai.com/deviceauth/callback",fe=900,W=[{id:"anthropic",name:"Anthropic (Claude)",envVar:"ANTHROPIC_API_KEY",authJsonKey:"anthropic"},{id:"openai-codex",name:"OpenAI (ChatGPT \u8BA2\u9605)",envVar:"",oauth:!0,authJsonKey:"openai-codex"},{id:"openai",name:"OpenAI (API Key)",envVar:"OPENAI_API_KEY",authJsonKey:"openai"},{id:"google",name:"Google (Gemini)",envVar:"GEMINI_API_KEY",authJsonKey:"google"},{id:"groq",name:"Groq",envVar:"GROQ_API_KEY",authJsonKey:"groq"},{id:"xai",name:"xAI (Grok)",envVar:"XAI_API_KEY",authJsonKey:"xai"},{id:"openrouter",name:"OpenRouter",envVar:"OPENROUTER_API_KEY",authJsonKey:"openrouter"},{id:"mistral",name:"Mistral",envVar:"MISTRAL_API_KEY",authJsonKey:"mistral"},{id:"together",name:"Together AI",envVar:"TOGETHER_API_KEY",authJsonKey:"together"},{id:"fireworks",name:"Fireworks",envVar:"FIREWORKS_API_KEY",authJsonKey:"fireworks"},{id:"nvidia",name:"NVIDIA NIM",envVar:"NVIDIA_API_KEY",authJsonKey:"nvidia"},{id:"deepseek",name:"DeepSeek",envVar:"DEEPSEEK_API_KEY",authJsonKey:"deepseek"},{id:"zai",name:"\u667A\u8C31 Z.AI (GLM)",envVar:"ZAI_API_KEY",authJsonKey:"zai"},{id:"zai-coding-cn",name:"\u667A\u8C31 Coding Plan (\u56FD\u5185)",envVar:"ZAI_CODING_CN_API_KEY",authJsonKey:"zai-coding-cn"},{id:"minimax",name:"MiniMax (\u56FD\u9645)",envVar:"MINIMAX_API_KEY",authJsonKey:"minimax"},{id:"minimax-cn",name:"MiniMax (\u56FD\u5185)",envVar:"MINIMAX_CN_API_KEY",authJsonKey:"minimax-cn"},{id:"moonshotai",name:"\u6708\u4E4B\u6697\u9762 Kimi (\u56FD\u9645)",envVar:"MOONSHOT_API_KEY",authJsonKey:"moonshotai"},{id:"moonshotai-cn",name:"\u6708\u4E4B\u6697\u9762 Kimi (\u56FD\u5185)",envVar:"MOONSHOT_API_KEY",authJsonKey:"moonshotai-cn"},{id:"xiaomi",name:"\u5C0F\u7C73 MiMo",envVar:"XIAOMI_API_KEY",authJsonKey:"xiaomi"},{id:"kimi-coding",name:"Kimi For Coding",envVar:"KIMI_API_KEY",authJsonKey:"kimi-coding"}],Re={piPath:"pi",provider:"",modelId:"",thinkingLevel:"",apiKey:"",autoScroll:!0,showThinking:!0,smartReviewEnabled:!1,smartReviewMaxContinues:3,maxHistoryDisplay:100,sessionTabs:[],activeSessionFile:"",systemPrompt:"",snippets:[],language:"zh",maxTabs:3,streamingRenderMode:"pretty",sessionTitles:{}},ee=class extends b.PluginSettingTab{plugin;temporaryProviders=[];justAddedBuiltinId=null;constructor(t,e){super(t,e),this.plugin=e}getAuthJsonPath(){let t=K.homedir();return $.join(t,".pi","agent","auth.json")}getModelsJsonPath(){let t=K.homedir();return $.join(t,".pi","agent","models.json")}readModelsJson(){let t=this.getModelsJsonPath();if(!E.existsSync(t))return{};try{let e=E.readFileSync(t,"utf-8"),i=JSON.parse(e)||{};return i.providers&&typeof i.providers=="object"?i.providers:{}}catch(e){return console.error("\u8BFB\u53D6 models.json \u5931\u8D25:",e),{}}}writeModelsJson(t){let e=this.getModelsJsonPath(),i={};if(E.existsSync(e))try{let s=E.readFileSync(e,"utf-8");i=JSON.parse(s)||{}}catch(s){console.error("\u89E3\u6790\u5DF2\u6709 models.json \u5931\u8D25\uFF0C\u5C06\u91CD\u7F6E\u914D\u7F6E:",s)}i.providers=t;try{let s=$.dirname(e);E.existsSync(s)||E.mkdirSync(s,{recursive:!0}),E.writeFileSync(e,JSON.stringify(i,null,2),"utf-8")}catch(s){console.error("\u5199\u5165 models.json \u5931\u8D25:",s)}}isBuiltinProvider(t){return W.some(e=>e.id===t)}getBuiltinProvider(t){return W.find(e=>e.id===t)}readApiKey(t){let e=this.getAuthJsonPath();if(!E.existsSync(e))return"";try{let i=E.readFileSync(e,"utf-8"),s=JSON.parse(i);if(s&&s[t]){let n=s[t];return n.type==="oauth"?"[OAuth \u5DF2\u6388\u6743 / OAuth Authorized]":n.key||""}}catch(i){console.error("\u8BFB\u53D6 auth.json \u5931\u8D25:",i)}return""}writeApiKey(t,e){if(e==="[OAuth \u5DF2\u6388\u6743 / OAuth Authorized]")return;let i=this.getAuthJsonPath(),s={};if(E.existsSync(i))try{let o=E.readFileSync(i,"utf-8");s=JSON.parse(o)||{}}catch(o){console.error("\u89E3\u6790\u5DF2\u6709 auth.json \u5931\u8D25\uFF0C\u5C06\u91CD\u7F6E\u914D\u7F6E:",o)}let n=e.trim();n?s[t]={type:"api_key",key:n}:delete s[t];try{let o=$.dirname(i);E.existsSync(o)||E.mkdirSync(o,{recursive:!0}),E.writeFileSync(i,JSON.stringify(s,null,2),"utf-8")}catch(o){console.error("\u5199\u5165 auth.json \u5931\u8D25:",o)}}getGlobalSkillsDir(){return $.join(K.homedir(),".pi","agent","skills")}getProjectSkillsDirs(){let e=this.app.vault.adapter.basePath||"";return e?[$.join(e,".pi","agent","skills"),$.join(e,"skills"),$.join(e,".agents","skills")]:[]}parseSkillFile(t){if(!E.existsSync(t))return null;try{let i=E.readFileSync(t,"utf-8").match(/^---\r?\n([\s\S]*?)\r?\n---/),s=$.basename($.dirname(t)),n="",o=!1;if(i){let r=i[1].split(`
`);for(let l of r){let d=l.split(":");if(d.length>=2){let c=d[0].trim(),p=d.slice(1).join(":").trim().replace(/^"|"$/g,"").replace(/^'|'$/g,"");c==="name"?s=p:c==="description"?n=p:c==="disable-model-invocation"&&(o=p==="true")}}}return{name:s,description:n,disabled:o}}catch(e){return console.error("\u89E3\u6790 skill \u6587\u4EF6\u5931\u8D25:",t,e),null}}toggleSkill(t,e){if(E.existsSync(t))try{let i=E.readFileSync(t,"utf-8"),s="disable-model-invocation",n=/^---\r?\n([\s\S]*?)\r?\n---/.test(i),o=i;if(n){let a=new RegExp(`^${s}\\s*:.*\\r?\\n`,"m").test(i);e&&!a?o=i.replace(/^---\r?\n/,`---
${s}: true
`):!e&&a&&(o=i.replace(new RegExp(`^${s}\\s*:.*\\r?\\n`,"m"),""))}else e&&(o=`---
${s}: true
---
${i}`);E.writeFileSync(t,o,"utf-8")}catch(i){console.error("\u66F4\u65B0 skill \u542F\u7528\u72B6\u6001\u5931\u8D25:",t,i)}}scanSkills(){let t=[],e=this.getGlobalSkillsDir();if(E.existsSync(e))try{let s=E.readdirSync(e);for(let n of s){let o=$.join(e,n);if(E.statSync(o).isDirectory())for(let a of["SKILL.md","skill.md"]){let r=$.join(o,a),l=this.parseSkillFile(r);if(l){t.push({...l,filePath:r,scope:"global"});break}}}}catch(s){console.error("\u626B\u63CF\u5168\u5C40 skills \u76EE\u5F55\u5931\u8D25:",s)}let i=this.getProjectSkillsDirs();for(let s of i)if(E.existsSync(s))try{let n=E.readdirSync(s);for(let o of n){let a=$.join(s,o);if(E.statSync(a).isDirectory())for(let r of["SKILL.md","skill.md"]){let l=$.join(a,r),d=this.parseSkillFile(l);if(d){t.some(c=>c.filePath===l)||t.push({...d,filePath:l,scope:"project"});break}}}}catch(n){console.error("\u626B\u63CF\u9879\u76EE skills \u76EE\u5F55\u5931\u8D25:",s,n)}return t}installSkill(t,e,i){let n=this.app.vault.adapter.basePath||"",o=e==="global",a=`npx skills add ${t.trim()} -y --agent pi${o?" -g":""}`,r=K.platform()==="win32"?`chcp 65001 >nul && ${a}`:a;(0,ve.exec)(r,{cwd:n||void 0},(l,d,c)=>{l?i(c.trim()||l.message||"\u5B89\u88C5\u5931\u8D25",d+c):i(null,d)})}async searchSkills(t){let i=`https://skills.sh/api/search?q=${encodeURIComponent(t)}&limit=30`;try{let s=await(0,b.requestUrl)(i);if(s.status<200||s.status>=300)throw new Error(`HTTP ${s.status}`);return(s.json.skills??[]).map(o=>{let a=o.name?.trim(),r=o.source?.trim(),l=o.id?.trim();return{package:`${r||l}@${a}`,installs:o.installs||0,url:l?`https://skills.sh/${l}`:""}})}catch(s){return console.warn("skills.sh search failed, falling back to local search:",s),new Promise(n=>{let o=process.platform==="win32",a=`npx skills find ${t.trim()}`,r=o?`chcp 65001 >nul && ${a}`:a;(0,ve.exec)(r,{timeout:15e3},(l,d,c)=>{let p=d+c,m="\x1B",v=p.replace(new RegExp(`${m}\\[[0-9;]*m`,"g"),""),w=[],T=v.split(`
`);for(let k=0;k<T.length;k++){let x=T[k].trim().match(/^([\w.-]+\/[\w.@:-]+)\s+([\d.,]+[KMB]?\s+installs)$/);if(x){let g=T[k+1]?.trim().replace(/^└\s*/,"");w.push({package:x[1],installs:x[2],url:g?.startsWith("https://")?g:""})}}n(w)})})}}display(){let{containerEl:t}=this;t.empty();let e=this.plugin.settings.language==="zh";new b.Setting(t).setName(e?"Pimate \u8BBE\u7F6E":"Pimate Settings").setHeading(),new b.Setting(t).setName(e?"\u8BED\u8A00 (Language)":"Language (\u8BED\u8A00)").setDesc(e?"\u9009\u62E9\u8BBE\u7F6E\u754C\u9762\u7684\u663E\u793A\u8BED\u8A00\u3002":"Choose the display language for the settings interface.").addDropdown(g=>g.addOption("zh","\u7B80\u4F53\u4E2D\u6587 (Chinese)").addOption("en","English").setValue(this.plugin.settings.language).onChange(async y=>{this.plugin.settings.language=y,await this.plugin.saveSettings(),this.display()})),new b.Setting(t).setName(e?"Pi \u53EF\u6267\u884C\u8DEF\u5F84":"Pi executable path").setDesc(e?"Pi \u547D\u4EE4\u7684\u8DEF\u5F84\u3002\u9ED8\u8BA4\u4F7F\u7528 'pi'\uFF0C\u4F1A\u4ECE\u7CFB\u7EDF\u7684 PATH \u73AF\u5883\u53D8\u91CF\u4E2D\u67E5\u627E\u3002":"Path to the pi command. Default is 'pi', which will be searched from the system PATH.").addText(g=>g.setPlaceholder("pi").setValue(this.plugin.settings.piPath).onChange(async y=>{this.plugin.settings.piPath=y||"pi",await this.plugin.saveSettings()})),new b.Setting(t).setName(e?"\u9ED8\u8BA4\u6A21\u578B\u914D\u7F6E (Default Model Configuration)":"Default Model Configuration").setHeading();let i={anthropic:{model:"claude-3-5-sonnet-latest",desc:e?"\u63A8\u8350: claude-3-5-sonnet-latest, claude-3-5-haiku-latest":"Recommended: claude-3-5-sonnet-latest, claude-3-5-haiku-latest",placeholder:"claude-3-5-sonnet-latest"},"openai-codex":{model:"gpt-4o",desc:e?"\u63A8\u8350: gpt-4o, gpt-4o-mini, o1, o3-mini":"Recommended: gpt-4o, gpt-4o-mini, o1, o3-mini",placeholder:"gpt-4o"},deepseek:{model:"deepseek-chat",desc:e?"\u63A8\u8350: deepseek-chat, deepseek-reasoner":"Recommended: deepseek-chat, deepseek-reasoner",placeholder:"deepseek-chat"},minimax:{model:"MiniMax-M2.7",desc:e?"\u5185\u7F6E MiniMax-M2.7 / M2.7-highspeed\u3002\u5982\u9700 M3\uFF0C\u5728 ~/.pi/agent/models.json \u6DFB\u52A0\u3002":"Built-in MiniMax-M2.7 / M2.7-highspeed. Add MiniMax-M3 via ~/.pi/agent/models.json.",placeholder:"MiniMax-M2.7"},"minimax-cn":{model:"MiniMax-M2.7",desc:e?"\u5185\u7F6E MiniMax-M2.7 / M2.7-highspeed\u3002\u5DF2\u901A\u8FC7 models.json \u6DFB\u52A0 MiniMax-M3\uFF08100 \u4E07\u4E0A\u4E0B\u6587\uFF0C\u652F\u6301\u56FE\u50CF\uFF09\u3002":"Built-in MiniMax-M2.7 / M2.7-highspeed. MiniMax-M3 (1M context, image support) added via models.json.",placeholder:"MiniMax-M2.7"},siliconflow:{model:"deepseek-ai/DeepSeek-V3",desc:e?"\u63A8\u8350: deepseek-ai/DeepSeek-V3, deepseek-ai/DeepSeek-R1":"Recommended: deepseek-ai/DeepSeek-V3, deepseek-ai/DeepSeek-R1",placeholder:"deepseek-ai/DeepSeek-V3"},google:{model:"gemini-2.5-flash",desc:e?"\u63A8\u8350: gemini-2.5-flash, gemini-2.5-pro":"Recommended: gemini-2.5-flash, gemini-2.5-pro",placeholder:"gemini-2.5-flash"},zhipu:{model:"glm-5.2",desc:e?"\u63A8\u8350: glm-5.2\uFF08Z.ai \u65D7\u8230, 1M \u4E0A\u4E0B\u6587\uFF09\u3002GLM Coding Plan \u5957\u9910\u987B\u8D70\u4E13\u5C5E\u7AEF\u70B9 https://open.bigmodel.cn/api/coding/paas/v4 \u2014\u2014 \u901A\u7528\u7AEF\u70B9 /api/paas/v4 \u4E0D\u62B5\u6263\u5957\u9910\u3001\u6309\u91CF\u6263\u8D39\uFF08\u4F1A\u62A5 429 \u4F59\u989D\u4E0D\u8DB3\uFF09\u3002":"Recommended: glm-5.2 (Z.ai flagship, 1M context). GLM Coding Plan MUST use https://open.bigmodel.cn/api/coding/paas/v4 \u2014 the generic /api/paas/v4 bypasses the plan and bills per-token (causes 429 balance errors).",placeholder:"glm-5.2"}};new b.Setting(t).setName(e?"\u9ED8\u8BA4\u670D\u52A1\u5546 (Default Provider)":"Default Provider").setDesc(e?"\u9009\u62E9\u804A\u5929\u65F6\u9ED8\u8BA4\u542F\u7528\u7684\u6A21\u578B\u670D\u52A1\u5546\u3002":"Choose the default model provider for chat sessions.").addDropdown(g=>{let y=this.readModelsJson(),C=[];for(let S of W)C.push({id:S.id,name:S.name});for(let S of Object.keys(y))if(!this.isBuiltinProvider(S)){let P=y[S],L=Array.isArray(P?.models)?P.models.length:0;C.push({id:S,name:`${S} (\u81EA\u5B9A\u4E49/${L}\u6A21\u578B)`})}for(let S of C){let L=this.readApiKey(S.id)?`${S.name} [\u5DF2\u914D\u7F6E / Active]`:S.name;g.addOption(S.id,L)}g.setValue(this.plugin.settings.provider||"anthropic").onChange(async S=>{this.plugin.settings.provider=S;let P=i[S];P&&(this.plugin.settings.modelId=P.model),await this.plugin.saveSettings(),this.display();let L=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let f of L){let D=f.view;if(D)if(typeof D.updateActiveTabModel=="function")try{await D.updateActiveTabModel(S,this.plugin.settings.modelId)}catch(O){console.warn("[pimate] updateActiveTabModel failed in settings:",O)}else D.client&&typeof D.client.setModel=="function"&&(await D.client.setModel(S,this.plugin.settings.modelId),typeof D.updateModelDisplay=="function"&&D.updateModelDisplay(S,this.plugin.settings.modelId))}})});let s=this.plugin.settings.provider||"anthropic",n=i[s]||{model:"",desc:"",placeholder:""};new b.Setting(t).setName(e?"\u9ED8\u8BA4\u6A21\u578B ID (Default Model ID)":"Default Model ID").setDesc(n.desc||(e?"\u5F53\u524D\u670D\u52A1\u5546\u7684\u6A21\u578B ID":"Model ID for current provider")).addText(g=>g.setPlaceholder(n.placeholder).setValue(this.plugin.settings.modelId||"").onChange(async y=>{let C=y.trim();this.plugin.settings.modelId=C,await this.plugin.saveSettings();let S=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let P of S){let L=P.view;if(L)if(typeof L.updateActiveTabModel=="function")try{await L.updateActiveTabModel(this.plugin.settings.provider,C)}catch(f){console.warn("[pimate] updateActiveTabModel failed in settings:",f)}else L.client&&typeof L.client.setModel=="function"&&(await L.client.setModel(this.plugin.settings.provider,C),typeof L.updateModelDisplay=="function"&&L.updateModelDisplay(this.plugin.settings.provider,C))}})),new b.Setting(t).setName(e?"\u9ED8\u8BA4\u601D\u8003\u5F3A\u5EA6 (Default Effort Level)":"Default Effort Level").setDesc(e?"\u4F5C\u4E3A\u65B0 Tab \u7684\u9ED8\u8BA4\u504F\u597D\uFF1B\u5F53\u524D\u6A21\u578B\u5B9E\u9645\u652F\u6301\u54EA\u4E9B\u6863\u4F4D\uFF0C\u4EE5\u804A\u5929\u9875 Effort \u5F39\u7A97\u548C Pi \u751F\u6548\u7ED3\u679C\u4E3A\u51C6\u3002":"Default preference for new tabs. The chat Effort popup and Pi's effective state determine which levels the current model actually supports.").addDropdown(g=>g.addOption("",e?"\u9ED8\u8BA4 (Pi Default)":"Pi Default").addOption("off",e?"\u5173\u95ED (Off)":"Off").addOption("minimal",e?"\u6700\u4F4E (Minimal)":"Minimal").addOption("low",e?"\u8F83\u4F4E (Low)":"Low").addOption("medium",e?"\u4E2D\u7B49 (Medium)":"Medium").addOption("high",e?"\u8F83\u9AD8 (High)":"High").addOption("xhigh",e?"\u6781\u9AD8 (X-High)":"X-High").addOption("max",e?"\u6781\u9650 (Max)":"Max").setValue(this.plugin.settings.thinkingLevel||"").onChange(async y=>{this.plugin.settings.thinkingLevel=y,await this.plugin.saveSettings();let C=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let S of C){let P=S.view;if(P)if(typeof P.updateActiveTabThinkingLevel=="function")try{await P.updateActiveTabThinkingLevel(y)}catch(L){console.warn("[pimate] updateActiveTabThinkingLevel failed in settings:",L)}else P.client&&typeof P.client.setThinkingLevel=="function"&&(await P.client.setThinkingLevel(y),P.footerEffortCurrent&&P.footerEffortCurrent.setText(P.getThinkingLevelLabel(y)))}})),new b.Setting(t).setName(e?"\u5927\u6A21\u578B\u51ED\u8BC1\u914D\u7F6E (LLM Credentials)":"LLM Credentials").setHeading();let o=this.getAuthJsonPath(),a={};if(E.existsSync(o))try{let g=E.readFileSync(o,"utf-8");a=JSON.parse(g)||{}}catch(g){console.error("\u8BFB\u53D6 auth.json \u5931\u8D25:",g)}let r=this.readModelsJson(),l=Object.keys(a).filter(g=>{let y=a[g];return y&&(y.type==="oauth"||y.key&&y.key.trim())});new b.Setting(t).setName(e?"\u5185\u7F6E Provider\uFF08\u914D key \u5373\u7528\uFF09":"Built-in Providers (key only)").setDesc(e?"\u8FD9\u4E9B\u670D\u52A1\u5546 Pi \u539F\u751F\u652F\u6301\uFF0C\u586B\u5165 API Key \u6216\u5B8C\u6210 OAuth \u5373\u53EF\u4F7F\u7528\u3002\u672A\u5217\u51FA\u7684\u5185\u7F6E provider \u4E5F\u53EF\u901A\u8FC7\u73AF\u5883\u53D8\u91CF\u914D\u7F6E\u3002":"Pi natively supports these providers \u2014 just add an API Key or complete OAuth. Other built-in providers can also be used via environment variables.").setHeading();let d=Array.from(new Set([...W.map(g=>g.id).filter(g=>l.includes(g)),...this.temporaryProviders.filter(g=>this.isBuiltinProvider(g))]));if(d.length===0)t.createEl("p",{text:e?"\u5C1A\u672A\u914D\u7F6E\u4EFB\u4F55\u5185\u7F6E provider\u3002\u5728\u4E0B\u65B9\u9009\u62E9\u4E00\u4E2A\u6DFB\u52A0\u3002":"No built-in provider configured yet. Add one below.",cls:"setting-item-description"});else{for(let g of W)d.includes(g.id)&&this.renderBuiltinCredentialRow(t,g,a,o,e);for(let g of d)this.isBuiltinProvider(g)}let c=W.filter(g=>!d.includes(g.id));if(c.length>0){let g=c[0].id;new b.Setting(t).setName(e?"+ \u6DFB\u52A0\u5185\u7F6E Provider":"+ Add Built-in Provider").setDesc(e?"\u9009\u62E9\u4E00\u4E2A\u672A\u914D\u7F6E\u7684\u5185\u7F6E\u670D\u52A1\u5546\u5E76\u70B9\u51FB\u6DFB\u52A0\u3002":"Select an unconfigured built-in provider to add.").addDropdown(y=>{for(let C of c)y.addOption(C.id,C.name);y.setValue(g).onChange(C=>{g=C})}).addButton(y=>{y.setButtonText(e?"\u6DFB\u52A0":"Add").setCta().onClick(()=>{this.temporaryProviders.push(g),this.justAddedBuiltinId=g,this.display(),window.setTimeout(()=>{let C=t.querySelector("[data-just-added='true'] input[type='password']");if(C)C.focus();else{let S=t.querySelector("[data-just-added='true'] input");S&&S.focus()}this.justAddedBuiltinId=null},50)})})}new b.Setting(t).setName(e?"\u81EA\u5B9A\u4E49 Provider\uFF08\u6765\u81EA models.json\uFF09":"Custom Providers (models.json)").setDesc(e?"\u8FD9\u4E9B\u670D\u52A1\u5546\u5728 ~/.pi/agent/models.json \u4E2D\u5B9A\u4E49\uFF08\u5982\u7845\u57FA\u6D41\u52A8\u3001\u706B\u5C71\u5F15\u64CE\u7B49 Pi \u4E0D\u5185\u7F6E\u7684\u670D\u52A1\uFF09\u3002\u70B9\u51FB\u201C\u6DFB\u52A0\u201D\u53EF\u4F7F\u7528\u5411\u5BFC\u751F\u6210\u914D\u7F6E\u3002":"Defined in ~/.pi/agent/models.json (e.g. SiliconFlow, Volcengine \u2014 providers Pi doesn't ship built-in). Use the wizard to add one.").setHeading();let p=Object.keys(r).filter(g=>!this.isBuiltinProvider(g)),m=l.filter(g=>!this.isBuiltinProvider(g)&&!p.includes(g)),v=Array.from(new Set([...p,...m,...this.temporaryProviders.filter(g=>!this.isBuiltinProvider(g))]));if(v.length===0)t.createEl("p",{text:e?"\u6682\u65E0\u81EA\u5B9A\u4E49 provider\u3002\u70B9\u51FB\u4E0B\u65B9\u6309\u94AE\u4F7F\u7528\u5411\u5BFC\u6DFB\u52A0\u3002":"No custom providers yet. Use the button below to add one via wizard.",cls:"setting-item-description"});else for(let g of v)this.renderCustomProviderRow(t,g,r,a,e);new b.Setting(t).setName(e?"+ \u6DFB\u52A0\u81EA\u5B9A\u4E49 Provider\uFF08\u5411\u5BFC\uFF09":"+ Add Custom Provider (Wizard)").setDesc(e?"\u6253\u5F00\u5411\u5BFC\u586B\u8868\u751F\u6210 models.json \u914D\u7F6E\uFF0C\u9002\u914D\u7845\u57FA\u6D41\u52A8/\u706B\u5C71\u5F15\u64CE/OpenAI \u517C\u5BB9\u7AEF\u70B9\u7B49\u3002":"Open a wizard to generate models.json config for SiliconFlow/Volcengine/OpenAI-compatible endpoints.").addButton(g=>{g.setButtonText(e?"\u6253\u5F00\u5411\u5BFC":"Open Wizard").setCta().onClick(()=>{new we(this.app,e,async y=>{this.applyCustomProviderConfig(y,e)}).open()})}),new b.Setting(t).setName(e?"\u63D0\u793A\u8BCD\u9ED8\u8BA4\u8BBE\u7F6E":"Prompt Defaults").setHeading(),new b.Setting(t).setName(e?"\u7CFB\u7EDF\u63D0\u793A\u8BCD":"System prompt").setDesc(e?"\u6BCF\u6B21\u666E\u901A\u5BF9\u8BDD\u524D\u81EA\u52A8\u9644\u52A0\u7684\u56FA\u5B9A\u8981\u6C42\uFF0C\u4F8B\u5982\u4E2D\u6587\u5199\u4F5C\u98CE\u683C\u3001\u8BED\u6C14\u3001\u5DE5\u4F5C\u6D41\u89C4\u5219\u3002":"Optional instruction prepended to each normal Pimate prompt.").addTextArea(g=>{g.setPlaceholder(e?"\u4F8B\u5982\uFF1A\u4F60\u662F\u6211\u7684 Obsidian \u5199\u4F5C\u52A9\u624B\uFF0C\u8F93\u51FA\u4E2D\u6587\uFF0C\u98CE\u683C\u514B\u5236\u3001\u76F4\u63A5\uFF0C\u4E0D\u8981\u8425\u9500\u611F\u3002":"e.g. You are my helpful Obsidian assistant. Keep answers direct and clear.").setValue(this.plugin.settings.systemPrompt||"").onChange(async y=>{this.plugin.settings.systemPrompt=y,await this.plugin.saveSettings()}),g.inputEl.rows=5,g.inputEl.addClass("pi-agent-textarea-full-width")}),new b.Setting(t).setName(e?"\u5E38\u7528\u6307\u4EE4\u7247\u6BB5":"Snippets").setDesc(e?"\u4E00\u884C\u4E00\u4E2A\u3002\u652F\u6301 \u6807\u9898::\u63D0\u793A\u8BCD \u6216 \u5206\u7EC4/\u6807\u9898::\u63D0\u793A\u8BCD\uFF0C\u4EE5\u53CA\u53D8\u91CF {{selection}}, {{current_file}}, {{current_title}}, {{date}}\u3002":"One per line with optional names, groups, and variables. Supports Title::Prompt or Group/Title::Prompt.").addTextArea(g=>{g.setPlaceholder(e?`\u6539\u5199/\u514B\u5236::\u8BF7\u628A {{selection}} \u6539\u5F97\u66F4\u514B\u5236\uFF0C\u4E0D\u8981\u8425\u9500\u611F
\u603B\u7ED3/\u4E09\u70B9::\u8BF7\u603B\u7ED3\u6210 3 \u4E2A\u8981\u70B9
\u538B\u7F29\u5230 300 \u5B57`:`Rewrite/Concise::Please rewrite {{selection}} to be more concise
Summarize/Keypoints::Summarize into 3 key points`).setValue((this.plugin.settings.snippets||[]).join(`
`)).onChange(async y=>{this.plugin.settings.snippets=y.split(/\r?\n/).map(C=>C.trim()).filter(Boolean),await this.plugin.saveSettings()}),g.inputEl.rows=5,g.inputEl.addClass("pi-agent-textarea-full-width")}),new b.Setting(t).setName(e?"\u663E\u793A\u9009\u9879":"Display Options").setHeading(),new b.Setting(t).setName(e?"\u81EA\u52A8\u6EDA\u52A8":"Auto-scroll").setDesc(e?"\u6709\u65B0\u5185\u5BB9\u65F6\u81EA\u52A8\u6EDA\u52A8\u5230\u5E95\u90E8\u3002":"Automatically scroll to bottom when new content arrives.").addToggle(g=>g.setValue(this.plugin.settings.autoScroll).onChange(async y=>{this.plugin.settings.autoScroll=y,await this.plugin.saveSettings()})),new b.Setting(t).setName(e?"\u6D41\u5F0F\u6E32\u67D3\u6A21\u5F0F":"Streaming render mode").setDesc(e?"Auto \u63A8\u8350\uFF1A\u77ED\u8F93\u51FA\u4FDD\u6301\u539F\u6765\u7684 Markdown \u7F8E\u89C2\u6D41\u5F0F\uFF0C\u957F\u8F93\u51FA\u81EA\u52A8\u5207\u6362\u4E3A\u6781\u901F\u6A21\u5F0F\u4EE5\u51CF\u5C11\u5361\u987F\u3002":"Auto recommended: pretty Markdown streaming for short output, fast plain streaming for long output.").addDropdown(g=>g.addOption("auto",e?"\u81EA\u52A8 Auto\uFF08\u63A8\u8350\uFF09":"Auto (recommended)").addOption("pretty",e?"\u7F8E\u89C2 Pretty\uFF08\u539F\u7248\u4F53\u9A8C\uFF09":"Pretty (original feel)").addOption("fast",e?"\u6781\u901F Fast\uFF08\u957F\u8F93\u51FA\u6700\u5FEB\uFF09":"Fast (best for long output)").setValue(this.plugin.settings.streamingRenderMode||"auto").onChange(async y=>{this.plugin.settings.streamingRenderMode=y,await this.plugin.saveSettings()})),new b.Setting(t).setName(e?"\u663E\u793A\u601D\u8003\u8FC7\u7A0B":"Show thinking").setDesc(e?"\u5728\u804A\u5929\u4E2D\u663E\u793A\u6A21\u578B thinking/reasoning \u5757\u3002":"Display model thinking/reasoning blocks in the chat.").addToggle(g=>g.setValue(this.plugin.settings.showThinking!==!1).onChange(async y=>{this.plugin.settings.showThinking=y,await this.plugin.saveSettings();for(let C of this.app.workspace.getLeavesOfType(U))C.view?.refreshThinkingVisibility?.()})),new b.Setting(t).setName(e?"\u667A\u80FD\u5BA1\u6838":"Smart review").setDesc(e?"\u5F00\u542F\u540E\uFF0CAgent \u4F1A\u5728\u957F\u4EFB\u52A1\u4E2D\u81EA\u68C0\u7ED3\u679C\u5E76\u5C1D\u8BD5\u4F18\u5316\u540E\u518D\u8F93\u51FA\u3002":"When enabled, the agent self-checks long tasks and improves the result before replying.").addToggle(g=>g.setValue(this.plugin.settings.smartReviewEnabled===!0).onChange(async y=>{this.plugin.settings.smartReviewEnabled=y,await this.plugin.saveSettings();for(let C of this.app.workspace.getLeavesOfType(U))C.view?.refreshSmartReviewToggle?.()})),new b.Setting(t).setName(e?"\u667A\u80FD\u5BA1\u6838\u6700\u5927\u81EA\u52A8\u7EE7\u7EED\u6B21\u6570":"Smart review max auto-continue").setDesc(e?"\u5F00\u5173\u5F00\u542F\u65F6\uFF0CAgent \u7ED3\u675F\u540E\u63D2\u4EF6\u6700\u591A\u81EA\u52A8\u7EE7\u7EED\u7684\u6B21\u6570\u3002\u8303\u56F4 1-10\u3002":"When smart review is on, max auto-continue turns after the agent ends. Range 1-10.").addText(g=>g.setPlaceholder("3").setValue(String(this.plugin.settings.smartReviewMaxContinues??3)).onChange(async y=>{let C=parseInt(y,10);!isNaN(C)&&C>=1&&C<=10&&(this.plugin.settings.smartReviewMaxContinues=C,await this.plugin.saveSettings())})),new b.Setting(t).setName(e?"\u6700\u5927\u5386\u53F2\u663E\u793A\u6570\u91CF":"Max history display").setDesc(e?"\u804A\u5929\u533A\u6700\u591A\u663E\u793A\u591A\u5C11\u6761\u6D88\u606F\uFF0C\u65E7\u6D88\u606F\u4F1A\u9690\u85CF\u3002":"Maximum number of messages to show in chat; older messages are hidden.").addSlider(g=>g.setLimits(10,500,10).setValue(this.plugin.settings.maxHistoryDisplay).setDynamicTooltip().onChange(async y=>{this.plugin.settings.maxHistoryDisplay=y,await this.plugin.saveSettings()})),new b.Setting(t).setName(e?"\u6700\u5927\u4F1A\u8BDD\u5361\u6570\u91CF":"Max session tabs").setDesc(e?"\u56FA\u5B9A\u5C55\u793A\u5728\u9876\u90E8\u7684\u4F1A\u8BDD\u5361 (Tab 1, 2, 3) \u6570\u91CF\u3002\u4FEE\u6539\u540E\u7ACB\u5373\u91CD\u6784\u9876\u680F\u3002":"The number of static tabs (1, 2, 3, etc.) displayed in the header.").addText(g=>g.setPlaceholder("3").setValue(String(this.plugin.settings.maxTabs??3)).onChange(async y=>{let C=parseInt(y,10);if(!isNaN(C)&&C>0&&C<=20){this.plugin.settings.maxTabs=C,await this.plugin.saveSettings();let S=this.app.workspace.getLeavesOfType("pimate-chat-view");if(S.length>0){let P=S[0].view;P&&typeof P.setupStaticTabs=="function"&&await P.setupStaticTabs()}}})),new b.Setting(t).setName(e?"\u6280\u80FD\u7BA1\u7406 (Skills Management)":"Skills Management").setHeading();let w=this.scanSkills(),T=w.filter(g=>g.scope==="project"),k=w.filter(g=>g.scope==="global");if(w.length===0)t.createEl("p",{text:e?"\u5F53\u524D\u672A\u68C0\u6D4B\u5230\u4EFB\u4F55\u6280\u80FD\u6269\u5C55 (\u5982 SKILL.md)\u3002\u53EF\u4EE5\u4F7F\u7528\u4E0B\u65B9\u8F93\u5165\u6846\u5B89\u88C5\u65B0\u6280\u80FD\u3002":"No skills detected. You can install new skills below.",cls:"setting-item-description"});else{if(T.length>0){new b.Setting(t).setName(e?"\u9879\u76EE\u672C\u5730\u6280\u80FD (Project Skills)":"Project Skills").setHeading();for(let g of T)this.createSkillSetting(t,g,e)}if(k.length>0){new b.Setting(t).setName(e?"\u5168\u5C40\u5B89\u88C5\u6280\u80FD (Global Skills)":"Global Skills").setHeading();for(let g of k)this.createSkillSetting(t,g,e)}}let M="",x="project";new b.Setting(t).setName(e?"+ \u5B89\u88C5\u65B0\u6280\u80FD":"+ Install New Skill").setDesc(e?"\u8F93\u5165 skills.sh \u6280\u80FD\u5305\u540D\uFF0C\u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E\u5E76\u70B9\u51FB\u5B89\u88C5\u3002":"Enter package name from skills.sh, select scope and click install.").addText(g=>{g.setPlaceholder("e.g. brave-search").onChange(y=>{M=y.trim()})}).addDropdown(g=>{g.addOption("project",e?"\u9879\u76EE\u672C\u5730 (Project)":"Project").addOption("global",e?"\u5168\u5C40 (Global)":"Global").setValue(x).onChange(y=>{x=y})}).addButton(g=>{g.setButtonText(e?"\u5B89\u88C5":"Install").setCta().onClick(()=>{if(!M){new b.Notice(e?"\u8BF7\u8F93\u5165\u6280\u80FD\u5305\u540D\uFF01":"Please enter package name!");return}g.setDisabled(!0),g.setButtonText(e?"\u6B63\u5728\u5B89\u88C5...":"Installing..."),new b.Notice(e?`\u5F00\u59CB\u5B89\u88C5\u6280\u80FD ${M}...`:`Starting installation of ${M}...`),this.installSkill(M,x,(y,C)=>{g.setDisabled(!1),g.setButtonText(e?"\u5B89\u88C5":"Install"),y?(new b.Notice(e?`\u5B89\u88C5\u5931\u8D25\uFF1A${y}`:`Installation failed: ${y}`),console.error("\u6280\u80FD\u5B89\u88C5\u5931\u8D25\uFF1A",y,C)):(new b.Notice(e?`\u6280\u80FD ${M} \u5B89\u88C5\u6210\u529F\uFF01`:`Skill ${M} installed successfully!`),this.display())})})})}renderBuiltinCredentialRow(t,e,i,s,n){let o=e.id,a=i[o],r=a&&a.type==="oauth",l=!!(a&&(a.type==="oauth"||a.key&&a.key.trim())),d=new b.Setting(t).setName(e.name).setDesc(r?n?"OAuth \u5DF2\u6388\u6743 / Connected":"OAuth Authorized":l?n?`API \u5BC6\u94A5\u5DF2\u914D\u7F6E / Connected${e.envVar?" \xB7 \u73AF\u5883\u53D8\u91CF "+e.envVar:""}`:`API Key configured${e.envVar?" \xB7 env "+e.envVar:""}`:n?`\u7B49\u5F85\u914D\u7F6E API \u5BC6\u94A5${e.envVar?" \xB7 \u73AF\u5883\u53D8\u91CF "+e.envVar:""}`:`Awaiting API Key${e.envVar?" \xB7 env "+e.envVar:""}`);if(this.justAddedBuiltinId===o&&(d.settingEl.dataset.justAdded="true"),r){d.addButton(c=>{c.setButtonText(n?"\u65AD\u5F00\u8FDE\u63A5":"Disconnect"),c.buttonEl.addClass("mod-warning"),c.onClick(()=>{(async()=>{delete i[o],E.writeFileSync(s,JSON.stringify(i,null,2),"utf-8"),this.temporaryProviders=this.temporaryProviders.filter(m=>m!==o),this.display();let p=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let m of p){let v=m.view;v&&v.client&&await v.client.restart()}})().catch(p=>{console.error("[pimate] disconnect provider failed",p),new b.Notice(p instanceof Error?p.message:String(p))})})});return}e.oauth&&o==="openai-codex"&&d.addButton(c=>{c.setButtonText(n?"Device Code \u767B\u5F55":"Device Code Login").setCta().onClick(()=>{this.startOpenAICodexDeviceCodeLogin().catch(p=>{console.error("[pimate] device-code login failed",p),new b.Notice(p instanceof Error?p.message:String(p))})})}),d.addText(c=>{let p="";c.setPlaceholder(l?n?"\u8F93\u5165\u65B0\u5BC6\u94A5\u4EE5\u66FF\u6362...":"Enter new key to replace...":"sk-...").onChange(v=>{p=v.trim()}),c.inputEl.type="password",c.inputEl.addClass("pi-agent-input-api-key");let m=async()=>{if(p){this.writeApiKey(o,p),this.temporaryProviders=this.temporaryProviders.filter(w=>w!==o),this.display();let v=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let w of v){let T=w.view;T&&T.client&&await T.client.restart()}}};c.inputEl.addEventListener("blur",()=>{m()}),c.inputEl.addEventListener("keydown",v=>{v.key==="Enter"&&(v.preventDefault(),m())})}),d.addButton(c=>{c.setButtonText(n?"\u65AD\u5F00\u8FDE\u63A5":"Disconnect"),c.buttonEl.addClass("mod-warning"),c.onClick(()=>{(async()=>{delete i[o],E.writeFileSync(s,JSON.stringify(i,null,2),"utf-8"),this.temporaryProviders=this.temporaryProviders.filter(m=>m!==o),this.display();let p=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let m of p){let v=m.view;v&&v.client&&await v.client.restart()}})().catch(p=>{console.error("[pimate] disconnect provider failed",p),new b.Notice(p instanceof Error?p.message:String(p))})})})}renderCustomProviderRow(t,e,i,s,n){let o=i[e]||{},a=Array.isArray(o.models)?o.models:[],r=a.length,l=o.baseUrl||"",d=o.api||"",c=!!(s[e]&&s[e].key),p=[];l&&p.push(l),d&&p.push(`api: ${d}`),p.push(n?`${r} \u4E2A\u6A21\u578B`:`${r} model${r===1?"":"s"}`),p.push(c?n?"key \u5DF2\u914D\u7F6E":"key set":n?"\u26A0 \u672A\u914D key":"\u26A0 no key");let m=new b.Setting(t).setName(e+(c?"":" \u26A0")).setDesc(p.join(" \xB7 "));if(r>0){let v=m.descEl.createEl("div",{cls:"pi-agent-custom-model-list"});for(let w of a){let T=typeof w=="string"?w:w.id||"",k=typeof w=="object"&&w.name?w.name:"",M=v.createEl("div",{cls:"pi-agent-custom-model-item"});M.createEl("span",{cls:"pi-agent-custom-model-id",text:T}),k&&k!==T&&M.createEl("span",{cls:"pi-agent-custom-model-name",text:k}),typeof w=="object"&&w.reasoning&&M.createEl("span",{cls:"pi-agent-custom-model-tag",text:n?"\u63A8\u7406":"reasoning"})}}m.addText(v=>{let w="";v.setPlaceholder(c?n?"\u8F93\u5165\u65B0\u5BC6\u94A5\u4EE5\u66FF\u6362...":"Enter new key to replace...":"sk-...").onChange(k=>{w=k.trim()}),v.inputEl.type="password",v.inputEl.addClass("pi-agent-input-api-key");let T=async()=>{if(w){this.writeApiKey(e,w),this.display();let k=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let M of k){let x=M.view;x&&x.client&&await x.client.restart()}}};v.inputEl.addEventListener("blur",()=>{T()}),v.inputEl.addEventListener("keydown",k=>{k.key==="Enter"&&(k.preventDefault(),T())})}),m.addButton(v=>{v.setButtonText(n?"\u5220\u9664":"Delete"),v.buttonEl.addClass("mod-warning"),v.onClick(()=>{window.confirm(n?`\u786E\u5B9A\u5220\u9664\u81EA\u5B9A\u4E49 provider \u201C${e}\u201D\uFF1F
\u5C06\u4ECE models.json \u548C auth.json \u4E2D\u79FB\u9664\u8BE5 provider\u3002`:`Delete custom provider "${e}"?
It will be removed from both models.json and auth.json.`)&&(async()=>{let T=this.readModelsJson();delete T[e],this.writeModelsJson(T);let k=this.getAuthJsonPath();if(E.existsSync(k))try{let x=JSON.parse(E.readFileSync(k,"utf-8"))||{};delete x[e],E.writeFileSync(k,JSON.stringify(x,null,2),"utf-8")}catch(x){console.error("\u6E05\u7406 auth.json \u5931\u8D25:",x)}this.temporaryProviders=this.temporaryProviders.filter(x=>x!==e),this.display();let M=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let x of M){let g=x.view;g&&g.client&&await g.client.restart()}})().catch(T=>{console.error("[pimate] delete custom provider failed",T),new b.Notice(T instanceof Error?T.message:String(T))})})})}applyCustomProviderConfig(t,e){let i=this.readModelsJson(),s={baseUrl:t.baseUrl.trim(),api:t.apiType},n=t.apiKey.trim();n&&(s.apiKey=n,this.writeApiKey(t.providerId,n)),t.supportsDeveloperRole===!1&&(s.compat={...s.compat||{},supportsDeveloperRole:!1}),s.models=t.models.filter(a=>a.id.trim()),i[t.providerId]=s,this.writeModelsJson(i),new b.Notice(e?`\u5DF2\u6DFB\u52A0\u81EA\u5B9A\u4E49 provider \u201C${t.providerId}\u201D\u5230 models.json\u3002\u91CD\u542F Pimate \u751F\u6548\u3002`:`Custom provider "${t.providerId}" added to models.json. Restart Pimate to apply.`),this.display();let o=this.app.workspace.getLeavesOfType("pimate-chat-view");for(let a of o){let r=a.view;r&&r.client&&r.client.restart().catch(l=>console.error("[pimate] restart failed",l))}}createSkillSetting(t,e,i){let s=K.homedir(),n=e.filePath;n.startsWith(s)&&(n="~"+n.slice(s.length));let a=this.app.vault.adapter.basePath||"";a&&n.startsWith(a)&&(n="."+n.slice(a.length));let r=`${e.description||(i?"\u65E0\u63CF\u8FF0":"No description")}
(${n})`;new b.Setting(t).setName(e.name).setDesc(r).addToggle(l=>{l.setValue(!e.disabled).onChange(async d=>{this.toggleSkill(e.filePath,!d),new b.Notice(i?`\u6280\u80FD\u5DF2${d?"\u542F\u7528":"\u7981\u7528"}`:`Skill ${d?"enabled":"disabled"}`)})})}async startOpenAICodexDeviceCodeLogin(){let t=this.plugin.settings.language==="zh",e=new ye(this.app);e.open();let i=new AbortController;e.onCancelSignal=()=>i.abort();try{e.setProgress(t?"\u6B63\u5728\u8BF7\u6C42 device code...":"Requesting device code...");let s=await this.requestOpenAICodexUserCode(i.signal);e.setDeviceCode({userCode:s.userCode,verificationUri:nt,intervalSeconds:s.intervalSeconds,expiresInSeconds:fe}),e.setProgress(t?"\u7B49\u5F85\u4F60\u5728\u6D4F\u89C8\u5668\u4E2D\u5B8C\u6210\u6388\u6743...":"Waiting for browser authorization...");let{authorizationCode:n,codeVerifier:o}=await this.pollOpenAICodexDeviceAuth(s,i.signal,l=>e.setProgress(l));e.setProgress(t?"\u4EA4\u6362 access token...":"Exchanging authorization code for tokens...");let a=await this.exchangeOpenAICodexAuthorizationCode(n,o,i.signal);this.writeApiKey("openai-codex",JSON.stringify({type:"oauth",refresh:a.refresh,access:a.access,expires:a.expires})),e.closeWithSuccess(),new b.Notice(t?"OpenAI Codex \u8BA2\u9605\u767B\u5F55\u6210\u529F\uFF01":"OpenAI Codex subscription connected!"),this.display();let r=this.app.workspace.getLeavesOfType(U);for(let l of r){let d=l.view;if(d&&d.client)try{await d.client.restart()}catch(c){console.error("[pimate] failed to restart client after OAuth login",c)}}}catch(s){let n=s?.message||String(s);i.signal.aborted||new b.Notice(t?`\u767B\u5F55\u5931\u8D25\uFF1A${n}`:`Login failed: ${n}`,8e3),e.closeWithError(n)}}async requestOpenAICodexUserCode(t){if(t.aborted)throw new Error("Login cancelled");let e=await(0,b.requestUrl)({url:tt,method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_id:Le}),throw:!1});if(e.status<200||e.status>=300)throw e.status===404?new Error("OpenAI Codex device code login is not enabled. Please try again later."):new Error(`OpenAI Codex device code request failed: ${e.status} ${e.text}`);let i=e.json,s=i.device_auth_id,n=i.user_code,o=i.interval,a=typeof o=="string"?Number(o.trim()):o;if(!s||!n||typeof a!="number"||!Number.isFinite(a)||a<0)throw new Error(`Invalid OpenAI Codex device code response: ${JSON.stringify(i)}`);return{deviceAuthId:s,userCode:n,intervalSeconds:a}}async pollOpenAICodexDeviceAuth(t,e,i){let o=Date.now()+fe*1e3,a=Math.max(1e3,Math.floor((t.intervalSeconds||5)*1e3)),r=0;for(;Date.now()<o;){if(e.aborted)throw new Error("Login cancelled");r++,i(`Polling\u2026 attempt ${r} (${Math.round((Date.now()-(o-fe*1e3))/1e3)}s)`);let l;try{let c=await(0,b.requestUrl)({url:it,method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_auth_id:t.deviceAuthId,user_code:t.userCode}),throw:!1});if(c.status>=200&&c.status<300){let p=c.json,m=p.authorization_code,v=p.code_verifier;!m||!v?l={status:"failed",message:`Invalid OpenAI Codex device auth response: ${JSON.stringify(p)}`}:l={status:"complete",value:{authorizationCode:m,codeVerifier:v}}}else if(c.status===403||c.status===404)l={status:"pending"};else{let p=c.text||"",m;try{let w=JSON.parse(p)?.error;m=typeof w=="object"?w?.code:w}catch{}m==="deviceauth_authorization_pending"?l={status:"pending"}:m==="slow_down"?l={status:"slow_down"}:l={status:"failed",message:`OpenAI Codex device auth failed (${c.status}): ${p}`}}}catch(c){if(e.aborted)throw new Error("Login cancelled");l={status:"pending"},console.warn("[pimate] device code poll network error",c)}if(l.status==="complete")return l.value;if(l.status==="failed")throw new Error(l.message||"Login failed");l.status==="slow_down"&&(a=Math.max(1e3,a+5e3),i(`Server asked us to slow down. Next poll in ${Math.round(a/1e3)}s.`));let d=o-Date.now();if(d<=0)break;await this.sleep(Math.min(a,d),e)}throw new Error("OpenAI Codex device code timed out")}async exchangeOpenAICodexAuthorizationCode(t,e,i){if(i.aborted)throw new Error("Login cancelled");let s=await(0,b.requestUrl)({url:st,method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",client_id:Le,code:t,code_verifier:e,redirect_uri:ot}).toString(),throw:!1});if(s.status<200||s.status>=300)throw new Error(`OpenAI Codex token exchange failed: ${s.status} ${s.text}`);let n=s.json,o=n.access_token,a=n.refresh_token,r=n.expires_in;if(!o||!a||typeof r!="number")throw new Error(`OpenAI Codex token exchange response missing fields: ${JSON.stringify(n)}`);return{access:o,refresh:a,expires:Date.now()+r*1e3}}sleep(t,e){return new Promise((i,s)=>{if(e.aborted){s(new Error("Login cancelled"));return}let n=window.setTimeout(()=>{e.removeEventListener("abort",o),i()},t),o=()=>{window.clearTimeout(n),s(new Error("Login cancelled"))};e.addEventListener("abort",o,{once:!0})})}},we=class extends b.Modal{isZh;onSubmit;idInput;nameInput;baseUrlInput;apiTypeSelect;apiKeyInput;devRoleCheckbox;modelsTextarea;constructor(t,e,i){super(t),this.isZh=e,this.onSubmit=i}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("pi-agent-wizard-modal"),this.titleEl.setText(this.isZh?"\u6DFB\u52A0\u81EA\u5B9A\u4E49 Provider":"Add Custom Provider");let e=(d,c)=>this.isZh?d:c;t.createEl("p",{text:e("\u586B\u5199\u4EE5\u4E0B\u5B57\u6BB5\u751F\u6210 ~/.pi/agent/models.json \u914D\u7F6E\u3002\u9002\u7528\u4E8E\u7845\u57FA\u6D41\u52A8\u3001\u706B\u5C71\u5F15\u64CE\u3001OpenAI \u517C\u5BB9\u7AEF\u70B9\u7B49 Pi \u4E0D\u5185\u7F6E\u7684\u670D\u52A1\u5546\u3002","Fill in the fields below to generate ~/.pi/agent/models.json config. For providers Pi doesn't ship built-in (SiliconFlow, Volcengine, OpenAI-compatible endpoints, etc.)."),cls:"setting-item-description"}),this.addField(e("Provider ID","Provider ID"),e("\u5982 siliconflow\uFF08\u82F1\u6587\u6807\u8BC6\u7B26\uFF09","e.g. siliconflow"),"text","siliconflow",d=>this.idInput=d),this.addField(e("\u663E\u793A\u540D\uFF08\u53EF\u9009\uFF09","Display name (optional)"),e("\u5982 \u7845\u57FA\u6D41\u52A8","e.g. SiliconFlow"),"text","",d=>this.nameInput=d),this.addField(e("Base URL","Base URL"),e("\u5982 https://api.siliconflow.cn/v1","e.g. https://api.siliconflow.cn/v1"),"text","https://api.siliconflow.cn/v1",d=>this.baseUrlInput=d);let i=t.createDiv({cls:"pi-agent-wizard-field"});i.createEl("label",{text:e("API \u534F\u8BAE","API protocol"),cls:"pi-agent-wizard-label"}),this.apiTypeSelect=i.createEl("select",{cls:"dropdown pi-agent-wizard-select"});let s=[{id:"openai-completions",name:e("OpenAI Chat Completions\uFF08\u6700\u5E38\u7528\uFF09","OpenAI Chat Completions (most common)")},{id:"anthropic-messages",name:e("Anthropic Messages","Anthropic Messages")},{id:"openai-responses",name:"OpenAI Responses"},{id:"google-generative-ai",name:"Google Generative AI"}];for(let d of s)this.apiTypeSelect.createEl("option",{value:d.id,text:d.name});this.apiTypeSelect.value="openai-completions",i.createEl("div",{text:e("\u5927\u591A\u6570 OpenAI \u517C\u5BB9\u670D\u52A1\u9009\u7B2C\u4E00\u9879\u3002","Most OpenAI-compatible services use the first option."),cls:"setting-item-description"}),this.addField(e("API Key","API Key"),e("\u53EF\u7559\u7A7A\uFF0C\u7A0D\u540E\u5728\u5217\u8868\u91CC\u586B\u3002","Optional; can fill in later in the list."),"password","",d=>this.apiKeyInput=d);let n=t.createDiv({cls:"pi-agent-wizard-field"});this.devRoleCheckbox=n.createEl("input",{type:"checkbox"}),this.devRoleCheckbox.checked=!0,n.createEl("label",{text:e("\u652F\u6301 developer role","Supports developer role"),cls:"pi-agent-wizard-label"}),n.createEl("div",{text:e("\u82E5\u670D\u52A1\u5546\u4E0D\u8BA4 OpenAI \u7684 developer role\uFF08\u5982\u7845\u57FA\u6D41\u52A8\u4F1A\u62A5 400\uFF09\uFF0C\u53D6\u6D88\u52FE\u9009\u6B64\u9879\u3002\u9ED8\u8BA4\u52FE\u9009\u3002","Uncheck if the provider rejects OpenAI's developer role (e.g. SiliconFlow returns 400). Checked by default."),cls:"setting-item-description"});let o=t.createDiv({cls:"pi-agent-wizard-field"});o.createEl("label",{text:e("\u6A21\u578B\u5217\u8868\uFF08\u6BCF\u884C\u4E00\u4E2A\uFF09","Models (one per line)"),cls:"pi-agent-wizard-label"}),this.modelsTextarea=o.createEl("textarea",{cls:"pi-agent-wizard-textarea"}),this.modelsTextarea.rows=5,this.modelsTextarea.placeholder=e(`deepseek-ai/DeepSeek-V4-Flash
zai-org/GLM-5.2 | GLM-5.2
deepseek-ai/DeepSeek-V4-Pro | DeepSeek V4 Pro | reasoning`,`deepseek-ai/DeepSeek-V4-Flash
zai-org/GLM-5.2 | GLM-5.2
deepseek-ai/DeepSeek-V4-Pro | DeepSeek V4 Pro | reasoning`),o.createEl("div",{text:e("\u683C\u5F0F\uFF1A\u6A21\u578BID \u6216 \u6A21\u578BID | \u663E\u793A\u540D \u6216 \u6A21\u578BID | \u663E\u793A\u540D | reasoning","Format: model-id or model-id | display name or model-id | display name | reasoning"),cls:"setting-item-description"});let a=t.createDiv({cls:"pi-agent-wizard-buttons"}),r=a.createEl("button",{text:e("\u53D6\u6D88","Cancel")});r.onclick=()=>this.close();let l=a.createEl("button",{text:e("\u751F\u6210\u914D\u7F6E","Generate"),cls:"mod-cta"});l.onclick=()=>this.handleSubmit()}addField(t,e,i,s,n){let o=this.contentEl.createDiv({cls:"pi-agent-wizard-field"});o.createEl("label",{text:t,cls:"pi-agent-wizard-label"});let a=o.createEl("input",{type:i,cls:"text-input pi-agent-wizard-input"});a.placeholder=e,a.value=s,n(a)}handleSubmit(){let t=this.idInput.value.trim(),e=this.baseUrlInput.value.trim(),i=this.apiTypeSelect.value,s=this.apiKeyInput.value.trim(),n=this.devRoleCheckbox.checked,o=this.nameInput.value.trim();if(!t){new b.Notice(this.isZh?"Provider ID \u4E0D\u80FD\u4E3A\u7A7A":"Provider ID is required"),this.idInput.focus();return}if(!/^[a-zA-Z0-9_-]+$/.test(t)){new b.Notice(this.isZh?"Provider ID \u53EA\u80FD\u542B\u5B57\u6BCD\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u3001\u8FDE\u5B57\u7B26":"Provider ID may only contain letters, digits, _ and -"),this.idInput.focus();return}if(!e){new b.Notice(this.isZh?"Base URL \u4E0D\u80FD\u4E3A\u7A7A":"Base URL is required"),this.baseUrlInput.focus();return}let a=[],r=this.modelsTextarea.value.split(/\r?\n/).map(l=>l.trim()).filter(Boolean);for(let l of r){let d=l.split("|").map(m=>m.trim()),c=d[0];if(!c)continue;let p={id:c};d[1]&&(p.name=d[1]),(d.includes("reasoning")||d.includes("\u63A8\u7406"))&&(p.reasoning=!0),a.push(p)}if(a.length===0){new b.Notice(this.isZh?"\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u6A21\u578B":"At least one model is required"),this.modelsTextarea.focus();return}this.onSubmit({providerId:t,displayName:o||void 0,baseUrl:e,apiType:i,apiKey:s,supportsDeveloperRole:n,models:a}),this.close()}onClose(){this.contentEl.empty()}},ye=class extends b.Modal{statusEl;codeEl;linkEl;openBtn;copyBtn;cancelBtn;instructionsEl;state="waiting";onCancelSignal=null;constructor(t){super(t)}onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("pi-agent-device-code-modal"),this.titleEl.setText("OpenAI Codex \xB7 Device Code"),this.statusEl=t.createDiv({cls:"pi-agent-device-code-status"}),this.statusEl.setText("Requesting device code\u2026"),this.codeEl=t.createDiv({cls:"pi-agent-device-code-code"}),this.codeEl.setText("\u2014 \u2014 \u2014 \u2014"),this.codeEl.addClass("pi-agent-hidden"),this.linkEl=t.createEl("a",{cls:"pi-agent-device-code-link",text:""}),this.linkEl.setAttribute("target","_blank"),this.linkEl.setAttribute("rel","noopener noreferrer"),this.linkEl.addClass("pi-agent-hidden"),this.instructionsEl=t.createDiv({cls:"pi-agent-device-code-instructions"}),this.instructionsEl.addClass("pi-agent-hidden");let e=t.createDiv({cls:"pi-agent-device-code-buttons"});this.openBtn=e.createEl("button",{text:"Open verification page",cls:"mod-cta"}),this.openBtn.addClass("pi-agent-hidden"),this.openBtn.onclick=()=>{if(!this.linkEl.getAttribute("href"))return;let i=this.linkEl.getAttribute("href")||"";this.openExternal(i).catch(s=>{console.error("[pimate] open external failed",s)})},this.copyBtn=e.createEl("button",{text:"Copy code"}),this.copyBtn.addClass("pi-agent-hidden"),this.copyBtn.onclick=()=>{let i=this.codeEl.textContent||"";!i||i==="\u2014 \u2014 \u2014 \u2014"||navigator.clipboard.writeText(i).then(()=>{this.copyBtn.setText("Copied \u2713"),window.setTimeout(()=>this.copyBtn.setText("Copy code"),1500)}).catch(s=>{console.error("[pimate] clipboard write failed",s)})},this.cancelBtn=e.createEl("button",{text:"Cancel"}),this.cancelBtn.onclick=()=>{this.cancel()}}onClose(){this.contentEl.empty()}setDeviceCode(t){this.state="code",this.statusEl.setText("Open the verification page in your browser and enter the code below:"),this.codeEl.setText(t.userCode),this.codeEl.removeClass("pi-agent-hidden"),this.linkEl.setText(t.verificationUri),this.linkEl.setAttribute("href",t.verificationUri),this.linkEl.removeClass("pi-agent-hidden"),this.openBtn.removeClass("pi-agent-hidden"),this.copyBtn.removeClass("pi-agent-hidden");let e=t.expiresInSeconds?Math.round(t.expiresInSeconds/60):null;this.instructionsEl.setText(e?`Code expires in about ${e} minute${e===1?"":"s"}.`:"Code expires after a few minutes \u2014 finish quickly."),this.instructionsEl.removeClass("pi-agent-hidden")}setBrowserAuthUrl(t,e){this.state="browser",this.statusEl.setText(e||"A browser-based login URL is available. Open it to continue:"),this.linkEl.setText(t),this.linkEl.setAttribute("href",t),this.linkEl.removeClass("pi-agent-hidden"),this.openBtn.removeClass("pi-agent-hidden")}setProgress(t){this.state==="success"||this.state==="error"||this.state==="cancelled"||this.statusEl.setText(t)}closeWithSuccess(){this.state="success",this.statusEl.setText("\u2713 Connected. Loading credentials\u2026"),this.openBtn.addClass("pi-agent-hidden"),this.copyBtn.addClass("pi-agent-hidden"),this.cancelBtn.setText("Close")}closeWithError(t){this.state="error",this.statusEl.setText(`\u2717 ${t||"Login failed"}`),this.openBtn.addClass("pi-agent-hidden"),this.copyBtn.addClass("pi-agent-hidden"),this.cancelBtn.setText("Close")}cancel(){if(this.state==="success"||this.state==="error"||this.state==="cancelled"){this.close();return}this.state="cancelled",this.statusEl.setText("Cancelling\u2026"),this.openBtn.addClass("pi-agent-hidden"),this.copyBtn.addClass("pi-agent-hidden"),this.cancelBtn.setText("Close"),this.onCancelSignal?.(),this.close()}async openExternal(t){let e=!1;try{let i=window.require?.("electron");i?.shell?.openExternal&&(await i.shell.openExternal(t),e=!0)}catch(i){console.warn("[pimate] electron shell.openExternal failed, fallback",i)}if(!e)try{let i=activeDocument.createElement("a");i.href=t,i.target="_blank",i.rel="noopener noreferrer",i.click()}catch(i){console.error("[pimate] fallback anchor click failed",i)}}};var ie=z(require("fs")),$e=z(require("path")),Fe=z(require("os")),te=class extends I.Plugin{constructor(t,e){super(t,e)}explorerSelection=[];refreshExplorerSelection(){let t=this.app.workspace.getLeavesOfType("file-explorer")[0]?.view;if(!t){this.explorerSelection=[];return}let e=[],i=new Set,s=a=>{a&&!i.has(a)&&(i.add(a),e.push(a))},n=t.selection;if(n&&n.size>0)for(let a of n)s(a);let o=t.fileItems;if(o){let a=o instanceof Map?o.entries():Object.entries(o);for(let[r,l]of a){let d=l?.el;d&&d.classList&&d.classList.contains("is-selected")&&s(r&&typeof r=="object"?r:this.app.vault.getAbstractFileByPath(String(r)))}}e.length>0&&(this.explorerSelection=e)}getExplorerSelectionForContext(){return this.refreshExplorerSelection(),[...this.explorerSelection]}getRightClickMultiSelection(t){if(this.explorerSelection.length===0)return[t];let e=new Set,i=[];for(let s of this.explorerSelection)e.has(s)||(e.add(s),i.push(s));return e.has(t)||i.push(t),i}async onload(){(0,I.addIcon)("pimate-logo",'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5h14v14H5zM9 2v3M15 2v3M9 19v3M15 19v3M2 9h3M2 15h3M19 9h3M19 15h3M8.5 9.5h7M11 9.5Q10.5 13 8.5 15M13.5 9.5L13.5 13.5Q13.5 15 15 15"/></svg>'),(0,I.addIcon)("pi-agent-icon-openai",'<svg viewBox="0 0 24 24" fill="currentColor" class="svg-icon" style="color: #10a37f;"><path d="M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z"/></svg>'),(0,I.addIcon)("pi-agent-icon-claude",'<svg viewBox="0 0 16 16" fill="currentColor" class="svg-icon" style="color: #cc5a37;"><path d="M9.218 2h2.402L16 12.987h-2.402zM4.379 2h2.512l4.38 10.987H8.82l-.895-2.308h-4.58l-.896 2.307H0L4.38 2.001zm2.755 6.64L5.635 4.777 4.137 8.64z"/></svg>'),(0,I.addIcon)("pi-agent-icon-deepseek",'<svg viewBox="0 0 512 509.64" fill="currentColor" class="svg-icon" style="color: #0066ff;"><path fill-rule="nonzero" d="M440.898 139.167c-4.001-1.961-5.723 1.776-8.062 3.673-.801.612-1.479 1.407-2.154 2.141-5.848 6.246-12.681 10.349-21.607 9.859-13.048-.734-24.192 3.368-34.04 13.348-2.093-12.307-9.048-19.658-19.635-24.37-5.54-2.449-11.141-4.9-15.02-10.227-2.708-3.795-3.447-8.021-4.801-12.185-.861-2.509-1.725-5.082-4.618-5.512-3.139-.49-4.372 2.142-5.601 4.349-4.925 9.002-6.833 18.921-6.647 28.962.432 22.597 9.972 40.597 28.932 53.397 2.154 1.47 2.707 2.939 2.032 5.082-1.293 4.41-2.832 8.695-4.186 13.105-.862 2.817-2.157 3.429-5.172 2.205-10.402-4.346-19.391-10.778-27.332-18.553-13.481-13.044-25.668-27.434-40.873-38.702a177.614 177.614 0 00-10.834-7.409c-15.512-15.063 2.032-27.434 6.094-28.902 4.247-1.532 1.478-6.797-12.251-6.736-13.727.061-26.285 4.653-42.288 10.777-2.34.92-4.801 1.593-7.326 2.142-14.527-2.756-29.608-3.368-45.367-1.593-29.671 3.305-53.368 17.329-70.788 41.272-20.928 28.785-25.854 61.482-19.821 95.59 6.34 35.943 24.683 65.704 52.876 88.974 29.239 24.123 62.911 35.943 101.32 33.677 23.329-1.346 49.307-4.468 78.607-29.27 7.387 3.673 15.142 5.144 28.008 6.246 9.911.92 19.452-.49 26.839-2.019 11.573-2.449 10.773-13.166 6.586-15.124-33.915-15.797-26.47-9.368-33.24-14.573 17.235-20.39 43.213-41.577 53.369-110.222.8-5.448.121-8.877 0-13.287-.061-2.692.553-3.734 3.632-4.041 8.494-.981 16.742-3.305 24.314-7.471 21.975-12.002 30.84-31.719 32.933-55.355.307-3.612-.061-7.348-3.879-9.245v-.003zM249.4 351.89c-32.872-25.838-48.814-34.352-55.4-33.984-6.155.368-5.048 7.41-3.694 12.002 1.415 4.532 3.264 7.654 5.848 11.634 1.785 2.634 3.017 6.551-1.784 9.493-10.587 6.55-28.993-2.205-29.856-2.635-21.421-12.614-39.334-29.269-51.954-52.047-12.187-21.924-19.267-45.435-20.435-70.542-.308-6.061 1.478-8.207 7.509-9.307 7.94-1.471 16.127-1.778 24.068-.615 33.547 4.9 62.108 19.902 86.054 43.66 13.666 13.531 24.007 29.699 34.658 45.496 11.326 16.778 23.514 32.761 39.026 45.865 5.479 4.592 9.848 8.083 14.035 10.656-12.62 1.407-33.673 1.714-48.075-9.676zm15.899-102.519c.521-2.111 2.421-3.658 4.722-3.658a4.74 4.74 0 011.661.305c.678.246 1.293.614 1.786 1.163.861.859 1.354 2.083 1.354 3.368 0 2.695-2.154 4.837-4.862 4.837a4.748 4.748 0 01-4.738-4.034 5.01 5.01 0 01.077-1.981zm47.208 26.915c-2.606.996-5.2 1.778-7.707 1.88-4.679.244-9.787-1.654-12.556-3.981-4.308-3.612-7.386-5.631-8.679-11.941-.554-2.695-.247-6.858.246-9.246 1.108-5.144-.124-8.451-3.754-11.451-2.954-2.449-6.711-3.122-10.834-3.122-1.539 0-2.954-.673-4.001-1.224-1.724-.856-3.139-3-1.785-5.634.432-.856 2.525-2.939 3.018-3.305 5.6-3.185 12.065-2.144 18.034.244 5.54 2.266 9.727 6.429 15.759 12.307 6.155 7.102 7.263 9.063 10.773 14.39 2.771 4.163 5.294 8.451 7.018 13.348.877 2.561.071 4.74-2.341 6.277-.981.625-2.109 1.044-3.191 1.458z"/></svg>'),(0,I.addIcon)("pi-agent-icon-minimax",'<svg viewBox="0 0 24 24" fill="currentColor" class="svg-icon" style="color: #ff4d4f;"><path d="M16.278 2c1.156 0 2.093.927 2.093 2.07v12.501a.74.74 0 00.744.709.74.74 0 00.743-.709V9.099a2.06 2.06 0 012.071-2.049A2.06 2.06 0 0124 9.1v6.561a.649.649 0 01-.652.645.649.649 0 01-.653-.645V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v7.472a2.037 2.037 0 01-2.048 2.026 2.037 2.037 0 01-2.048-2.026v-12.5a.785.785 0 00-.788-.753.785.785 0 00-.789.752l-.001 15.904A2.037 2.037 0 0113.441 22a2.037 2.037 0 01-2.048-2.026V18.04c0-.356.292-.645.652-.645.36 0 .652.289.652.645v1.934c0 .263.142.506.372.638.23.131.514.131.744 0a.734.734 0 00.372-.638V4.07c0-1.143.937-2.07 2.093-2.07zm-5.674 0c1.156 0 2.093.927 2.093 2.07v11.523a.648.648 0 01-.652.645.648.648 0 01-.652-.645V4.07a.785.785 0 00-.789-.78.785.785 0 00-.789.78v14.013a2.06 2.06 0 01-2.07 2.048 2.06 2.06 0 01-2.071-2.048V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v3.8a2.06 2.06 0 01-2.071 2.049A2.06 2.06 0 010 12.9v-1.378c0-.357.292-.646.652-.646.36 0 .653.29.653.646V12.9c0 .418.343.757.766.757s.766-.339.766-.757V9.099a2.06 2.06 0 012.07-2.048 2.06 2.06 0 012.071 2.048v8.984c0 .419.343.758.767.758.423 0 .766-.339.766-.758V4.07c0-1.143.937-2.07 2.093-2.07z"/></svg>'),(0,I.addIcon)("pi-agent-icon-gemini",'<svg viewBox="0 0 24 24" fill="currentColor" class="svg-icon" style="color: #7c3aed;"><path d="M12 2l1.8 5.4L19.2 9.2 13.8 11 12 16.4 10.2 11 4.8 9.2l5.4-1.8L12 2zm6 12l.9 2.7L21.6 17.6l-2.7.9-.9 2.7-.9-2.7-2.7-.9 2.7-.9.9-2.7z"/></svg>'),(0,I.addIcon)("pi-agent-icon-xiaomi",'<svg viewBox="0 0 24 24" fill="none" class="svg-icon" style="color: #ff6700;"><path d="M12,2C17.5,2 22,6.5 22,12C22,17.5 17.5,22 12,22C6.5,22 2,17.5 2,12C2,6.5 6.5,2 12,2Z" fill="currentColor"/><path d="M6.5,16V10.5a1.8,1.8 0 0,1 3.6,0V16 M10.1,16V10.5a1.8,1.8 0 0,1 3.6,0V16 M17.5,16V8.5" fill="none" stroke="#ffffff" stroke-width="1.6" stroke-linecap="butt" stroke-linejoin="round"/></svg>'),(0,I.addIcon)("pi-agent-icon-volcengine",'<svg viewBox="0 0 24 24" fill="currentColor" class="svg-icon" style="color: #1664ff;"><path d="M5.31 15.756c.172-3.75 1.883-5.999 2.549-6.739-3.26 2.058-5.425 5.658-6.358 8.308v1.12C1.501 21.513 4.226 24 7.59 24a6.59 6.59 0 002.2-.375c.353-.12.7-.248 1.039-.378.913-.899 1.65-1.91 2.243-2.992-4.877 2.431-7.974.072-7.763-4.5l.002.001z" fill-opacity=".5"></path><path d="M22.57 10.283c-1.212-.901-4.109-2.404-7.397-2.8.295 3.792.093 8.766-2.1 12.773a12.782 12.782 0 01-2.244 2.992c3.764-1.448 6.746-3.457 8.596-5.219 2.82-2.683 3.353-5.178 3.361-6.66a2.737 2.737 0 00-.216-1.084v-.002zM14.303 1.867C12.955.7 11.248 0 9.39 0 7.532 0 5.883.677 4.545 1.807 2.791 3.29 1.627 5.557 1.5 8.125v9.201c.932-2.65 3.097-6.25 6.357-8.307.5-.318 1.025-.595 1.569-.829 1.883-.801 3.878-.932 5.746-.706-.222-2.83-.718-5.002-.87-5.617h.001z"></path><path d="M17.305 4.961a199.47 199.47 0 01-1.08-1.094c-.202-.213-.398-.419-.586-.622l-1.333-1.378c.151.615.648 2.786.869 5.617 3.288.395 6.185 1.898 7.396 2.8-1.306-1.275-3.475-3.487-5.266-5.323z" fill-opacity=".5"></path></svg>'),(0,I.addIcon)("pi-agent-icon-siliconflow",'<svg viewBox="0 0 24 24" fill="currentColor" class="svg-icon" style="color: #00a3ff;"><path clip-rule="evenodd" d="M22.956 6.521H12.522c-.577 0-1.044.468-1.044 1.044v3.13c0 .577-.466 1.044-1.043 1.044H1.044c-.577 0-1.044.467-1.044 1.044v4.174C0 17.533.467 18 1.044 18h10.434c.577 0 1.044-.467 1.044-1.043v-3.13c0-.578.466-1.044 1.043-1.044h9.391c.577 0 1.044-.467 1.044-1.044V7.565c0-.576-.467-1.044-1.044-1.044z"/></svg>'),(0,I.addIcon)("pi-agent-icon-zhipu",'<svg viewBox="0 0 24 24" fill="currentColor" class="svg-icon" style="color: #3b82f6;"><path d="M3 3h7.2L12 5.4 13.8 3H21v7.2L18.6 12 21 13.8V21h-7.2L12 18.6 10.2 21H3v-7.2L5.4 12 3 10.2V3zm2.4 1.8v4.4L8.6 12 5.4 14.8v4.4h4.4L12 15.4l2.2 3.8h4.4v-4.4L15.4 12l3.2-2.8V4.8h-4.4L12 8.6 9.8 4.8H5.4zM12 10.2L13.5 12 12 13.8 10.5 12 12 10.2z"/></svg>'),await this.loadSettings(),this.registerView(U,e=>new Z(e,this)),this.addRibbonIcon("pimate-logo","Open Pimate",()=>{let e=this.settings?.language==="en"?"en":"zh";new I.Notice(e==="zh"?"\u6B63\u5728\u542F\u52A8 Pimate...":"Starting Pimate..."),this.activateView()}),this.addCommand({id:"open-chat",name:"Open chat",callback:()=>{this.activateView()}}),this.addCommand({id:"new-session",name:"New session",callback:()=>this.runAsync(async()=>{await(await this.activateView())?.newChatSession()})}),this.addCommand({id:"close-active-session",name:"Close active session tab",callback:()=>this.runAsync(async()=>{await(await this.activateView())?.closeActiveSessionTab()})}),this.addCommand({id:"focus-composer",name:"Focus composer",callback:()=>this.runAsync(async()=>{(await this.activateView())?.focusComposer()})}),this.addCommand({id:"open-actions-and-skills",name:"Open actions and skills",callback:()=>this.runAsync(async()=>{(await this.activateView())?.openCommandsAndSkills()})}),this.addCommand({id:"previous-message",name:"Jump to previous message",callback:()=>this.runAsync(async()=>{(await this.activateView())?.scrollToPreviousMessage()})}),this.addCommand({id:"next-message",name:"Jump to next message",callback:()=>this.runAsync(async()=>{(await this.activateView())?.scrollToNextMessage()})}),this.addCommand({id:"toggle-last-tool",name:"Toggle last tool output",callback:()=>this.runAsync(async()=>{(await this.activateView())?.toggleLastToolBlock()})}),this.addCommand({id:"jump-last-diff",name:"Jump to last diff",callback:()=>this.runAsync(async()=>{(await this.activateView())?.scrollToLastDiff()})}),this.addCommand({id:"resume-session",name:"Resume previous session",callback:()=>this.runAsync(async()=>{await(await this.activateView())?.resumePreviousSession()})}),this.addCommand({id:"fork-session",name:"Fork session from previous prompt",callback:()=>this.runAsync(async()=>{await(await this.activateView())?.forkFromPreviousPrompt()})}),this.addCommand({id:"clone-branch",name:"Clone current branch",callback:()=>this.runAsync(async()=>{await(await this.activateView())?.cloneCurrentSessionBranch()})}),this.addCommand({id:"send-selection",name:"Send selection",editorCallback:e=>this.runAsync(async()=>{let i=e.getSelection();if(!i){new I.Notice("No text selected");return}(await this.activateView())?.addSelectionContext(i)})}),this.addCommand({id:"inline-edit-selection",name:"Inline edit selection",editorCallback:e=>this.runAsync(async()=>{let i=e.getSelection();if(!i){new I.Notice("No text selected");return}let s=e.getCursor("from"),n=e.getCursor("to");await(await this.activateView())?.inlineEditSelection(i,a=>{e.replaceRange(a,s,n)})})}),this.addCommand({id:"send-current-file",name:"Send current file",callback:()=>this.runAsync(async()=>{if(!this.app.workspace.getActiveFile()){new I.Notice("No active file");return}(await this.activateView())?.addActiveFileContext()})}),this.addCommand({id:"insert-last-response",name:"Insert last response into current note",callback:()=>this.runAsync(async()=>{await(await this.activateView())?.insertLastAssistantIntoActiveNote()})}),this.registerEvent(this.app.workspace.on("active-leaf-change",()=>{this.refreshExplorerSelection()})),this.registerDomEvent(activeDocument,"click",()=>{this.refreshExplorerSelection()},!0),this.registerEvent(this.app.workspace.on("file-menu",(e,i)=>{if(!(i instanceof I.TFile))return;this.refreshExplorerSelection();let s=this.getRightClickMultiSelection(i),o=s.length>1?`Add ${s.length} items to Pimate context`:"Send to Pimate";e.addItem(a=>a.setTitle(o).setIcon("pimate-logo").onClick(()=>this.runAsync(async()=>{let r=await this.activateView();if(!r)return;let l=0;for(let d of s)d instanceof I.TFile?(r.addFileContextItem(d),l++):d instanceof I.TFolder&&(r.addFolderContextItem(d,!0),l++);new I.Notice(`Pimate: added ${l} item${l===1?"":"s"} to context`)})))}));let t=(e,i)=>{this.refreshExplorerSelection();let s=this.getRightClickMultiSelection(i),o=s.length>1?`Add ${s.length} items to Pimate context`:"Add folder to Pimate context";e.addItem(a=>a.setTitle(o).setIcon("pimate-logo").onClick(()=>this.runAsync(async()=>{let r=await this.activateView();if(!r)return;let l=0;for(let d of s)d instanceof I.TFile?(r.addFileContextItem(d),l++):d instanceof I.TFolder&&(r.addFolderContextItem(d,!0),l++);new I.Notice(`Pimate: added ${l} item${l===1?"":"s"} to context`)})))};this.registerEvent(this.app.workspace.on("folder-menu",t)),this.addSettingTab(new ee(this.app,this)),console.log("Pimate plugin loaded")}runAsync(t){t().catch(e=>{console.error("[pimate] command failed",e),new I.Notice(e instanceof Error?e.message:String(e))})}onunload(){console.log("Pimate plugin unloaded")}async activateView(){let{workspace:t}=this.app,e=t.getLeavesOfType(U)[0]??null;return e||(e=t.getRightLeaf(!1),e&&await e.setViewState({type:U,active:!0})),e&&t.setActiveLeaf(e),e?.view}async loadSettings(){this.settings=Object.assign({},Re,await this.loadData()),this.settings.showThinking=this.settings.showThinking!==!1,this.autoDetectDefaultModel()}autoDetectDefaultModel(){if(this.settings.provider&&this.settings.modelId)return;let t=Fe.homedir(),e=$e.join(t,".pi","agent","auth.json");if(ie.existsSync(e))try{let i=ie.readFileSync(e,"utf-8"),s=JSON.parse(i)||{},n=[{id:"deepseek",defaultModel:"deepseek-chat"},{id:"openai-codex",defaultModel:"gpt-4o"},{id:"minimax",defaultModel:"MiniMax-M2.7"},{id:"minimax-cn",defaultModel:"MiniMax-M2.7"},{id:"siliconflow",defaultModel:"deepseek-ai/DeepSeek-V3"},{id:"google",defaultModel:"gemini-2.5-flash"},{id:"anthropic",defaultModel:"claude-3-5-sonnet-latest"},{id:"zhipu",defaultModel:"glm-5.2"}];for(let o of n)if(s[o.id]&&(s[o.id].key||s[o.id].type==="oauth")){this.settings.provider=o.id,this.settings.modelId=o.defaultModel,this.saveSettings(),console.log(`[Pimate] \u81EA\u52A8\u68C0\u6D4B\u5230\u5DF2\u914D\u7F6E\u51ED\u636E\u7684\u5382\u5546\uFF0C\u9ED8\u8BA4\u6A21\u578B\u8BBE\u4E3A ${o.id}/${o.defaultModel}`);break}}catch(i){console.error("[Pimate] \u81EA\u52A8\u68C0\u6D4B\u5DF2\u914D\u7F6E\u6A21\u578B\u5931\u8D25:",i)}}async saveSettings(){await this.saveData(this.settings)}};