14 lines
26 KiB
JavaScript
14 lines
26 KiB
JavaScript
"use strict";var I=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var L=(r,e)=>{for(var s in e)I(r,s,{get:e[s],enumerable:!0})},G=(r,e,s,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of N(e))!H.call(r,i)&&i!==s&&I(r,i,{get:()=>e[i],enumerable:!(t=$(e,i))||t.enumerable});return r};var R=r=>G(I({},"__esModule",{value:!0}),r);var V={};L(V,{default:()=>b});module.exports=R(V);var U=require("obsidian");var g=require("obsidian"),P=[{trigger:"/campaign-seed",description:"Generate foundational campaign documents from a high-level concept",prompt:"Generate the foundational campaign documents from this concept. Create the campaign bible, world primer, pantheon sketch, faction sketch, and starting region overview. Use the campaign-seed skill. Concept:"},{trigger:"/region",description:"Build a detailed region with geography, settlements, and politics",prompt:"Build a detailed D&D region with geography, settlements, trade routes, political boundaries, faction presence, and adventure hooks. Use the region-builder skill. Context:"},{trigger:"/factions",description:"Generate a faction ecosystem with competing goals and built-in conflict",prompt:"Generate a faction ecosystem \u2014 3-5 factions with competing goals, full profiles, conflict matrix, and hooks. Every faction should conflict with at least one other. Use the faction-ecosystem skill. Context:"},{trigger:"/starting-town",description:"Build a detailed starting settlement with NPCs, hooks, and regional ties",prompt:"Build a detailed starting settlement for the campaign. Generate districts, named NPCs with relationships, quest hooks, a rumor table, faction presence, and an opening scene with read-aloud text. Use the starting-town skill. Context:"},{trigger:"/pantheon",description:"Design a full pantheon with deities, institutions, and folk practices",prompt:"Design a full pantheon for the campaign. Generate deity profiles with domains, symbols, worship practices, clergy, holy days, and hooks. Include religious institutions, folk religion, and divine conflict. Use the pantheon-builder skill. Context:"},{trigger:"/arc-design",description:"Design a multi-arc campaign skeleton with major decision points",prompt:"Design a multi-arc campaign skeleton. Generate a phase map with 3-5 arcs, each with themes, must-resolve beats, decision points, character arc pressure, and estimated session counts. Use the campaign-arc-designer skill. Context:"},{trigger:"/session-zero",description:"Build session zero agenda and player-facing campaign primer",prompt:"Build session zero materials. Generate a player-facing campaign primer with world overview, character creation guidance, hooks, and content boundaries. Include a session zero agenda with time estimates and discussion goals. Use the session-zero-builder skill. Context:"},{trigger:"/threads",description:"Crawl the campaign wiki for unresolved plot threads",prompt:"Crawl the campaign wiki for unresolved plot threads relevant to the next session. Cross-reference current party location, active PCs, and open story hooks. Rank by narrative urgency and suggest specific integration points."},{trigger:"/npc",description:"Generate a detailed NPC with full backstory, beliefs, and ties",prompt:"Generate a detailed D&D NPC with full backstory, core beliefs, motivations, ties, a secret, and a voice note. Use the npc-generator skill in detailed mode. Context:"},{trigger:"/npc-fast",description:"Quick NPC \u2014 name, race, age, description only (mid-session)",prompt:"Generate a quick D&D NPC \u2014 just name, race, age range, and 3 bullet descriptions. Use the npc-generator skill in fast mode. Context:"},{trigger:"/location",description:"Generate a detailed location with atmosphere, features, and wiki ties",prompt:"Generate a detailed D&D location with atmosphere, notable features, potential encounters, and wiki connections. Use the location-generator skill in detailed mode. Context:"},{trigger:"/location-fast",description:"Quick location \u2014 name, vibe, one interesting detail (mid-session)",prompt:"Generate a quick D&D location \u2014 just name, type, 3-sentence atmosphere, and one notable detail. Use the location-generator skill in fast mode. Context:"},{trigger:"/scene",description:"Generate atmospheric read-aloud text for a D&D scene",prompt:"Generate atmospheric read-aloud text for this D&D scene. Pull details from the campaign wiki if the location exists there. Use the scene-setter skill. Context:"},{trigger:"/relations",description:"Map all wiki-documented relationships for an NPC",prompt:"Map all wiki-documented relationships, connections, session appearances, and faction ties for this campaign NPC. Use the relation-mapper skill. NPC:"},{trigger:"/hook",description:"Generate quest hooks tied to existing campaign threads",prompt:"Generate 2-3 quest hooks tied to existing campaign wiki threads. Every hook must have a documented source. Use the hook-generator skill. Context:"},{trigger:"/encounter",description:"Build a themed encounter with creatures, hazards, and wiki ties",prompt:"Build a thematically appropriate D&D encounter with creatures, environmental features, and a wiki connection. Include multiple resolution paths. Use the encounter-builder skill. Context:"},{trigger:"/loot",description:"Generate themed treasure \u2014 coins, items, and a signature piece with a story hook",prompt:"Generate D&D treasure scaled to party level and themed to the context. Include coin, 1-2 items, and one signature item with a story hook. Use the loot-generator skill. Context:"},{trigger:"/lint",description:"Scan the campaign wiki for lore inconsistencies and stale data",prompt:"Scan the campaign wiki for lore inconsistencies \u2014 temporal contradictions, spatial impossibilities, one-way relationships, factual conflicts, orphaned entities, stale records, and dead plot threads. Flag issues for GM resolution. Use the lore-lint skill. Scope:"},{trigger:"/prep-session",description:"Prep the next D&D session",prompt:"Run the full session-prep pipeline for the next SKT session: scan recent session notes, identify loose threads, generate a session guide with modular flow-chart sections."},{trigger:"/sync-content",description:"Sync Content Sink notes to vault",prompt:"/run content-sink-sync"},{trigger:"/lint-wiki",description:"[Legacy] Scan the campaign wiki (use /lint instead)",prompt:"Scan the campaign wiki for lore inconsistencies and stale data. Use the lore-lint skill. Scope:"}],M={gatewayUrl:"http://192.168.1.12:8642/v1",apiKey:"0f224b188b52e8728d135ec339f8db8dfbf82d89a60021dcfe20d91c6174cf9b",showModelInfo:!0,enableContextInjection:!0,chatFontSize:14,customCommands:[],chatMessages:[],chatSessionId:""},x=class extends g.PluginSettingTab{plugin;constructor(e,s){super(e,s),this.plugin=s}display(){let{containerEl:e}=this;e.empty(),e.createEl("h2",{text:"Hermes Chat Settings"}),new g.Setting(e).setName("Gateway URL").setDesc("Base URL of your Hermes Gateway API server (e.g. http://192.168.1.12:8642/v1)").addText(i=>i.setPlaceholder("http://192.168.1.12:8642/v1").setValue(this.plugin.settings.gatewayUrl).onChange(async n=>{this.plugin.settings.gatewayUrl=n,await this.plugin.saveData(this.plugin.settings)})),new g.Setting(e).setName("API Key").setDesc("API key for authenticating with the Hermes Gateway").addText(i=>i.setPlaceholder("Enter your API key").setValue(this.plugin.settings.apiKey).onChange(async n=>{this.plugin.settings.apiKey=n,await this.plugin.saveData(this.plugin.settings)})),new g.Setting(e).setName("Show model info").setDesc("Display the current model name in the status bar").addToggle(i=>i.setValue(this.plugin.settings.showModelInfo).onChange(async n=>{this.plugin.settings.showModelInfo=n,await this.plugin.saveData(this.plugin.settings)})),new g.Setting(e).setName("Enable context injection").setDesc("Automatically send the active note as context with each message").addToggle(i=>i.setValue(this.plugin.settings.enableContextInjection).onChange(async n=>{this.plugin.settings.enableContextInjection=n,await this.plugin.saveData(this.plugin.settings)})),new g.Setting(e).setName("Chat font size").setDesc("Font size for chat messages and input (10\u201424 px)").addSlider(i=>i.setLimits(10,24,1).setValue(this.plugin.settings.chatFontSize).setDynamicTooltip().onChange(async n=>{this.plugin.settings.chatFontSize=n,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Slash Commands"}),e.createEl("p",{text:"Type / in the chat input to see available commands. Built-in: /prep-session, /sync-content, /lint-wiki. Add custom commands below as JSON."}),e.createDiv("setting-item-description").setText('Format: [{"trigger":"/my-cmd","description":"What it does","prompt":"Full prompt text..."}]');let t=e.createEl("textarea");t.setAttribute("rows","6"),t.style.width="100%",t.style.fontFamily="monospace",t.style.fontSize="12px",t.value=JSON.stringify(this.plugin.settings.customCommands,null,2),t.addEventListener("change",async()=>{try{let i=JSON.parse(t.value);Array.isArray(i)&&(this.plugin.settings.customCommands=i,await this.plugin.saveData(this.plugin.settings))}catch{}})}};var m=require("obsidian"),d="hermes-chat-view",w=class extends m.ItemView{apiClient=null;contextBridge=null;persistence=null;chatState;messagesContainer=null;statusBar=null;loadingEl=null;textarea=null;sendButton=null;_restoring=!1;_chatFontSize=14;capturedNote=null;slashCommands=[];suggestEl=null;suggestIndex=-1;filteredCommands=[];constructor(e,s,t,i){super(e),this.apiClient=s??null,this.contextBridge=t??null,this.persistence=i??null,this.chatState={sessionId:null,messages:[],isLoading:!1,model:"hermes-agent",contextActive:!1}}getViewType(){return d}getDisplayText(){return"Hermes"}async onOpen(){let e=this.containerEl.children[1];e.empty(),e.addClass("hermes-chat-container"),this.setChatFontSize(this._chatFontSize),this.messagesContainer=e.createDiv("chat-messages"),this.messagesContainer.id="chat-messages",this.containerEl.addEventListener("focusin",()=>{this.contextBridge&&(this.capturedNote=this.contextBridge.snapshot())}),this.registerEvent(this.app.workspace.on("active-leaf-change",t=>{t?.view instanceof m.MarkdownView&&this.contextBridge&&(this.capturedNote=this.contextBridge.snapshot())})),this.loadingEl=this.messagesContainer.createDiv("chat-loading"),this.loadingEl.setText("Thinking\u2026"),this.loadingEl.style.display="none";let s=e.createDiv("chat-input-area");if(this.textarea=s.createEl("textarea"),this.textarea.placeholder="Type your message\u2026",this.textarea.setAttribute("rows","1"),this.textarea.addEventListener("keydown",t=>{if(this.suggestEl&&this.suggestEl.style.display!=="none"){if(t.key==="ArrowDown"){t.preventDefault(),this.suggestMove(1);return}if(t.key==="ArrowUp"){t.preventDefault(),this.suggestMove(-1);return}if(t.key==="Enter"&&!t.shiftKey){t.preventDefault(),this.suggestIndex>=0&&this.suggestIndex<this.filteredCommands.length?this.suggestSelect(this.filteredCommands[this.suggestIndex]):this.suggestClose();return}if(t.key==="Escape"){t.preventDefault(),this.suggestClose();return}if(t.key==="Tab"){t.preventDefault(),this.suggestIndex>=0&&this.suggestIndex<this.filteredCommands.length&&this.suggestSelect(this.filteredCommands[this.suggestIndex]);return}}t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),this.handleSend())}),this.textarea.addEventListener("input",()=>{this.checkSlashTrigger()}),this.sendButton=s.createEl("button"),this.sendButton.setText("Send"),this.sendButton.addEventListener("click",()=>this.handleSend()),this.suggestEl=e.createDiv("hermes-slash-suggest"),this.suggestEl.style.display="none",this.suggestEl.style.position="absolute",this.suggestEl.style.zIndex="1000",this.statusBar=e.createDiv("chat-status-bar"),this.updateStatus(this.chatState.model,null),this.persistence){let t=this.persistence.loadMessages();if(console.log("[Hermes] Restoring messages \u2014 count:",t?.length??0),t&&t.length>0){this._restoring=!0;try{for(let i of t)await this.appendMessage(i.role,i.content);console.log("[Hermes] Restored",t.length,"messages successfully")}catch(i){console.error("[Hermes] Failed to restore messages:",i)}finally{this._restoring=!1}await this.persistence.saveMessages(this.chatState.messages)}}}async onClose(){console.log("[Hermes] onClose \u2014 saving",this.chatState.messages.length,"messages"),await this.persistence?.saveMessages(this.chatState.messages)}setApiClient(e){this.apiClient=e}setContextActive(e){this.chatState.contextActive=e}setSlashCommands(e){this.slashCommands=e}setChatFontSize(e){this._chatFontSize=e;let s=this.containerEl.querySelector(".hermes-chat-container");s&&s.style.setProperty("--hermes-chat-font-size",`${e}px`)}async appendMessage(e,s){if(!this.messagesContainer)return;let t={id:`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,role:e,content:s,timestamp:Date.now()};this.chatState.messages.push(t);let i=this.messagesContainer.createDiv("chat-message");i.addClass(`chat-message-${e}`),i.createDiv("chat-message-role").setText(e==="user"?"You":e==="assistant"?"Hermes":"System");let a=i.createDiv("chat-message-content");await m.MarkdownRenderer.render(this.app,s,a,"",this),this.scrollToBottom()}setLoading(e){this.chatState.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none"),this.textarea&&(this.textarea.disabled=e),this.sendButton&&(this.sendButton.disabled=e)}updateStatus(e,s){if(this.chatState.model=e,this.chatState.sessionId=s,this.statusBar){let t=s?`Session: ${s}`:"Session: \u2014";this.statusBar.setText(`Model: ${e} | ${t}`)}}clearChat(){if(!this.messagesContainer)return;let e=Array.from(this.messagesContainer.children);for(let s of e)s!==this.loadingEl&&s.remove();this.chatState.messages=[]}scrollToBottom(){this.messagesContainer&&(this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight)}refreshVault(){try{this.app.vault.trigger("resolved"),console.log("[Hermes] Vault refresh triggered")}catch(e){console.error("[Hermes] Vault refresh failed:",e)}}checkSlashTrigger(){if(!this.textarea)return;let e=this.textarea.value,s=this.textarea.selectionStart,t=s-1;for(;t>=0&&e[t]!==" "&&e[t]!==`
|
|
`;)t--;t++;let i=e.slice(t,s);if(i.startsWith("/")&&(t===0||e[t-1]===" "||e[t-1]===`
|
|
`)){let n=i.slice(1).toLowerCase();if(this.filteredCommands=this.slashCommands.filter(a=>a.trigger.toLowerCase().includes(n)||a.description.toLowerCase().includes(n)),this.filteredCommands.length>0){this.suggestShow();return}}this.suggestClose()}suggestShow(){if(!this.suggestEl||!this.textarea)return;this.suggestIndex=-1,this.suggestEl.empty();for(let t=0;t<this.filteredCommands.length;t++){let i=this.filteredCommands[t],n=this.suggestEl.createDiv("hermes-slash-item");n.createSpan("hermes-slash-trigger").setText(i.trigger),n.createSpan("hermes-slash-desc").setText(i.description),n.addEventListener("click",()=>this.suggestSelect(i)),n.addEventListener("mouseenter",()=>{this.suggestIndex=t,this.suggestHighlight()})}let e=this.textarea.getBoundingClientRect(),s=this.containerEl.getBoundingClientRect();this.suggestEl.style.left=`${e.left-s.left}px`,this.suggestEl.style.top=`${e.bottom-s.top}px`,this.suggestEl.style.width=`${e.width}px`,this.suggestEl.style.display="block"}suggestClose(){this.suggestEl&&(this.suggestEl.style.display="none",this.suggestEl.empty()),this.suggestIndex=-1,this.filteredCommands=[]}suggestMove(e){this.filteredCommands.length!==0&&(this.suggestIndex+=e,this.suggestIndex<0&&(this.suggestIndex=this.filteredCommands.length-1),this.suggestIndex>=this.filteredCommands.length&&(this.suggestIndex=0),this.suggestHighlight())}suggestHighlight(){if(!this.suggestEl)return;this.suggestEl.querySelectorAll(".hermes-slash-item").forEach((s,t)=>{t===this.suggestIndex?s.addClass("hermes-slash-item-active"):s.removeClass("hermes-slash-item-active")})}suggestSelect(e){if(!this.textarea)return;let s=this.textarea.value,t=this.textarea.selectionStart,i=t-1;for(;i>=0&&s[i]!==" "&&s[i]!==`
|
|
`;)i--;i++;let n=s.slice(0,i),a=s.slice(t);this.textarea.value=n+e.prompt+a,this.suggestClose(),this.textarea.focus()}resolveSlashCommand(e){let s=e.trim();for(let t of this.slashCommands)if(s.startsWith(t.trigger))return t.prompt+s.slice(t.trigger.length);return e}async handleSend(){if(!this.textarea)return;let e=this.textarea.value.trim();if(!e)return;if(this.textarea.value="",e==="/refresh"){this.refreshVault(),await this.appendMessage("user","/refresh"),await this.appendMessage("assistant","Vault refreshed. File explorer should now reflect all changes.");return}let s=this.resolveSlashCommand(e);if(await this.appendMessage("user",s),!this.apiClient){await this.appendMessage("assistant","[API client not configured. Check plugin settings.]");return}this.setLoading(!0);let t=this.messagesContainer?.createDiv("chat-message chat-message-assistant"),i=t?.createDiv("chat-message-role");i&&i.setText("Hermes");let n=t?.createDiv("chat-message-content");n&&n.setText("");let a="";try{let h;if(this.chatState.contextActive&&this.capturedNote){let o=this.capturedNote;o.selection?h=[{role:"system",content:`[Selection from ${o.vault}/${o.path}]
|
|
|
|
${o.selection}`},{role:"user",content:s}]:h=[{role:"system",content:[`[Current note: ${o.vault}/${o.path}]`,`Use mcp_obsidian_get_vault_document(vault_name="${o.vault}", doc_path="${o.path}") to read the full contents.`].join(`
|
|
`)},{role:"user",content:s}]}else h=this.contextBridge?this.contextBridge.buildMessages(s,this.chatState.contextActive):[{role:"user",content:s}];let l=await this.apiClient.streamChat(h,o=>{a+=o,n&&n.setText(a),this.scrollToBottom()});n&&(n.empty(),await m.MarkdownRenderer.render(this.app,a,n,"",this));let p={id:`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,role:"assistant",content:a,timestamp:Date.now()};this.chatState.messages.push(p),l.sessionId&&(this.chatState.sessionId=l.sessionId,this.updateStatus(l.model,l.sessionId),await this.persistence?.saveSessionId(l.sessionId)),await this.persistence?.saveMessages(this.chatState.messages),this.refreshVault()}catch(h){n&&n.setText(`Error: ${h.message||"Unknown error"}`)}finally{this.setLoading(!1)}}};var y=class{baseUrl;apiKey;model;currentSessionId;constructor(e){this.baseUrl=e.baseUrl.replace(/\/+$/,""),this.apiKey=e.apiKey,this.model=e.model,this.currentSessionId=null}updateConfig(e){e.baseUrl!==void 0&&(this.baseUrl=e.baseUrl.replace(/\/+$/,"")),e.apiKey!==void 0&&(this.apiKey=e.apiKey),e.model!==void 0&&(this.model=e.model)}getSessionId(){return this.currentSessionId}setSessionId(e){this.currentSessionId=e||null}get rootUrl(){return this.baseUrl.endsWith("/v1")?this.baseUrl.slice(0,-3):new URL("/",this.baseUrl).href.replace(/\/+$/,"")}async fetchWithTimeout(e,s,t=6e4){let i=new AbortController,n=setTimeout(()=>i.abort(),t);try{return await fetch(e,{...s,signal:i.signal})}finally{clearTimeout(n)}}async extractErrorBody(e){let s="";if((e.headers.get("content-type")??"").includes("application/json"))try{let i=await e.json();if(i.error?.message?s=i.error.message:typeof i.message=="string"?s=i.message:typeof i.error=="string"&&(s=i.error),s)return s}catch{}try{let i=await e.text();if(i.trim())return s=i.trim().substring(0,300),s}catch{}return e.statusText||`HTTP ${e.status}`}async chat(e,s=!1){let t={Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"};this.currentSessionId&&(t["X-Hermes-Session-Id"]=this.currentSessionId),console.log("[Hermes API] POST",`${this.baseUrl}/chat/completions`,"| model:",this.model,"| msgs:",e.length,"| session:",this.currentSessionId?this.currentSessionId.slice(0,8)+"...":"(none)");let i=await this.fetchWithTimeout(`${this.baseUrl}/chat/completions`,{method:"POST",headers:t,body:JSON.stringify({model:this.model,messages:e,stream:s})});if(!i.ok){let p=await this.extractErrorBody(i);throw new Error(`API error ${i.status}: ${p}`)}let n=i.headers.get("X-Hermes-Session-Id");n&&(this.currentSessionId=n);let a=await i.json();if(a.error)throw new Error(a.error.message||"Unknown API error");return{content:a.choices?.[0]?.message?.content??"",sessionId:this.currentSessionId??"",model:a.model??this.model,usage:a.usage}}async streamChat(e,s){let t={Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"};this.currentSessionId&&(t["X-Hermes-Session-Id"]=this.currentSessionId),console.log("[Hermes API] POST",`${this.baseUrl}/chat/completions`,"| model:",this.model,"| msgs:",e.length,"| session:",this.currentSessionId?this.currentSessionId.slice(0,8)+"...":"(none)");let i=await this.fetchWithTimeout(`${this.baseUrl}/chat/completions`,{method:"POST",headers:t,body:JSON.stringify({model:this.model,messages:e,stream:!0})});if(!i.ok){let u=await this.extractErrorBody(i);throw new Error(`API error ${i.status}: ${u}`)}let n=i.headers.get("X-Hermes-Session-Id");n&&(this.currentSessionId=n,console.log("[Hermes API] New session:",n.slice(0,8)+"..."));let a=i.body?.getReader();if(!a)throw new Error("Response body is not readable");let h=new TextDecoder("utf-8"),l="",p="",o=this.model,E;for(;;){let{done:u,value:C}=await a.read();if(u)break;l+=h.decode(C,{stream:!0});let f=l.split(`
|
|
|
|
`);l=f.pop()??"";for(let T of f){let v=T.split(`
|
|
`);for(let D of v){if(!D.startsWith("data: "))continue;let B=D.slice(6).trim();if(B!=="[DONE]")try{let c=JSON.parse(B);if(c.error)throw new Error(c.error.message||"Stream error");let k=c.choices?.[0]?.delta?.content;k&&(p+=k,s(k)),c.model&&(o=c.model),c.usage&&(E=c.usage)}catch(c){if(c instanceof Error&&c.message!=="Unexpected token"&&!c.message.includes("JSON"))throw c}}}}if(l.trim()){let u=l.split(`
|
|
`);for(let C of u){if(!C.startsWith("data: "))continue;let f=C.slice(6).trim();if(f!=="[DONE]")try{let v=JSON.parse(f).choices?.[0]?.delta?.content;v&&(p+=v,s(v))}catch{}}}return{content:p,sessionId:this.currentSessionId??"",model:o,usage:E}}async getModels(){let e=await this.fetchWithTimeout(`${this.baseUrl}/models`,{headers:{Authorization:`Bearer ${this.apiKey}`}});if(!e.ok){let t=await this.extractErrorBody(e);throw new Error(`Failed to fetch models: ${e.status} \u2014 ${t}`)}return(await e.json()).data??[]}async getCapabilities(){let e=await this.fetchWithTimeout(`${this.baseUrl}/capabilities`,{headers:{Authorization:`Bearer ${this.apiKey}`}});if(!e.ok){let s=await this.extractErrorBody(e);throw new Error(`Failed to fetch capabilities: ${e.status} \u2014 ${s}`)}return e.json()}async healthCheck(){try{let e=await this.fetchWithTimeout(`${this.rootUrl}/health`,{},1e4);return e.ok?(await e.json()).status==="ok":!1}catch{return!1}}};var A=require("obsidian"),S=class{app;constructor(e){this.app=e}getActiveNoteContext(){let e=this.app.workspace.activeEditor;if(!e||!e.editor)return null;let s=this.app.workspace.activeLeaf;if(!s||!(s.view instanceof A.MarkdownView))return null;let t=s.view.file;return t?{vault:this.app.vault.getName(),path:t.path,title:t.basename}:null}snapshot(){let e=this.getActiveNoteContext();return e?{...e,selection:this.getSelectionContext()}:null}getSelectionContext(){let e=this.app.workspace.activeEditor;return!e||!e.editor?null:e.editor.getSelection()||null}formatContextMessage(e){return{role:"system",content:[`[Current note: ${e.vault}/${e.path}]`,`Use mcp_obsidian_get_vault_document(vault_name="${e.vault}", doc_path="${e.path}") to read the full contents.`].join(`
|
|
`)}}buildMessages(e,s){let t=[];if(s){let i=this.getSelectionContext();if(i){let n=this.getActiveNoteContext(),a=n?`${n.vault}/${n.path}`:"current note";t.push({role:"system",content:`[Selection from ${a}]
|
|
|
|
${i}`})}else{let n=this.getActiveNoteContext();n&&t.push(this.formatContextMessage(n))}}return t.push({role:"user",content:e}),t}};var b=class extends U.Plugin{settings;statusBarItem=null;contextBridge=null;async onload(){await this.loadSettings(),this.registerView(d,e=>{let s=new y(this.getGatewayConfig()),t={loadMessages:()=>this.settings.chatMessages,saveMessages:async n=>{this.settings.chatMessages=n,await this.saveData(this.settings)},loadSessionId:()=>this.settings.chatSessionId??"",saveSessionId:async n=>{this.settings.chatSessionId=n}},i=new w(e,s,this.contextBridge,t);return i.setContextActive(this.settings.enableContextInjection),i.setSlashCommands(this.getAllCommands()),i.setChatFontSize(this.settings.chatFontSize),this.settings.chatSessionId?(s.setSessionId(this.settings.chatSessionId),i.updateStatus("hermes-agent",this.settings.chatSessionId),console.log("[Hermes] Restored session:",this.settings.chatSessionId.slice(0,8)+"...")):console.log("[Hermes] No saved session \u2014 starting fresh"),i}),this.addSettingTab(new x(this.app,this)),this.addRibbonIcon("message-square","Open Hermes Chat",()=>{this.activateView()}),this.settings.showModelInfo&&(this.statusBarItem=this.addStatusBarItem(),this.statusBarItem.setText("Hermes: connecting...")),this.contextBridge=new S(this.app),this.addCommand({id:"open-hermes-chat",name:"Open Hermes Chat",callback:()=>{this.activateView()}}),this.addCommand({id:"open-hermes-chat-new-tab",name:"Open Hermes Chat in New Tab",callback:()=>{this.openNewTab()}}),this.addCommand({id:"send-note-as-context",name:"Send Current Note as Context",callback:()=>{let e=this.contextBridge?.getActiveNoteContext();e?(this.activateView(),console.log(`Context ready: vault=${e.vault}, path=${e.path}`)):console.log("No active note to send as context")}}),this.statusBarItem&&(this.statusBarItem.setText("Hermes: checking..."),new y(this.getGatewayConfig()).healthCheck().then(s=>{this.statusBarItem&&this.statusBarItem.setText(s?"Hermes: connected":"Hermes: unreachable")}))}async onunload(){this.app.workspace.detachLeavesOfType(d)}async activateView(){let{workspace:e}=this.app,s=e.getLeavesOfType(d);if(s.length>0){e.revealLeaf(s[0]);return}let t=e.getRightLeaf(!1);t&&(await t.setViewState({type:d,active:!0}),e.revealLeaf(t))}async openNewTab(){let e=this.app.workspace.getRightLeaf(!1);e&&(await e.setViewState({type:d,active:!0}),this.app.workspace.revealLeaf(e))}getGatewayConfig(){return{baseUrl:this.settings.gatewayUrl,apiKey:this.settings.apiKey,model:"hermes-agent"}}async loadSettings(){this.settings=Object.assign({},M,await this.loadData())}async saveSettings(){await this.saveData(this.settings),this.syncSettingsToViews()}syncSettingsToViews(){let e=this.app.workspace.getLeavesOfType(d),s=this.getAllCommands();for(let t of e)t.view instanceof w&&(t.view.setContextActive(this.settings.enableContextInjection),t.view.setSlashCommands(s),t.view.setChatFontSize(this.settings.chatFontSize))}getAllCommands(){return[...P,...this.settings.customCommands]}};
|