mirror of
https://github.com/gorazenxu/pimate.git
synced 2026-07-22 07:32:35 +00:00
- 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
71 lines
201 KiB
JavaScript
71 lines
201 KiB
JavaScript
/*
|
||
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)}};
|