-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmain.js
More file actions
12 lines (12 loc) · 12.5 KB
/
Copy pathmain.js
File metadata and controls
12 lines (12 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
/* OriginTrail Shared Memory for Obsidian */
var y=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var $=Object.prototype.hasOwnProperty;var M=(i,t)=>{for(var e in t)y(i,e,{get:t[e],enumerable:!0})},N=(i,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of D(t))!$.call(i,s)&&s!==e&&y(i,s,{get:()=>t[s],enumerable:!(n=G(t,s))||n.enumerable});return i};var I=i=>N(y({},"__esModule",{value:!0}),i);var E={};M(E,{default:()=>m});module.exports=I(E);var c=require("obsidian");var d=class{constructor(t,e,n){this.baseUrl=t;this.authToken=e;this.request=n}async status(){return this.json("GET","/api/status")}async identity(){return this.json("GET","/api/agent/identity")}async listContextGraphs(){let t=await this.json("GET","/api/context-graph/list");return(Array.isArray(t)?t:t.contextGraphs??t.graphs??[]).map(n=>({id:String(n.id??n.contextGraphId??n.context_graph_id??""),name:String(n.name??n.displayName??n.id??n.contextGraphId??""),subscribed:n.subscribed,synced:n.synced})).filter(n=>n.id.length>0)}async createContextGraph(t,e){return this.json("POST","/api/context-graph/create",{id:t,name:e,description:`Obsidian vault project for ${e}`,accessPolicy:1})}async ensureContextGraph(t,e){let s=(await this.listContextGraphs().catch(()=>[])).find(r=>r.id===t||r.name===e);if(s)return s;try{await this.createContextGraph(t,e)}catch(r){let a=r instanceof Error?r.message:String(r);if(!/409|conflict|already/i.test(a))throw r}return(await this.listContextGraphs().catch(()=>[])).find(r=>r.id===t||r.name===e)??{id:t,name:e}}async createAssertion(t,e){return this.json("POST","/api/assertion/create",{contextGraphId:t,name:e})}async importMarkdown(t,e,n,s){let o=`----obsidian-origintrail-${Date.now()}-${Math.random().toString(16).slice(2)}`,r=this.multipartBody(o,{contextGraphId:t,contentType:"text/markdown"},{fieldName:"file",fileName:n,contentType:"text/markdown; charset=utf-8",content:s});return this.rawJson("POST",`/api/assertion/${encodeURIComponent(e)}/import-file`,r,{"Content-Type":`multipart/form-data; boundary=${o}`})}async extractionStatus(t,e){let n=`contextGraphId=${encodeURIComponent(t)}`;return this.json("GET",`/api/assertion/${encodeURIComponent(e)}/extraction-status?${n}`)}async promoteAssertion(t,e){return this.json("POST",`/api/assertion/${encodeURIComponent(e)}/promote`,{contextGraphId:t,entities:"all"})}async json(t,e,n){return this.rawJson(t,e,n===void 0?void 0:JSON.stringify(n),{"Content-Type":"application/json"})}async rawJson(t,e,n,s={}){let o={...s},r=this.authToken.trim();r&&(o.Authorization=`Bearer ${r}`);let a=await this.request({url:this.url(e),method:t,headers:o,body:n,throw:!1});if(a.status<200||a.status>=300){let u=typeof a.text=="string"?a.text:JSON.stringify(a.json??"");throw new Error(`DKG ${t} ${e} failed (${a.status}): ${u.slice(0,500)}`)}if(a.json!==void 0&&a.json!==null)return a.json;if(!a.text)return{};try{return JSON.parse(a.text)}catch{return a.text}}url(t){return`${this.baseUrl.replace(/\/+$/,"")}${t.startsWith("/")?t:`/${t}`}`}multipartBody(t,e,n){let s=[];for(let[o,r]of Object.entries(e))s.push(`--${t}\r
Content-Disposition: form-data; name="${w(o)}"\r
\r
${r}\r
`);return s.push(`--${t}\r
Content-Disposition: form-data; name="${w(n.fieldName)}"; filename="${w(n.fileName)}"\r
Content-Type: ${n.contentType}\r
\r
${n.content}\r
`),s.push(`--${t}--\r
`),s.join("")}};function w(i){return i.replace(/["\r\n]/g,"_")}function k(i){return i.trim().toLowerCase().replace(/['"`]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"obsidian-vault"}async function j(i){let t=new TextEncoder().encode(i),e=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(e)).map(n=>n.toString(16).padStart(2,"0")).join("")}function A(i){return i.replace(/\\/g,"/").replace(/^\/+/,"")}async function P(i,t,e){let n=A(t),s=await j(`${i}:${n}:${e}`),o=new Date().toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"Z");return`obsidian-note-${s.slice(0,16)}-${o}`}function C(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`vault-${Date.now()}-${Math.random().toString(16).slice(2)}`}function g(i){return i.startsWith(".obsidian/")||i.startsWith(".trash/")||i.includes("/.trash/")}async function f(i,t,e,n,s,o){let r=await i.vault.read(s),a=await P(n,s.path,r);await t.createAssertion(e,a);let u=await t.importMarkdown(e,a,s.name,r),p=u?.extraction?.tripleCount;if(u?.extraction?.status==="in_progress"){let T=await U(t,e,a);p=T?.tripleCount??T?.extraction?.tripleCount??p}return o?(await t.promoteAssertion(e,a),{filePath:s.path,assertionName:a,status:"promoted",tripleCount:p}):{filePath:s.path,assertionName:a,status:"imported",tripleCount:p}}async function v(i,t,e,n,s,o){let r=i.vault.getMarkdownFiles().filter(u=>!g(u.path)),a=[];for(let u of r)o?.(a.length,r.length,u),a.push(await f(i,t,e,n,u,s));return a}async function U(i,t,e){for(let n=0;n<20;n++){await O(750);let s=await i.extractionStatus(t,e),o=s?.status??s?.extraction?.status;if(o==="completed"||o==="failed"||o==="skipped")return s}return{}}function O(i){return new Promise(t=>setTimeout(t,i))}var l=require("obsidian"),h=class extends l.PluginSettingTab{constructor(e,n){super(e,n);this.plugin=n}display(){let{containerEl:e}=this;e.empty(),e.createEl("h2",{text:"OriginTrail Shared Memory"}),e.createEl("p",{text:"Connect this vault to an OriginTrail DKG v10 Project. Notes are imported into Working Memory first; Shared Memory promotion is optional."}).addClass("origintrail-sm-muted"),new l.Setting(e).setName("DKG node URL").setDesc("Local DKG node API base URL.").addText(n=>n.setPlaceholder("http://127.0.0.1:9200").setValue(this.plugin.settings.dkgNodeUrl).onChange(async s=>{this.plugin.settings.dkgNodeUrl=s.trim(),await this.plugin.saveSettings()})),new l.Setting(e).setName("Auth token").setDesc("Bearer token for the local DKG node. Stored only in this vault's plugin data.json.").addText(n=>{n.inputEl.type="password",n.setPlaceholder("Paste DKG auth token").setValue(this.plugin.settings.authToken).onChange(async s=>{this.plugin.settings.authToken=s.trim(),await this.plugin.saveSettings()})}),new l.Setting(e).setName("Current DKG Project").setDesc(this.plugin.settings.defaultContextGraphId||"No project linked yet. Use the vault-first command below.").addText(n=>n.setPlaceholder("context graph id").setValue(this.plugin.settings.defaultContextGraphId).onChange(async s=>{this.plugin.settings.defaultContextGraphId=s.trim(),await this.plugin.saveSettings(),this.plugin.updateStatusBar()})),new l.Setting(e).setName("Power up this vault with OriginTrail Shared Memory").setDesc("Creates/links an OriginTrail DKG Project using this vault name, then imports all Markdown notes into Working Memory.").addButton(n=>n.setButtonText("Power up vault").setCta().onClick(()=>this.plugin.createProjectFromVaultAndSyncNotes())),new l.Setting(e).setName("Test DKG connection").setDesc("Checks /api/status and /api/agent/identity with the current settings.").addButton(n=>n.setButtonText("Test").onClick(()=>this.plugin.testConnection())),new l.Setting(e).setName("Auto-sync saved notes").setDesc("When enabled, saved Markdown notes are imported into DKG Working Memory for the linked Project.").addToggle(n=>n.setValue(this.plugin.settings.autoSync).onChange(async s=>{this.plugin.settings.autoSync=s,await this.plugin.saveSettings(),this.plugin.updateStatusBar()})),new l.Setting(e).setName("Promote saved notes to Shared Memory").setDesc("Optional. Leave off during early testing; when enabled, synced notes are promoted from Working Memory to Shared Memory.").addToggle(n=>n.setValue(this.plugin.settings.autoPromote).onChange(async s=>{this.plugin.settings.autoPromote=s,await this.plugin.saveSettings(),this.plugin.updateStatusBar()})),new l.Setting(e).setName("Auto-sync debounce").setDesc("Milliseconds to wait after a note is modified before syncing.").addText(n=>n.setPlaceholder("1500").setValue(String(this.plugin.settings.syncDebounceMs)).onChange(async s=>{let o=Number(s);Number.isFinite(o)&&o>=250&&(this.plugin.settings.syncDebounceMs=o,await this.plugin.saveSettings())}))}};var b={dkgNodeUrl:"http://127.0.0.1:9200",authToken:"",defaultContextGraphId:"",autoSync:!0,autoPromote:!1,syncDebounceMs:1500,vaultId:"",hasSeenPowerUpPrompt:!1};var m=class extends c.Plugin{settings;statusBarEl;pendingSyncTimers=new Map;async onload(){await this.loadSettings(),this.statusBarEl=this.addStatusBarItem(),this.statusBarEl.addClass("origintrail-sm-status"),this.updateStatusBar(),this.addSettingTab(new h(this.app,this)),this.addCommand({id:"test-dkg-connection",name:"Test DKG connection",callback:()=>this.testConnection()}),this.addCommand({id:"create-project-from-current-vault-and-sync-notes",name:"Power up current vault with OriginTrail Shared Memory",callback:()=>this.createProjectFromVaultAndSyncNotes()}),this.addCommand({id:"sync-current-note-to-dkg-working-memory",name:"Sync current note to DKG Working Memory",checkCallback:t=>{let e=this.app.workspace.getActiveFile();return!e||e.extension!=="md"?!1:(t||this.syncFile(e),!0)}}),this.registerEvent(this.app.vault.on("modify",t=>{t instanceof c.TFile&&this.scheduleAutoSync(t)})),this.app.workspace.onLayoutReady(()=>this.maybeShowPowerUpPrompt())}onunload(){for(let t of this.pendingSyncTimers.values())window.clearTimeout(t);this.pendingSyncTimers.clear()}async loadSettings(){this.settings=Object.assign({},b,await this.loadData()),this.settings.vaultId||(this.settings.vaultId=C(),await this.saveSettings())}async saveSettings(){await this.saveData(this.settings)}client(){return new d(this.settings.dkgNodeUrl,this.settings.authToken,c.requestUrl)}updateStatusBar(){if(!this.statusBarEl)return;let t=this.settings.defaultContextGraphId||"unlinked",e=this.settings.autoPromote?"Shared Memory":"Working Memory",n=this.settings.autoSync?"auto-sync on":"auto-sync off";this.statusBarEl.setText(`DKG: ${t} \xB7 ${e} \xB7 ${n}`)}async testConnection(){try{let t=this.client();await t.status(),this.settings.authToken.trim()&&await t.identity(),new c.Notice("OriginTrail DKG connection OK")}catch(t){console.error(t),new c.Notice(`OriginTrail DKG connection failed: ${S(t)}`,1e4)}}async createProjectFromVaultAndSyncNotes(){let t=this.app.vault.getName(),e=k(t),n=this.client();try{new c.Notice(`Creating/linking DKG Project \u201C${t}\u201D\u2026`);let s=await n.ensureContextGraph(e,t);this.settings.defaultContextGraphId=s.id||e,this.settings.autoSync=!0,this.settings.hasSeenPowerUpPrompt=!0,await this.saveSettings(),this.updateStatusBar(),new c.Notice("Syncing Markdown notes to DKG Working Memory\u2026");let o=await v(this.app,n,this.settings.defaultContextGraphId,this.settings.vaultId,this.settings.autoPromote,(r,a,u)=>{(r===0||r%5===0)&&new c.Notice(`DKG sync ${r+1}/${a}: ${u.path}`,2500)});new c.Notice(`DKG Project linked: ${this.settings.defaultContextGraphId}. Synced ${o.length} notes to ${this.settings.autoPromote?"Shared Memory":"Working Memory"}.`,1e4)}catch(s){console.error(s),new c.Notice(`Create/sync failed: ${S(s)}`,12e3)}}async syncFile(t){if(!this.settings.defaultContextGraphId){new c.Notice("This vault is not powered up yet. Run \u201CPower up current vault with OriginTrail Shared Memory\u201D first.");return}if(!(t.extension!=="md"||g(t.path)))try{let e=await f(this.app,this.client(),this.settings.defaultContextGraphId,this.settings.vaultId,t,this.settings.autoPromote);new c.Notice(`DKG ${e.status}: ${t.path}`)}catch(e){console.error(e),new c.Notice(`DKG sync failed for ${t.path}: ${S(e)}`,1e4)}}scheduleAutoSync(t){if(!this.settings.autoSync||!this.settings.defaultContextGraphId||t.extension!=="md"||g(t.path))return;let e=this.pendingSyncTimers.get(t.path);e&&window.clearTimeout(e);let n=window.setTimeout(()=>{this.pendingSyncTimers.delete(t.path),this.syncFile(t)},this.settings.syncDebounceMs);this.pendingSyncTimers.set(t.path,n)}maybeShowPowerUpPrompt(){this.settings.defaultContextGraphId||this.settings.hasSeenPowerUpPrompt||new x(this).open()}},x=class extends c.Modal{constructor(e){super(e.app);this.plugin=e}onOpen(){let{contentEl:e}=this;e.empty(),e.createEl("h2",{text:"Power up this vault with OriginTrail Shared Memory"}),e.createEl("p",{text:"Create an OriginTrail DKG Project with this vault\u2019s name and sync Markdown notes into DKG Working Memory. Shared Memory promotion stays off until you enable it."}),new c.Setting(e).addButton(n=>n.setButtonText("Power up vault").setCta().onClick(async()=>{this.close(),await this.plugin.createProjectFromVaultAndSyncNotes()})).addButton(n=>n.setButtonText("Maybe later").onClick(async()=>{this.plugin.settings.hasSeenPowerUpPrompt=!0,await this.plugin.saveSettings(),this.close()}))}onClose(){this.contentEl.empty()}};function S(i){return i instanceof Error?i.message:String(i)}