/ releases / chrome-mv3 / background.js
background.js
  1  var background=function(){"use strict";var co=Object.defineProperty;var lo=(Ie,pe,Ee)=>pe in Ie?co(Ie,pe,{enumerable:!0,configurable:!0,writable:!0,value:Ee}):Ie[pe]=Ee;var M=(Ie,pe,Ee)=>lo(Ie,typeof pe!="symbol"?pe+"":pe,Ee);var Ie=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function pe(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}var Ee={exports:{}};(function(r,e){(function(t,n){n(r)})(typeof globalThis<"u"?globalThis:typeof self<"u"?self:Ie,function(t){if(!(globalThis.chrome&&globalThis.chrome.runtime&&globalThis.chrome.runtime.id))throw new Error("This script should only be loaded in a browser extension.");if(globalThis.browser&&globalThis.browser.runtime&&globalThis.browser.runtime.id)t.exports=globalThis.browser;else{const n="The message port closed before a response was received.",s=a=>{const o={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getSubTree:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{disable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},enable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},openPopup:{minArgs:0,maxArgs:0},setBadgeBackgroundColor:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setBadgeText:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},browsingData:{remove:{minArgs:2,maxArgs:2},removeCache:{minArgs:1,maxArgs:1},removeCookies:{minArgs:1,maxArgs:1},removeDownloads:{minArgs:1,maxArgs:1},removeFormData:{minArgs:1,maxArgs:1},removeHistory:{minArgs:1,maxArgs:1},removeLocalStorage:{minArgs:1,maxArgs:1},removePasswords:{minArgs:1,maxArgs:1},removePluginData:{minArgs:1,maxArgs:1},settings:{minArgs:0,maxArgs:0}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2,singleCallbackArg:!1}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0},elements:{createSidebarPane:{minArgs:1,maxArgs:1}}}},downloads:{cancel:{minArgs:1,maxArgs:1},download:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},identity:{launchWebAuthFlow:{minArgs:1,maxArgs:1}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},setEnabled:{minArgs:2,maxArgs:2},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},permissions:{contains:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},request:{minArgs:1,maxArgs:1}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},sessions:{getDevices:{minArgs:0,maxArgs:1},getRecentlyClosed:{minArgs:0,maxArgs:1},restore:{minArgs:0,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{captureVisibleTab:{minArgs:0,maxArgs:2},create:{minArgs:1,maxArgs:1},detectLanguage:{minArgs:0,maxArgs:1},discard:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},goBack:{minArgs:0,maxArgs:1},goForward:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},query:{minArgs:1,maxArgs:1},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},topSites:{get:{minArgs:0,maxArgs:0}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(Object.keys(o).length===0)throw new Error("api-metadata.json has not been included in browser-polyfill");class i extends WeakMap{constructor(A,P=void 0){super(P),this.createItem=A}get(A){return this.has(A)||this.set(A,this.createItem(A)),super.get(A)}}const l=T=>T&&typeof T=="object"&&typeof T.then=="function",d=(T,A)=>(...P)=>{a.runtime.lastError?T.reject(new Error(a.runtime.lastError.message)):A.singleCallbackArg||P.length<=1&&A.singleCallbackArg!==!1?T.resolve(P[0]):T.resolve(P)},u=T=>T==1?"argument":"arguments",m=(T,A)=>function(N,...J){if(J.length<A.minArgs)throw new Error(`Expected at least ${A.minArgs} ${u(A.minArgs)} for ${T}(), got ${J.length}`);if(J.length>A.maxArgs)throw new Error(`Expected at most ${A.maxArgs} ${u(A.maxArgs)} for ${T}(), got ${J.length}`);return new Promise((re,se)=>{if(A.fallbackToNoCallback)try{N[T](...J,d({resolve:re,reject:se},A))}catch(v){console.warn(`${T} API method doesn't seem to support the callback parameter, falling back to call it without a callback: `,v),N[T](...J),A.fallbackToNoCallback=!1,A.noCallback=!0,re()}else A.noCallback?(N[T](...J),re()):N[T](...J,d({resolve:re,reject:se},A))})},h=(T,A,P)=>new Proxy(A,{apply(N,J,re){return P.call(J,T,...re)}});let k=Function.call.bind(Object.prototype.hasOwnProperty);const E=(T,A={},P={})=>{let N=Object.create(null),J={has(se,v){return v in T||v in N},get(se,v,Q){if(v in N)return N[v];if(!(v in T))return;let G=T[v];if(typeof G=="function")if(typeof A[v]=="function")G=h(T,T[v],A[v]);else if(k(P,v)){let we=m(v,P[v]);G=h(T,T[v],we)}else G=G.bind(T);else if(typeof G=="object"&&G!==null&&(k(A,v)||k(P,v)))G=E(G,A[v],P[v]);else if(k(P,"*"))G=E(G,A[v],P["*"]);else return Object.defineProperty(N,v,{configurable:!0,enumerable:!0,get(){return T[v]},set(we){T[v]=we}}),G;return N[v]=G,G},set(se,v,Q,G){return v in N?N[v]=Q:T[v]=Q,!0},defineProperty(se,v,Q){return Reflect.defineProperty(N,v,Q)},deleteProperty(se,v){return Reflect.deleteProperty(N,v)}},re=Object.create(T);return new Proxy(re,J)},y=T=>({addListener(A,P,...N){A.addListener(T.get(P),...N)},hasListener(A,P){return A.hasListener(T.get(P))},removeListener(A,P){A.removeListener(T.get(P))}}),_=new i(T=>typeof T!="function"?T:function(P){const N=E(P,{},{getContent:{minArgs:0,maxArgs:0}});T(N)}),S=new i(T=>typeof T!="function"?T:function(P,N,J){let re=!1,se,v=new Promise(Ae=>{se=function(le){re=!0,Ae(le)}}),Q;try{Q=T(P,N,se)}catch(Ae){Q=Promise.reject(Ae)}const G=Q!==!0&&l(Q);if(Q!==!0&&!G&&!re)return!1;const we=Ae=>{Ae.then(le=>{J(le)},le=>{let Qe;le&&(le instanceof Error||typeof le.message=="string")?Qe=le.message:Qe="An unexpected error occurred",J({__mozWebExtensionPolyfillReject__:!0,message:Qe})}).catch(le=>{console.error("Failed to send onMessage rejected reply",le)})};return we(G?Q:v),!0}),O=({reject:T,resolve:A},P)=>{a.runtime.lastError?a.runtime.lastError.message===n?A():T(new Error(a.runtime.lastError.message)):P&&P.__mozWebExtensionPolyfillReject__?T(new Error(P.message)):A(P)},D=(T,A,P,...N)=>{if(N.length<A.minArgs)throw new Error(`Expected at least ${A.minArgs} ${u(A.minArgs)} for ${T}(), got ${N.length}`);if(N.length>A.maxArgs)throw new Error(`Expected at most ${A.maxArgs} ${u(A.maxArgs)} for ${T}(), got ${N.length}`);return new Promise((J,re)=>{const se=O.bind(null,{resolve:J,reject:re});N.push(se),P.sendMessage(...N)})},U={devtools:{network:{onRequestFinished:y(_)}},runtime:{onMessage:y(S),onMessageExternal:y(S),sendMessage:D.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:D.bind(null,"sendMessage",{minArgs:2,maxArgs:3})}},oe={clear:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}};return o.privacy={network:{"*":oe},services:{"*":oe},websites:{"*":oe}},E(a,U,o)};t.exports=s(chrome)}})})(Ee);var kr=Ee.exports;const g=pe(kr);function br(r){return r==null||typeof r=="function"?{main:r}:r}function Sr(r){return r.type==="parent"}function q(r){return r.type==="child"||r.type==="standalone"}function _e(){const r=new Date().toISOString();return{version:1,workspaces:[],context:{activeParentId:null,openWorkspaceIds:[],transcendentIds:[],lastSwitchTime:r},contextHistory:{entries:[],currentIndex:-1,maxEntries:50},settings:{autoSave:!0,autoSaveInterval:3e4,showOrphanPrompt:!0,syncBackend:"none",confirmContextSwitch:!0,restoreWindowPositions:!0,useSmartPositioning:!0,theme:"system",lazyLoadTabs:!0},metadata:{version:1,created:r,lastModified:r}}}const dn={apiKey:null,enabled:!1,model:"claude-sonnet-4-20250514",autoSuggest:!1,maxSuggestions:5},wt={enabled:!1},Me="workspaceConfig";class Tr{constructor(){M(this,"cache",null);M(this,"cacheTimestamp",0);M(this,"cacheTTL",5e3)}async read(){if(this.cache&&Date.now()-this.cacheTimestamp<this.cacheTTL)return{success:!0,data:this.cache};try{const t=(await g.storage.local.get(Me))[Me];if(t)return this.cache=t,this.cacheTimestamp=Date.now(),{success:!0,data:t};const n=_e();return await this.write(n),{success:!0,data:n}}catch(e){const t=e instanceof Error?e.message:"Unknown storage error";return console.error("[Mnemonic] Storage read error:",t),{success:!1,error:t}}}async write(e){try{return e.metadata.lastModified=new Date().toISOString(),await g.storage.local.set({[Me]:e}),this.cache=e,this.cacheTimestamp=Date.now(),{success:!0}}catch(t){const n=t instanceof Error?t.message:"Unknown storage error";return console.error("[Mnemonic] Storage write error:",n),{success:!1,error:n}}}invalidateCache(){this.cache=null,this.cacheTimestamp=0}async getUsage(){try{return g.storage.local.getBytesInUse?{bytesUsed:await g.storage.local.getBytesInUse(Me),quota:10485760}:{bytesUsed:0,quota:10485760}}catch{return{bytesUsed:0,quota:10485760}}}onChanged(e){const t=(n,s)=>{s==="local"&&n[Me]&&(this.invalidateCache(),e({oldValue:n[Me].oldValue,newValue:n[Me].newValue}))};return g.storage.onChanged.addListener(t),()=>{g.storage.onChanged.removeListener(t)}}}const Ar=new Tr;function un(r){const e=_e();return{...e,...r,context:{...e.context,...r.context},contextHistory:{...e.contextHistory,...r.contextHistory},settings:{...e.settings,...r.settings},metadata:{...e.metadata,...r.metadata},workspaces:r.workspaces||[]}}class Ir{constructor(){M(this,"primary");M(this,"initialized",!1);this.primary=Ar}async initialize(){if(this.initialized)return;const e=await this.primary.read();e.success||(console.error("[Mnemonic] Failed to initialize storage:",e.error),await this.primary.write(_e())),this.initialized=!0,console.log("[Mnemonic] Storage initialized")}async read(){const e=await this.primary.read();return e.success?e.data:null}async write(e){const t=un(e);return(await this.primary.write(t)).success}async update(e){const t=await this.primary.read();if(!t.success||!t.data)return{success:!1,error:t.error||"No config found"};try{const n=await e(t.data),s=await this.primary.write(n);return s.success?{success:!0,data:n}:{success:!1,error:s.error}}catch(n){return{success:!1,error:n instanceof Error?n.message:"Update failed"}}}async getSettings(){const e=await this.read();return(e==null?void 0:e.settings)||null}async updateSettings(e){return(await this.update(n=>({...n,settings:{...n.settings,...e}}))).success}onChanged(e){return this.primary.onChanged(e)}async getUsage(){const e=await this.primary.getUsage();return{...e,percentUsed:e.quota>0?e.bytesUsed/e.quota*100:0}}async export(){const e=await this.read();if(!e)return null;const t={...e,workspaces:e.workspaces.map(n=>{const{...s}=n;return"windowId"in s&&delete s.windowId,"mainWindowId"in s&&delete s.mainWindowId,s})};return JSON.stringify(t,null,2)}async import(e){try{const t=JSON.parse(e);if(!t.version||!Array.isArray(t.workspaces))return{success:!1,error:"Invalid configuration format"};const n=un(t);return n.metadata.lastModified=new Date().toISOString(),await this.primary.write(n)}catch(t){return{success:!1,error:t instanceof Error?t.message:"Import failed"}}}async reset(){const e=_e();return this.write(e)}}const I=new Ir;function Er(r){const e=[];if((!r.id||typeof r.id!="string")&&e.push({field:"id",message:"Workspace must have a valid ID"}),(!r.name||typeof r.name!="string")&&e.push({field:"name",message:"Workspace must have a name",workspaceId:r.id}),["parent","child","standalone"].includes(r.type)||e.push({field:"type",message:`Invalid workspace type: ${r.type}`,workspaceId:r.id}),r.type==="parent"){const t=r;Array.isArray(t.children)||e.push({field:"children",message:"Parent workspace must have children array",workspaceId:r.id}),t.parentId!==null&&e.push({field:"parentId",message:"Parent workspaces cannot have a parent (single-level nesting only)",workspaceId:r.id})}if(r.type==="child"){const t=r;(!t.parentId||typeof t.parentId!="string")&&e.push({field:"parentId",message:"Child workspace must have a valid parentId",workspaceId:r.id}),Array.isArray(t.tabs)||e.push({field:"tabs",message:"Child workspace must have tabs array",workspaceId:r.id})}if(r.type==="standalone"){const t=r;t.parentId!==null&&e.push({field:"parentId",message:"Standalone workspace must have null parentId",workspaceId:r.id}),Array.isArray(t.tabs)||e.push({field:"tabs",message:"Standalone workspace must have tabs array",workspaceId:r.id})}return r.metadata||e.push({field:"metadata",message:"Workspace must have metadata",workspaceId:r.id}),{valid:e.length===0,errors:e}}function Mr(r){const e=[],t=new Set,n=new Set,s=new Map;for(const a of r)t.has(a.id)&&e.push({field:"id",message:`Duplicate workspace ID: ${a.id}`,workspaceId:a.id}),t.add(a.id),a.type==="parent"&&n.add(a.id),a.type==="child"&&s.set(a.id,a.parentId);for(const a of r){const o=Er(a);if(e.push(...o.errors),a.type==="child"){const i=a;n.has(i.parentId)||e.push({field:"parentId",message:`Child references non-existent parent: ${i.parentId}`,workspaceId:a.id})}if(a.type==="parent"){const i=a;for(const l of i.children){t.has(l)||e.push({field:"children",message:`Parent references non-existent child: ${l}`,workspaceId:a.id});const d=s.get(l);d&&d!==a.id&&e.push({field:"children",message:`Child ${l} has different parentId: ${d}`,workspaceId:a.id})}}}for(const a of r)if(a.type==="child"){const o=a,i=r.find(l=>l.type==="parent"&&l.id===o.parentId);i&&!i.children.includes(o.id)&&e.push({field:"parentId",message:"Child not listed in parent's children array",workspaceId:a.id})}return{valid:e.length===0,errors:e}}const yt="mnemonic_debug_log",kt=500,Cr=3e3;class xr{constructor(){M(this,"entries",[]);M(this,"flushTimer",null);M(this,"loaded",!1)}async load(){try{const t=(await g.storage.local.get(yt))[yt];t!=null&&t.entries&&(this.entries=t.entries.slice(-kt)),this.loaded=!0}catch{this.loaded=!0}}log(e,t={}){const n={timestamp:new Date().toISOString(),event:e,data:t};this.entries.push(n),this.entries.length>kt&&(this.entries=this.entries.slice(-kt)),e==="zero_tab_blocked"?this.flushNow():this.debouncedFlush()}getEntries(){return[...this.entries].reverse()}getEntriesByType(e){return this.entries.filter(t=>t.event===e).reverse()}async clear(){this.entries=[],await this.flushNow()}export(){return JSON.stringify({exportedAt:new Date().toISOString(),entryCount:this.entries.length,entries:this.entries},null,2)}debouncedFlush(){this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=setTimeout(()=>{this.flushNow(),this.flushTimer=null},Cr)}async flushNow(){try{const e={entries:this.entries,lastUpdated:new Date().toISOString()};await g.storage.local.set({[yt]:e})}catch{}}}let bt=null;function fe(){return bt||(bt=new xr),bt}function St(r){var n,s;const e=r.filter(a=>a.url&&!a.url.startsWith("chrome-extension://")).map(a=>{try{const o=new URL(a.url);return`${o.hostname}${o.pathname}`}catch{return a.url}}).sort();return{urlHash:e.join("|").split("").reduce((a,o)=>(a<<5)-a+o.charCodeAt(0)|0,0).toString(16),urlSet:e,tabCount:r.length,firstTabUrl:(n=r[0])==null?void 0:n.url,lastTabUrl:(s=r[r.length-1])==null?void 0:s.url}}function Tt(){const r=new Date().toISOString();return{created:r,lastModified:r,lastAccessed:r,switchCount:0,totalTimeActive:0}}class vr{async getAll(){const e=await I.read();return(e==null?void 0:e.workspaces)||[]}async getById(e){return(await this.getAll()).find(n=>n.id===e)||null}async getParents(){return(await this.getAll()).filter(Sr)}async getChildren(e){return(await this.getAll()).filter(n=>n.type==="child"&&n.parentId===e)}async getStandalone(){return(await this.getAll()).filter(t=>t.type==="standalone")}async getTranscendent(){return(await this.getAll()).filter(t=>t.isTranscendent)}async createParent(e,t={}){const n=await I.update(async a=>{const o=t.childIds||[];for(const l of o){const d=a.workspaces.find(u=>u.id===l);if(!d)throw new Error(`Child workspace ${l} not found`);if(d.type==="parent")throw new Error(`Cannot nest parent workspace ${l}`);if(d.type==="child")throw new Error(`Workspace ${l} already has a parent`)}const i={id:crypto.randomUUID(),name:e,type:"parent",parentId:null,isTranscendent:t.isTranscendent||!1,openInContextSwitch:!0,children:o,metadata:Tt()};for(const l of o){const d=a.workspaces.findIndex(u=>u.id===l);if(d>-1){const u=a.workspaces[d];a.workspaces[d]={...u,type:"child",parentId:i.id}}}return a.workspaces.push(i),a});if(!n.success)throw new Error(n.error||"Failed to create parent workspace");return n.data.workspaces.find(a=>a.type==="parent"&&a.name===e)}async createChild(e,t,n=[],s){const a=await I.update(async i=>{const l=i.workspaces.find(u=>u.id===e&&u.type==="parent");if(!l)throw new Error(`Parent workspace ${e} not found`);const d={id:crypto.randomUUID(),name:t,type:"child",parentId:e,isTranscendent:!1,openInContextSwitch:(s==null?void 0:s.openInContextSwitch)??!0,syncEnabled:(s==null?void 0:s.syncEnabled)??!0,tabs:n,fingerprint:n.length>0?St(n):void 0,metadata:Tt()};return l.children.push(d.id),i.workspaces.push(d),i});if(!a.success)throw new Error(a.error||"Failed to create child workspace");return a.data.workspaces.find(i=>i.type==="child"&&i.name===t&&i.parentId===e)}async createStandalone(e,t=[],n){const s=await I.update(async o=>{const i={id:crypto.randomUUID(),name:e,type:"standalone",parentId:null,isTranscendent:!1,openInContextSwitch:(n==null?void 0:n.openInContextSwitch)??!0,syncEnabled:(n==null?void 0:n.syncEnabled)??!0,tabs:t,fingerprint:t.length>0?St(t):void 0,metadata:Tt()};return o.workspaces.push(i),o});if(!s.success)throw new Error(s.error||"Failed to create standalone workspace");return s.data.workspaces.find(o=>o.type==="standalone"&&o.name===e)}async rename(e,t){const n=await I.update(s=>{const a=s.workspaces.find(o=>o.id===e);if(!a)throw new Error("Workspace not found");return a.name=t,a.metadata.lastModified=new Date().toISOString(),s});if(!n.success)throw new Error(n.error||"Failed to rename workspace")}async update(e,t){const n=await I.update(s=>{const a=s.workspaces.find(o=>o.id===e);if(!a)throw new Error("Workspace not found");return t.resources!==void 0&&(a.resources=t.resources),t.tags!==void 0&&(a.tags=t.tags),t.notesSidebarExpanded!==void 0&&(a.notesSidebarExpanded=t.notesSidebarExpanded),t.notesSidebarWidth!==void 0&&(a.notesSidebarWidth=t.notesSidebarWidth),"refocusTab"in t&&(a.type==="child"||a.type==="standalone")&&(a.refocusTab=t.refocusTab),"autoFocusPlayingTab"in t&&(a.type==="child"||a.type==="standalone")&&(a.autoFocusPlayingTab=t.autoFocusPlayingTab),"refocusTabOverridesPlaying"in t&&(a.type==="child"||a.type==="standalone")&&(a.refocusTabOverridesPlaying=t.refocusTabOverridesPlaying),a.metadata.lastModified=new Date().toISOString(),s});if(!n.success)throw new Error(n.error||"Failed to update workspace")}async updateTabs(e,t,n){const s=await I.update(a=>{const o=a.workspaces.find(d=>d.id===e);if(!o)throw new Error("Workspace not found");if(!q(o))throw new Error("Cannot update tabs on parent workspace");const i=o,l=i.tabs.length;return l>0&&t.length===0&&!(n!=null&&n.allowEmpty)?(console.warn(`[Mnemonic] ZERO-TAB PROTECTION: Blocked saving 0 tabs to "${o.name}" (had ${l})`),fe().log("zero_tab_blocked",{workspaceId:e,workspaceName:o.name,existingTabCount:l}),a):(fe().log("update_tabs",{workspaceId:e,workspaceName:o.name,oldCount:l,newCount:t.length}),i.tabs=t,i.fingerprint=St(t),o.metadata.lastModified=new Date().toISOString(),a)});if(!s.success)throw new Error(s.error||"Failed to update tabs")}async setTranscendent(e,t){const n=await I.update(s=>{const a=s.workspaces.find(o=>o.id===e);if(!a)throw new Error("Workspace not found");return a.isTranscendent=t,a.metadata.lastModified=new Date().toISOString(),t&&!s.context.transcendentIds.includes(e)?s.context.transcendentIds.push(e):t||(s.context.transcendentIds=s.context.transcendentIds.filter(o=>o!==e)),s});if(!n.success)throw new Error(n.error||"Failed to update transcendent status")}async setOpenInContextSwitch(e,t){const n=await I.update(s=>{const a=s.workspaces.find(o=>o.id===e);if(!a)throw new Error("Workspace not found");return a.openInContextSwitch=t,a.metadata.lastModified=new Date().toISOString(),s});if(!n.success)throw new Error(n.error||"Failed to update context switch setting")}async setSyncEnabled(e,t){const n=await I.update(s=>{const a=s.workspaces.find(o=>o.id===e);if(!a)throw new Error("Workspace not found");return a.syncEnabled=t,a.metadata.lastModified=new Date().toISOString(),s});if(!n.success)throw new Error(n.error||"Failed to update sync enabled setting")}async move(e,t){const n=await I.update(s=>{const a=s.workspaces.find(o=>o.id===e);if(!a)throw new Error("Workspace not found");if(a.type==="parent")throw new Error("Cannot move parent workspaces");if(a.type==="child"){const o=s.workspaces.find(i=>i.id===a.parentId);o&&(o.children=o.children.filter(i=>i!==e))}if(t){const o=s.workspaces.find(l=>l.id===t&&l.type==="parent");if(!o)throw new Error("New parent not found");o.children.push(e);const i=s.workspaces.findIndex(l=>l.id===e);s.workspaces[i]={...a,type:"child",parentId:t}}else{const o=s.workspaces.findIndex(i=>i.id===e);s.workspaces[o]={...a,type:"standalone",parentId:null}}return s});if(!n.success)throw new Error(n.error||"Failed to move workspace")}async convertToParent(e){const t=await I.update(n=>{const s=n.workspaces.findIndex(i=>i.id===e);if(s===-1)throw new Error("Workspace not found");const a=n.workspaces[s];if(a.type!=="standalone")throw new Error("Only standalone workspaces can be converted to parent");const o={id:a.id,name:a.name,type:"parent",parentId:null,children:[],isTranscendent:a.isTranscendent,openInContextSwitch:a.openInContextSwitch??!0,tags:a.tags,metadata:{...a.metadata,lastModified:new Date().toISOString()}};return n.workspaces[s]=o,n});if(!t.success)throw new Error(t.error||"Failed to convert to parent")}async delete(e,t={keepChildren:!0}){const n=await I.update(s=>{const a=s.workspaces.find(o=>o.id===e);if(!a)throw new Error("Workspace not found");if(a.type==="parent"){const o=a;if(t.keepChildren)for(const i of o.children){const l=s.workspaces.findIndex(d=>d.id===i);if(l>-1){const d=s.workspaces[l];s.workspaces[l]={...d,type:"standalone",parentId:null}}}else s.workspaces=s.workspaces.filter(i=>!o.children.includes(i.id))}if(a.type==="child"){const o=s.workspaces.find(i=>i.id===a.parentId);o&&(o.children=o.children.filter(i=>i!==e))}return s.context.transcendentIds=s.context.transcendentIds.filter(o=>o!==e),s.context.openWorkspaceIds=s.context.openWorkspaceIds.filter(o=>o!==e),s.workspaces=s.workspaces.filter(o=>o.id!==e),s});if(!n.success)throw new Error(n.error||"Failed to delete workspace")}async recordAccess(e){await I.update(t=>{const n=t.workspaces.find(s=>s.id===e);return n&&(n.metadata.lastAccessed=new Date().toISOString(),n.metadata.switchCount++),t})}async updateSummary(e,t,n){const s=await I.update(a=>{const o=a.workspaces.find(i=>i.id===e);if(!o)throw new Error("Workspace not found");return o.summary={text:t,isUserGenerated:n,lastUpdated:new Date().toISOString()},o.metadata.lastModified=new Date().toISOString(),a});if(!s.success)throw new Error(s.error||"Failed to update summary")}async clearSummary(e){const t=await I.update(n=>{const s=n.workspaces.find(a=>a.id===e);if(!s)throw new Error("Workspace not found");return delete s.summary,s.metadata.lastModified=new Date().toISOString(),n});if(!t.success)throw new Error(t.error||"Failed to clear summary")}async validate(){const e=await this.getAll(),t=Mr(e);return{valid:t.valid,errors:t.errors.map(n=>`${n.workspaceId||"global"}: ${n.message}`)}}async archive(e){const t=await I.update(n=>{const s=n.workspaces.find(o=>o.id===e);if(!s)throw new Error("Workspace not found");if(s.type==="parent")throw new Error("Use archiveContext to archive parent workspaces");if(s.archivedAt)throw new Error("Workspace is already archived");const a=new Date().toISOString();return s.archivedAt=a,s.metadata.lastModified=a,n.context.transcendentIds=n.context.transcendentIds.filter(o=>o!==e),n.context.openWorkspaceIds=n.context.openWorkspaceIds.filter(o=>o!==e),n});if(!t.success)throw new Error(t.error||"Failed to archive workspace")}async archiveContext(e){let t=0;const n=await I.update(s=>{const a=s.workspaces.find(l=>l.id===e);if(!a||a.type!=="parent")throw new Error("Parent workspace not found");if(a.archivedAt)throw new Error("Context is already archived");const o=new Date().toISOString(),i=a;a.archivedAt=o,a.metadata.lastModified=o,t++,s.context.transcendentIds=s.context.transcendentIds.filter(l=>l!==e),s.context.openWorkspaceIds=s.context.openWorkspaceIds.filter(l=>l!==e);for(const l of i.children){const d=s.workspaces.find(u=>u.id===l);d&&!d.archivedAt&&(d.archivedAt=o,d.metadata.lastModified=o,t++,s.context.transcendentIds=s.context.transcendentIds.filter(u=>u!==l),s.context.openWorkspaceIds=s.context.openWorkspaceIds.filter(u=>u!==l))}return s});if(!n.success)throw new Error(n.error||"Failed to archive context");return{archivedCount:t}}async restore(e){const t=await I.update(n=>{const s=n.workspaces.find(o=>o.id===e);if(!s)throw new Error("Workspace not found");if(!s.archivedAt)throw new Error("Workspace is not archived");const a=new Date().toISOString();if(delete s.archivedAt,s.metadata.lastModified=a,s.type==="child"){const o=s,i=n.workspaces.find(l=>l.id===o.parentId);i&&i.archivedAt&&(delete i.archivedAt,i.metadata.lastModified=a)}return n});if(!t.success)throw new Error(t.error||"Failed to restore workspace")}async restoreContext(e){let t=0;const n=await I.update(s=>{const a=s.workspaces.find(l=>l.id===e);if(!a||a.type!=="parent")throw new Error("Parent workspace not found");const o=new Date().toISOString(),i=a;a.archivedAt&&(delete a.archivedAt,a.metadata.lastModified=o,t++);for(const l of i.children){const d=s.workspaces.find(u=>u.id===l);d&&d.archivedAt&&(delete d.archivedAt,d.metadata.lastModified=o,t++)}return s});if(!n.success)throw new Error(n.error||"Failed to restore context");return{restoredCount:t}}async permanentlyDelete(e){const t=await this.getById(e);if(!t)throw new Error("Workspace not found");if(!t.archivedAt)throw new Error("Only archived workspaces can be permanently deleted. Archive first.");await this.delete(e,{keepChildren:!1})}async getArchived(){return(await this.getAll()).filter(t=>t.archivedAt)}async getActive(){return(await this.getAll()).filter(t=>!t.archivedAt)}async createGroup(e,t,n={}){if(!t||t.trim()==="")throw new Error("Group name cannot be empty");let s=null;const a=await I.update(o=>{const i=o.workspaces.find(d=>d.id===e&&d.type==="parent");if(!i)throw new Error("Parent workspace not found");i.groups||(i.groups=[]);const l={id:crypto.randomUUID(),name:t.trim(),collapsed:!1,...n.color&&{color:n.color}};return i.groups.push(l),i.metadata.lastModified=new Date().toISOString(),s=l,o});if(!a.success)throw new Error(a.error||"Failed to create group");return s}async renameGroup(e,t,n){const s=await I.update(a=>{var l;const o=a.workspaces.find(d=>d.id===e&&d.type==="parent");if(!o)throw new Error("Parent workspace not found");const i=(l=o.groups)==null?void 0:l.find(d=>d.id===t);if(!i)throw new Error("Group not found");return i.name=n,o.metadata.lastModified=new Date().toISOString(),a});if(!s.success)throw new Error(s.error||"Failed to rename group")}async deleteGroup(e,t){const n=await I.update(s=>{const a=s.workspaces.find(i=>i.id===e&&i.type==="parent");if(!a)throw new Error("Parent workspace not found");if(!a.groups)throw new Error("Group not found");const o=a.groups.findIndex(i=>i.id===t);if(o===-1)throw new Error("Group not found");a.groups.splice(o,1),a.metadata.lastModified=new Date().toISOString();for(const i of a.children){const l=s.workspaces.find(d=>d.id===i);l&&l.groupId===t&&(l.groupId=null,l.metadata.lastModified=new Date().toISOString())}return s});if(!n.success)throw new Error(n.error||"Failed to delete group")}async setChildGroup(e,t){const n=await I.update(s=>{var o;const a=s.workspaces.find(i=>i.id===e);if(!a)throw new Error("Child workspace not found");if(a.type!=="child")throw new Error("Can only set group on child workspaces");if(t!==null){const i=s.workspaces.find(d=>d.id===a.parentId&&d.type==="parent");if(!i)throw new Error("Parent workspace not found");if(!((o=i.groups)==null?void 0:o.some(d=>d.id===t)))throw new Error("Group not found in parent")}return a.groupId=t,a.metadata.lastModified=new Date().toISOString(),s});if(!n.success)throw new Error(n.error||"Failed to set child group")}async toggleGroupCollapsed(e,t){const n=await I.update(s=>{var i;const a=s.workspaces.find(l=>l.id===e&&l.type==="parent");if(!a)throw new Error("Parent workspace not found");const o=(i=a.groups)==null?void 0:i.find(l=>l.id===t);if(!o)throw new Error("Group not found");return o.collapsed=!o.collapsed,a.metadata.lastModified=new Date().toISOString(),s});if(!n.success)throw new Error(n.error||"Failed to toggle group collapsed state")}async updateGroupColor(e,t,n){const s=await I.update(a=>{var l;const o=a.workspaces.find(d=>d.id===e&&d.type==="parent");if(!o)throw new Error("Parent workspace not found");const i=(l=o.groups)==null?void 0:l.find(d=>d.id===t);if(!i)throw new Error("Group not found");return n===null?delete i.color:i.color=n,o.metadata.lastModified=new Date().toISOString(),a});if(!s.success)throw new Error(s.error||"Failed to update group color")}}const f=new vr,tt=1,Pr={};function gn(r){if(!r||typeof r!="object")return!0;const e=r.version;return typeof e!="number"||e<tt}function Wr(r){return!r||typeof r!="object"?0:r.version||0}function pn(r){let e=r,t=Wr(r);for(console.log(`[Mnemonic] Starting migration from v${t} to v${tt}`);t<tt;){const n=t+1,s=Pr[n];s?(console.log(`[Mnemonic] Migrating v${t} -> v${n}`),e=s(e)):e={...e,version:n},t=n}return console.log(`[Mnemonic] Migration complete, now at v${tt}`),e}function _r(r){const e=[],t=new Set,n=new Set,s=new Map;for(const a of r)t.has(a.id)&&e.push({type:"duplicate_id",workspaceId:a.id,message:`Duplicate workspace ID: ${a.id}`}),t.add(a.id),a.type==="parent"&&(n.add(a.id),s.set(a.id,a.children));for(const a of r){if(a.type==="child"){const o=a;if(!n.has(o.parentId))e.push({type:"invalid_parent_ref",workspaceId:a.id,message:`Child references non-existent parent: ${o.parentId}`});else{const i=s.get(o.parentId);i&&!i.includes(a.id)&&e.push({type:"orphan_child",workspaceId:a.id,message:"Child not listed in parent's children array"})}}if(a.type==="parent"){const o=a;for(const i of o.children)t.has(i)||e.push({type:"missing_child",workspaceId:a.id,message:`Parent lists non-existent child: ${i}`})}}return e}function Or(r){const e=_r(r.workspaces),t=[];if(e.length===0)return{config:r,report:{issues:[],fixes:[],wasRepaired:!1}};let n=[...r.workspaces];const s=new Set;n=n.filter(d=>s.has(d.id)?(t.push({type:"removed_duplicate",workspaceId:d.id,message:"Removed duplicate workspace"}),!1):(s.add(d.id),!0));const a=new Map(n.map(d=>[d.id,d])),o=new Set(n.filter(d=>d.type==="parent").map(d=>d.id));n=n.map(d=>{if(d.type==="child"){const u=d;if(!o.has(u.parentId))return t.push({type:"converted_to_standalone",workspaceId:d.id,message:`Converted to standalone (parent ${u.parentId} not found)`}),{...u,type:"standalone",parentId:null}}return d}),n=n.map(d=>{if(d.type==="parent"){const u=d,m=u.children.filter(h=>a.get(h)?!0:(t.push({type:"removed_from_children",workspaceId:d.id,message:`Removed non-existent child ${h} from children array`}),!1));if(m.length!==u.children.length)return{...u,children:m}}return d});const i=new Map;for(const d of n)d.type==="parent"&&i.set(d.id,new Set(d.children));for(const d of n)if(d.type==="child"){const u=d,m=i.get(u.parentId);m&&!m.has(d.id)&&(m.add(d.id),t.push({type:"fixed_reference",workspaceId:d.id,message:"Added to parent's children array"}))}return n=n.map(d=>{if(d.type==="parent"){const u=i.get(d.id);if(u)return{...d,children:Array.from(u)}}return d}),{config:{...r,workspaces:n,metadata:{...r.metadata,lastModified:new Date().toISOString()}},report:{issues:e,fixes:t,wasRepaired:t.length>0}}}function At(r){const e=new URLSearchParams;return e.set("workspaceId",r.id),e.set("type",r.type),e.set("transcendent",r.isTranscendent?"1":"0"),r.parentId&&e.set("parentId",r.parentId),g.runtime.getURL(`/workspace-dashboard.html?${e.toString()}`)}function fn(r){try{const e=g.runtime.getURL("/");if(!r.startsWith(e))return null;const t=new URL(r);if(!t.pathname.endsWith("workspace-dashboard.html"))return null;const n=t.searchParams.get("workspaceId"),s=t.searchParams.get("type"),a=t.searchParams.get("transcendent"),o=t.searchParams.get("parentId");return!n||!s||!["parent","child","standalone"].includes(s)?null:{workspaceId:n,type:s,isTranscendent:a==="1",parentId:o||null}}catch{return null}}async function nt(r){try{const e=await g.tabs.query({windowId:r});for(const t of e){if(!t.url||!t.id)continue;const n=fn(t.url);if(n)return{tabId:t.id,windowId:r,params:n}}return null}catch(e){return console.error("[Mnemonic] Error finding dashboard tab:",e),null}}async function Nr(){const r=[];try{const e=g.runtime.getURL("/workspace-dashboard.html"),t=await g.tabs.query({url:`${e}*`});for(const n of t){if(!n.url||!n.id||n.windowId===void 0)continue;const s=fn(n.url);s&&r.push({tabId:n.id,windowId:n.windowId,params:s})}}catch(e){console.error("[Mnemonic] Error finding all dashboard tabs:",e)}return r}async function Dr(r,e){try{const t=At(e);return(await g.tabs.create({windowId:r,url:t,pinned:!0,active:!1,index:0})).id??null}catch(t){return console.error("[Mnemonic] Error injecting dashboard tab:",t),null}}async function Fr(r,e){try{const t=At(e);return await g.tabs.update(r,{url:t}),!0}catch(t){return console.error("[Mnemonic] Error updating dashboard tab:",t),!1}}async function Ge(r,e){const t=await nt(r);if(t){if(t.params.workspaceId===e.id)return t;if(await Fr(t.tabId,e))return{tabId:t.tabId,windowId:r,params:{workspaceId:e.id,type:e.type,isTranscendent:e.isTranscendent,parentId:e.parentId}}}const n=await Dr(r,e);return n===null?null:{tabId:n,windowId:r,params:{workspaceId:e.id,type:e.type,isTranscendent:e.isTranscendent,parentId:e.parentId}}}const Ur=.3;function mn(r){try{const e=new URL(r);if(e.protocol==="chrome-extension:"||e.protocol==="moz-extension:"||e.protocol==="chrome:"||e.protocol==="about:")return"";let t=e.hostname.toLowerCase().replace(/^www\./,""),n=e.pathname;for(;n.endsWith("/")&&n.length>1;)n=n.slice(0,-1);return t+=n||"/",t}catch{return""}}function Br(r){const e=r.map(mn).filter(s=>s.length>0).sort();let t=0;const n=e.join("|");for(let s=0;s<n.length;s++){const a=n.charCodeAt(s);t=(t<<5)-t+a,t=t&t}return t.toString(36)}function It(r){const e=r.map(n=>n.url).filter(n=>n&&n.length>0),t=e.map(mn).filter(n=>n.length>0);return{urlHash:Br(e),urlSet:t,tabCount:r.length,firstTabUrl:t[0],lastTabUrl:t[t.length-1]}}function hn(r){let e=r.toLowerCase();for(e.startsWith("www.")&&(e=e.slice(4));e.endsWith("/")&&e.length>1;)e=e.slice(0,-1);return e}function Lr(r,e){if(r.length===0&&e.length===0)return 1;if(r.length===0||e.length===0)return 0;const t=new Set(r.map(hn)),n=new Set(e.map(hn));let s=0;for(const o of t)n.has(o)&&s++;const a=t.size+n.size-s;return a===0?0:s/a}const $r=.5;function Rr(r,e){const t=Math.min(r.tabCount,e.tabCount)/Math.max(r.tabCount,e.tabCount);if(t<$r)return 0;if(r.urlHash===e.urlHash)return 1;const n=Lr(r.urlSet,e.urlSet);let s=0;r.firstTabUrl&&r.firstTabUrl===e.firstTabUrl&&(s+=.05),r.lastTabUrl&&r.lastTabUrl===e.lastTabUrl&&(s+=.05);const a=t<.7?(.7-t)*.3:0;return Math.min(1,Math.max(0,n+s-a))}function wn(r,e){let t=null,n=0;for(const s of e){if(!s.fingerprint)continue;const a=Rr(r,s.fingerprint);if(console.log("[Mnemonic] fingerprint: comparing window ("+r.urlSet.length+' URLs) vs workspace "'+s.name+'" ('+s.fingerprint.urlSet.length+" URLs) = similarity:",a.toFixed(2)),a>=Ur&&a>n){n=a;const o=new Set(r.urlSet),i=s.fingerprint.urlSet.filter(l=>o.has(l)).length;t={workspaceId:s.id,confidence:a,matchedUrls:i,totalUrls:Math.max(r.urlSet.length,s.fingerprint.urlSet.length)}}}return t}async function yn(r){try{const t=(await g.tabs.query({windowId:r})).filter(n=>n.url&&!n.url.startsWith("chrome-extension://")&&!n.url.startsWith("moz-extension://")&&!n.url.startsWith("chrome://")&&!n.url.startsWith("about:"));return t.length===0?null:It(t.map(n=>({url:n.url})))}catch(e){return console.error("[Mnemonic] Error generating window fingerprint:",e),null}}function jr(r){return It(r.tabs)}class Kr{constructor(){M(this,"mappings",new Map);M(this,"workspaceToWindow",new Map);M(this,"untrackedWindows",new Map);M(this,"listeners",new Set);M(this,"untrackedListeners",new Set)}getMappings(){return Array.from(this.mappings.values())}getWindowMapping(e){return this.mappings.get(e)}getWorkspaceWindow(e){return this.workspaceToWindow.get(e)}isWindowTracked(e){return this.mappings.has(e)}hasActiveWindow(e){return this.workspaceToWindow.has(e)}setMapping(e){const t=this.mappings.get(e.windowId);t&&t.workspaceId!==e.workspaceId&&this.workspaceToWindow.delete(t.workspaceId),this.mappings.set(e.windowId,e),this.workspaceToWindow.set(e.workspaceId,e.windowId),this.notifyListeners()}removeWindow(e){const t=this.mappings.get(e);t&&(this.workspaceToWindow.delete(t.workspaceId),this.mappings.delete(e),this.notifyListeners())}removeWorkspace(e){const t=this.workspaceToWindow.get(e);t!==void 0&&(this.mappings.delete(t),this.workspaceToWindow.delete(e),this.notifyListeners())}clear(){this.mappings.clear(),this.workspaceToWindow.clear(),this.notifyListeners()}getUntrackedWindows(){return Array.from(this.untrackedWindows.values())}markAsUntracked(e,t,n="dashboard_closed"){const s=this.mappings.get(e);if(!s)return null;const a={windowId:e,previousWorkspaceId:s.workspaceId,previousWorkspaceName:t,lostAt:new Date().toISOString(),reason:n};return this.workspaceToWindow.delete(s.workspaceId),this.mappings.delete(e),this.untrackedWindows.set(e,a),this.notifyListeners(),this.notifyUntrackedListeners(),a}retrackWindow(e,t,n){this.untrackedWindows.delete(e),this.setMapping({windowId:e,workspaceId:t,isMainWindow:!1,isTranscendent:n}),this.notifyUntrackedListeners()}clearUntracked(e){this.untrackedWindows.delete(e)&&this.notifyUntrackedListeners()}subscribeUntracked(e){return this.untrackedListeners.add(e),()=>this.untrackedListeners.delete(e)}notifyUntrackedListeners(){const e=this.getUntrackedWindows();for(const t of this.untrackedListeners)try{t(e)}catch(n){console.error("[Mnemonic] Error in untracked listener:",n)}}getTranscendentWindows(){return Array.from(this.mappings.values()).filter(e=>e.isTranscendent).map(e=>e.windowId)}getNonTranscendentWindows(){return Array.from(this.mappings.values()).filter(e=>!e.isTranscendent).map(e=>e.windowId)}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notifyListeners(){const e=this.getMappings();for(const t of this.listeners)try{t(e)}catch(n){console.error("[Mnemonic] Error in tracker listener:",n)}}async identifyWindow(e,t){const n=await nt(e);if(n)return{workspaceId:n.params.workspaceId,method:"dashboard",confidence:1,dashboardTabId:n.tabId};const s=t.filter(q),a=await yn(e);if(a){const o=wn(a,s);if(o)return{workspaceId:o.workspaceId,method:"fingerprint",confidence:o.confidence}}return null}async scanAllWindows(e){const t=[];try{const s=await g.windows.getAll({windowTypes:["normal"]}),a=await Nr(),o=new Set;for(const u of a){o.add(u.windowId);const m=e.find(h=>h.id===u.params.workspaceId);m&&this.setMapping({windowId:u.windowId,workspaceId:m.id,isMainWindow:m.type==="parent",isTranscendent:m.isTranscendent})}const i=e.filter(q);for(const u of i)!u.fingerprint&&u.tabs&&u.tabs.length>0&&(u.fingerprint=It(u.tabs));const l=i.filter(u=>u.fingerprint);for(const u of s){if(!u.id||o.has(u.id))continue;const m=await yn(u.id);if(!m)continue;const h=wn(m,i);if(h){const k=e.find(E=>E.id===h.workspaceId);k&&(this.setMapping({windowId:u.id,workspaceId:k.id,isMainWindow:!1,isTranscendent:k.isTranscendent}),t.push({windowId:u.id,workspaceId:k.id,workspace:k,confidence:h.confidence}))}}const d=new Set(s.map(u=>u.id).filter(u=>u!==void 0));for(const u of this.mappings.keys())d.has(u)||this.removeWindow(u)}catch(s){console.error("[Mnemonic] Error scanning windows:",s)}return t}}let Et=null;function R(){return Et||(Et=new Kr),Et}const zr={saveTabs:!0,closeOthers:!0,restorePositions:!0,focusFirst:!0};class Gr{constructor(e){M(this,"snapshot");M(this,"closedWindows",[]);M(this,"openedWindowIds",[]);M(this,"committed",!1);M(this,"rolledBack",!1);this.snapshot=e}recordClosed(e){this.closedWindows.push(e)}recordOpened(e){this.openedWindowIds.push(e)}commit(){this.committed=!0,console.log("[Mnemonic] Context switch committed:",{closed:this.closedWindows.length,opened:this.openedWindowIds.length})}async rollback(){if(this.committed)return{success:!1,errors:["Cannot rollback a committed transaction"]};if(this.rolledBack)return{success:!1,errors:["Transaction already rolled back"]};this.rolledBack=!0;const e=[];console.log("[Mnemonic] Rolling back context switch:",{windowsToClose:this.openedWindowIds.length,windowsToRestore:this.closedWindows.length});for(const t of this.openedWindowIds)try{await g.windows.remove(t)}catch{console.log("[Mnemonic] Window already closed during rollback:",t)}for(const t of this.closedWindows)try{const n={type:"normal",focused:!1};t.position&&(n.left=t.position.left,n.top=t.position.top,n.width=t.position.width,n.height=t.position.height,n.state=t.position.state);const s=t.tabs.length>0?t.tabs.map(o=>o.url):["about:blank"];n.url=s;const a=await g.windows.create(n);if(a.id){const o=await g.tabs.query({windowId:a.id});for(let i=0;i<o.length&&i<t.tabs.length;i++)t.tabs[i].pinned&&o[i].id&&await g.tabs.update(o[i].id,{pinned:!0});R().setMapping({windowId:a.id,workspaceId:t.workspaceId,isMainWindow:!1,isTranscendent:t.isTranscendent})}}catch(n){e.push(`Failed to restore window for ${t.workspaceName}: ${n}`)}return{success:e.length===0,errors:e}}getSnapshot(){return this.snapshot}}async function Hr(r){const t=R().getMappings(),n=[];for(const s of t){const a=r.find(l=>l.id===s.workspaceId);if(!a)continue;const o=await Oe(s.windowId),i=await rt(s.windowId);n.push({windowId:s.windowId,workspaceId:a.id,workspaceName:a.name,tabs:o,position:i,isTranscendent:a.isTranscendent})}return{timestamp:new Date().toISOString(),windows:n}}async function Oe(r){try{return(await g.tabs.query({windowId:r})).filter(t=>t.url&&!t.url.startsWith("chrome-extension://")&&!t.url.startsWith("moz-extension://")&&!t.url.startsWith("chrome://")&&!t.url.startsWith("about:")).map(t=>({url:t.url,title:t.title||t.url,favIconUrl:t.favIconUrl,pinned:t.pinned||!1,groupId:t.groupId,cookieStoreId:t.cookieStoreId!=="firefox-default"?t.cookieStoreId:void 0}))}catch(e){return console.error("[Mnemonic] Error capturing window tabs:",e),[]}}async function rt(r){try{const e=await g.windows.get(r);return{left:e.left??0,top:e.top??0,width:e.width??800,height:e.height??600,state:e.state??"normal"}}catch(e){return console.error("[Mnemonic] Error capturing window position:",e),null}}async function Vr(r,e){const t=await Oe(e),n=await rt(e);return{tabs:t,position:n}}function qr(){return typeof g<"u"&&g.runtime.getURL("").startsWith("moz-extension://")}async function Mt(r,e={}){try{const t={focused:e.focused??!0,type:"normal"};e.position&&(t.left=e.position.left,t.top=e.position.top,t.width=e.position.width,t.height=e.position.height,t.state=e.position.state);const n=qr(),s=e.lazyLoad??!1;if(q(r)){const o=r.tabs;if(o.length===0){t.url="about:blank";const l=(await g.windows.create(t)).id;return l?(await Ge(l,r),await Ne(l,r),l):null}if(s&&o.length>1){const i=o[0];if(n&&i.cookieStoreId){t.url="about:blank";const d=(await g.windows.create(t)).id;if(!d)return null;const u=await g.tabs.create({windowId:d,url:i.url,active:!0,pinned:i.pinned,cookieStoreId:i.cookieStoreId}),h=(await g.tabs.query({windowId:d})).find(k=>k.url==="about:blank"&&k.id!==u.id);return h!=null&&h.id&&await g.tabs.remove(h.id),await kn(d,o.slice(1),n),await Ge(d,r),await Ne(d,r),d}else{t.url=i.url;const d=(await g.windows.create(t)).id;if(!d)return null;if(i.pinned){const m=(await g.tabs.query({windowId:d})).find(h=>h.url===i.url);m!=null&&m.id&&await g.tabs.update(m.id,{pinned:!0})}return await kn(d,o.slice(1),n),await Ge(d,r),await Ne(d,r),d}}else if(n&&o.some(i=>i.cookieStoreId)){t.url="about:blank";const l=(await g.windows.create(t)).id;if(!l)return null;for(let m=0;m<o.length;m++){const h=o[m];await g.tabs.create({windowId:l,url:h.url,active:m===0,pinned:h.pinned,cookieStoreId:h.cookieStoreId})}const u=(await g.tabs.query({windowId:l})).find(m=>m.url==="about:blank");return u!=null&&u.id&&await g.tabs.remove(u.id),await Ge(l,r),await Ne(l,r),l}else{t.url=o.map(d=>d.url);const l=(await g.windows.create(t)).id;return l?(await Yr(l,o),await Ge(l,r),await Ne(l,r),l):null}}else{t.url=At(r);const o=(await g.windows.create(t)).id;return o?(await Ne(o,r),o):null}}catch(t){return console.error("[Mnemonic] Error opening workspace window:",t),null}}async function kn(r,e,t){if(t)for(const n of e)try{await g.tabs.create({windowId:r,url:n.url,active:!1,pinned:n.pinned,discarded:!0,title:n.title,cookieStoreId:n.cookieStoreId})}catch(s){console.error("[Mnemonic] Error creating discarded tab:",s)}else for(let a=0;a<e.length;a+=5){const o=e.slice(a,a+5),i=await Promise.all(o.map(l=>g.tabs.create({windowId:r,url:l.url,active:!1,pinned:l.pinned})));for(const l of i)if(l.id)try{await g.tabs.discard(l.id)}catch{}a+5<e.length&&await new Promise(l=>setTimeout(l,100))}}async function Yr(r,e){const n=(await g.tabs.query({windowId:r})).filter(s=>{var a;return!((a=s.url)!=null&&a.includes("workspace-dashboard.html"))});for(let s=0;s<n.length&&s<e.length;s++){const a=e[s],o=n[s];a.pinned&&o.id&&await g.tabs.update(o.id,{pinned:!0})}}async function Ne(r,e){R().setMapping({windowId:r,workspaceId:e.id,isMainWindow:e.type==="parent",isTranscendent:e.isTranscendent})}async function bn(r){try{return await g.windows.remove(r),R().removeWindow(r),!0}catch(e){return console.error("[Mnemonic] Error closing window:",e),!1}}function st(r,e){return e.filter(t=>t.type==="child"&&t.parentId===r)}async function Jr(r,e){const t=R(),n=e.find(k=>k.id===r&&k.type==="parent");if(!n)return null;const s=new Set(e.filter(k=>k.isTranscendent).map(k=>k.id)),a=new Set([n.id,...st(n.id,e).map(k=>k.id)]),o=t.getMappings();let i=0,l=0,d=0;const u=[];for(const k of o){const E=e.find(y=>y.id===k.workspaceId);E&&(s.has(k.workspaceId)?d++:a.has(k.workspaceId)||(i++,u.push(E.name),q(E)&&(l+=E.tabs.length)))}let m=0;t.getWorkspaceWindow(n.id)||m++;const h=st(n.id,e);for(const k of h)t.getWorkspaceWindow(k.id)||m++;return{targetParentId:r,targetParentName:n.name,windowsToClose:i,tabsToClose:l,transcendentPreserved:d,workspacesToClose:u,windowsToOpen:m}}async function Zr(r,e,t={}){const n={...zr,...t},s=R(),a={success:!1,previousContext:r.fromParentId||null,newContext:r.toParentId,closedWindows:[],openedWindows:[],preservedWindows:[],errors:[]},o=await Hr(e),i=new Gr(o);try{const l=e.find(S=>S.id===r.toParentId&&S.type==="parent");if(!l)return a.errors.push(`Target parent workspace not found: ${r.toParentId}`),a;const d=e.filter(S=>S.isTranscendent),u=new Set(d.map(S=>S.id));console.log("[ContextSwitch] Transcendent workspaces:",d.map(S=>({id:S.id,name:S.name}))),console.log("[ContextSwitch] Transcendent IDs:",[...u]);const m=new Set([l.id,...st(l.id,e).map(S=>S.id)]),h=s.getMappings();console.log("[ContextSwitch] Current window mappings:",h);const k=[],E=new Map;for(const S of h){const O=e.find(D=>D.id===S.workspaceId);if(!O){console.log("[ContextSwitch] No workspace found for mapping:",S);continue}if(console.log("[ContextSwitch] Checking window",S.windowId,"workspace:",O.name,"isTranscendent:",O.isTranscendent,"inTranscendentIds:",u.has(S.workspaceId),"inTargetIds:",m.has(S.workspaceId)),u.has(S.workspaceId))console.log("[ContextSwitch] PRESERVING transcendent window:",S.windowId,O.name),a.preservedWindows.push(S.windowId);else if(m.has(S.workspaceId))console.log("[ContextSwitch] PRESERVING target context window:",S.windowId,O.name),a.preservedWindows.push(S.windowId);else if(n.closeOthers&&(console.log("[ContextSwitch] MARKING FOR CLOSE:",S.windowId,O.name),k.push({windowId:S.windowId,workspace:O}),n.saveTabs&&q(O))){const D=await Vr(O,S.windowId);E.set(O.id,D)}}for(const{windowId:S,workspace:O}of k){const D=await Oe(S),U=await rt(S);await bn(S)?(a.closedWindows.push(S),i.recordClosed({windowId:S,workspaceId:O.id,workspaceName:O.name,tabs:D,position:U,isTranscendent:O.isTranscendent})):a.errors.push(`Failed to close window ${S}`)}if(!s.getWorkspaceWindow(l.id)){const S=await Mt(l,{focused:n.focusFirst,lazyLoad:n.lazyLoad});if(S)a.openedWindows.push(S),i.recordOpened(S);else throw new Error("Failed to open parent workspace window")}const _=st(l.id,e);for(const S of _){if(s.getWorkspaceWindow(S.id))continue;const D=n.restorePositions?S.windowPosition:void 0,U=await Mt(S,{position:D,focused:!1,lazyLoad:n.lazyLoad});if(U)a.openedWindows.push(U),i.recordOpened(U);else throw new Error(`Failed to open child workspace window: ${S.name}`)}if(n.focusFirst){const S=s.getWorkspaceWindow(l.id);if(S)try{await g.windows.update(S,{focused:!0})}catch{}}return i.commit(),a.success=!0,a.savedStates=Object.fromEntries(E),a}catch(l){const d=l instanceof Error?l.message:"Unknown error during context switch";a.errors.push(d),console.error("[Mnemonic] Context switch failed, attempting rollback:",d);const u=await i.rollback();return u.success?a.errors.push("Context switch failed but previous state was restored"):a.errors.push(`Rollback also failed: ${u.errors.join(", ")}`),a}}async function Sn(r,e={}){const t=R(),n=t.getWorkspaceWindow(r.id);if(n)try{return await g.windows.update(n,{focused:!0}),n}catch{t.removeWindow(n)}const s=q(r)?r.windowPosition:void 0;return Mt(r,{position:s,focused:!0,lazyLoad:e.lazyLoad})}async function Xr(r){const t=R().getWorkspaceWindow(r);return t?bn(t):!0}async function Qr(r,e){const t=await Oe(e);return t.length>0&&(r.tabs=t,r.fingerprint=jr(r)),r}const es=new Set(["a","an","and","are","as","at","be","by","for","from","has","he","in","is","it","its","of","on","or","that","the","to","was","were","will","with","www","http","https","com","org","net"]),ts=2,ns=50;function Ct(r){return r.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").trim()}function Tn(r){return!(r.length<ts||r.length>ns||es.has(r)||!/[a-z]/.test(r))}function rs(r){const e=["ing","ed","es","s","ly","ment","ness","tion","sion"];for(const t of e)if(r.length>t.length+2&&r.endsWith(t))return r.slice(0,-t.length);return r}function An(r){try{return new URL(r).hostname.replace(/^www\./,"")}catch{return null}}function Z(r,e){if(!r||typeof r!="string")return[];const{stem:t=!0}=e||{},n=r.toLowerCase().replace(/[^\w\s-]/g," ").split(/\s+/).filter(Boolean),s=[],a=new Set;for(const o of n){const i=Ct(o);if(!Tn(i))continue;const l=t?rs(i):i;a.has(l)||(a.add(l),s.push(l))}return s}function In(r){const e=[];try{const t=new URL(r),s=t.hostname.replace(/^www\./,"").split(".").filter(o=>o.length>1);e.push(...s);const a=t.pathname.split("/").filter(Boolean).flatMap(o=>o.split(/[-_]/)).filter(o=>o.length>1&&!/^\d+$/.test(o));e.push(...a);for(const o of t.searchParams.keys())o.length>1&&e.push(o)}catch{return Z(r)}return[...new Set(e.map(Ct).filter(Tn))]}function En(r,e){if(r===e)return 1;if(!r||!e)return 0;const t=r.length>e.length?r:e,n=r.length>e.length?e:r;if(t.length===0)return 1;if(t.includes(n))return n.length/t.length;const s=[];for(let o=0;o<=n.length;o++)s[o]=[o];for(let o=0;o<=t.length;o++)s[0][o]=o;for(let o=1;o<=n.length;o++)for(let i=1;i<=t.length;i++){const l=n[o-1]===t[i-1]?0:1;s[o][i]=Math.min(s[o-1][i]+1,s[o][i-1]+1,s[o-1][i-1]+l)}return 1-s[n.length][t.length]/t.length}const ss={title:2,workspaceName:1.5,summary:1.6,domain:1.2,url:.8,tags:1.8,resourceTitle:1.8,resourceUrl:.8};function Mn(){return{tokens:new Map,documents:new Map,stats:{documentCount:0,tokenCount:0,lastUpdated:new Date().toISOString()}}}function xt(r,e,t){r.documents.set(e.id,e);for(const[n,s]of t){const a=ss[n]||1;for(const o of s){let i=r.tokens.get(o);i||(i={documentIds:new Set,termFrequency:new Map},r.tokens.set(o,i)),i.documentIds.add(e.id);const l=i.termFrequency.get(e.id)||0;i.termFrequency.set(e.id,l+a)}}}function Cn(r,e){if(r.documents.get(e)){r.documents.delete(e);for(const[n,s]of r.tokens)s.documentIds.delete(e),s.termFrequency.delete(e),s.documentIds.size===0&&r.tokens.delete(n);r.stats.documentCount=r.documents.size,r.stats.tokenCount=r.tokens.size,r.stats.lastUpdated=new Date().toISOString()}}function xn(r,e,t){var o;const n=(o=e.summary)==null?void 0:o.text,s={id:e.id,type:"workspace",title:e.name,workspaceName:e.name,parentName:t,workspaceType:e.type,summary:n,tags:e.tags,lastAccessed:e.metadata.lastAccessed},a=new Map;a.set("title",Z(e.name)),a.set("workspaceName",Z(e.name)),t&&a.set("workspaceName",[...Z(e.name),...Z(t)]),n&&a.set("summary",Z(n)),e.tags&&e.tags.length>0&&a.set("tags",e.tags.flatMap(i=>Z(i))),xt(r,s,a),r.stats.documentCount=r.documents.size,r.stats.tokenCount=r.tokens.size,r.stats.lastUpdated=new Date().toISOString()}function as(r,e,t,n,s){const a=An(e.url),o={id:`${n.id}:tab:${t}`,type:"tab",workspaceId:n.id,title:e.title,url:e.url,domain:a||void 0,workspaceName:n.name,parentName:s,workspaceType:n.type,lastAccessed:n.metadata.lastAccessed},i=new Map;i.set("title",Z(e.title)),i.set("url",In(e.url));const l=Z(n.name);s?i.set("workspaceName",[...l,...Z(s)]):i.set("workspaceName",l),a&&i.set("domain",Z(a)),xt(r,o,i),r.stats.documentCount=r.documents.size,r.stats.tokenCount=r.tokens.size,r.stats.lastUpdated=new Date().toISOString()}function vn(r,e,t){if(!q(e))return;e.tabs.forEach((s,a)=>{as(r,s,a,e,t)})}function os(r,e,t,n,s){const a=e.type==="url",o=a?An(e.value):void 0,i={id:`${n.id}:resource:${t}`,type:"resource",workspaceId:n.id,title:e.title,url:a?e.value:void 0,domain:o||void 0,workspaceName:n.name,parentName:s,workspaceType:n.type,lastAccessed:n.metadata.lastAccessed},l=new Map;l.set("resourceTitle",Z(e.title)),a?l.set("resourceUrl",In(e.value)):l.set("resourceUrl",Z(e.value.replace(/[-_/.]/g," "))),o&&l.set("domain",Z(o));const d=Z(n.name);s?l.set("workspaceName",[...d,...Z(s)]):l.set("workspaceName",d),xt(r,i,l),r.stats.documentCount=r.documents.size,r.stats.tokenCount=r.tokens.size,r.stats.lastUpdated=new Date().toISOString()}function Pn(r,e,t){const n=e.resources;!n||n.length===0||n.forEach((s,a)=>{os(r,s,a,e,t)})}function at(r){const e=Mn(),t=new Map;for(const n of r)n.type==="parent"&&t.set(n.id,n.name);for(const n of r){let s;if(n.type==="child"){const a=n;a.parentId&&(s=t.get(a.parentId))}xn(e,n,s),vn(e,n,s),Pn(e,n,s)}return e}function Y(r,e){const t=Array.from(r.documents.keys()).filter(n=>n===e.id||n.startsWith(`${e.id}:tab:`)||n.startsWith(`${e.id}:resource:`));for(const n of t)Cn(r,n);xn(r,e),vn(r,e),Pn(r,e)}function ot(r,e){const t=Array.from(r.documents.keys()).filter(n=>n===e||n.startsWith(`${e}:tab:`)||n.startsWith(`${e}:resource:`));for(const n of t)Cn(r,n)}function is(r){const e={documents:Array.from(r.documents.entries()),tokens:Array.from(r.tokens.entries()).map(([t,n])=>[t,{documentIds:Array.from(n.documentIds),termFrequency:Array.from(n.termFrequency.entries())}]),stats:r.stats};return JSON.stringify(e)}function cs(r){const e=JSON.parse(r),t={documents:new Map(e.documents),tokens:new Map,stats:e.stats};for(const[n,s]of e.tokens)t.tokens.set(n,{documentIds:new Set(s.documentIds),termFrequency:new Map(s.termFrequency)});return t}const ls=["domain:","workspace:","type:","in:","site:"];function ds(r){const e=r.trim();if(!e)return{terms:[],original:e,isEmpty:!0,filters:{}};const t=[],n={},s=gs(e);let a=!1;for(const o of s){if(o==="|"||o.toLowerCase()==="or"){a=!0;continue}const i=o.startsWith("-"),l=i?o.slice(1):o;let d=null,u=l;for(const h of ls)if(l.toLowerCase().startsWith(h)){d=us(h.slice(0,-1)),u=l.slice(h.length);break}d&&!i&&(d==="domain"||d==="site"?n.domain=u.toLowerCase():d==="workspace"||d==="in"?n.workspace=u:d==="type"&&(u==="workspace"||u==="tab")&&(n.type=u));const m=Z(u,{stem:!1});m.length===0&&u.length>0&&m.push(Ct(u));for(const h of m)t.push({term:h,original:u,negated:i,field:d,isOr:a}),a=!1}return{terms:t,original:e,isEmpty:t.length===0,filters:n}}function us(r){return{site:"domain",in:"workspace"}[r]||r}function gs(r){const e=[];let t="",n=!1,s="";for(let a=0;a<r.length;a++){const o=r[a];if((o==='"'||o==="'")&&!n){n=!0,s=o;continue}if(o===s&&n){n=!1,t&&(e.push(t),t="");continue}if(o===" "&&!n){t&&(e.push(t),t="");continue}t+=o}return t&&e.push(t),e}function Wn(r){return r.terms.filter(e=>!e.negated&&!e.isOr)}function _n(r){return r.terms.filter(e=>e.isOr)}function ps(r){return r.terms.filter(e=>e.negated)}const ue={tfWeight:1,idfWeight:1.5,maxRecencyBoost:.3,recencyHalfLife:24,exactTitleBoost:2,domainBoost:1.5,partialMatchPenalty:.7,minScore:.01};function fs(r,e,t){var k;const n=performance.now(),s=ds(e);if(s.isEmpty)return{query:e,results:[],totalMatches:0,duration:performance.now()-n};const{limit:a=50,type:o="all",workspaceId:i,recencyBoost:l=!0}=t||{},d=ms(r,s),u=[];for(const E of d){const y=r.documents.get(E);if(!y||o!=="all"&&y.type!==o||i&&y.workspaceId!==i&&y.id!==i||s.filters.domain&&y.domain!==s.filters.domain||s.filters.workspace&&!(((k=y.workspaceName)==null?void 0:k.toLowerCase())||"").includes(s.filters.workspace.toLowerCase())||s.filters.type&&y.type!==s.filters.type||ws(r,y,s))continue;const{score:_,matchedTerms:S}=ys(r,y,s,l);_>=ue.minScore&&u.push({document:y,score:_,matchedTerms:S})}u.sort((E,y)=>y.score-E.score);const m=u.slice(0,a),h=u.length;return{query:e,results:m,totalMatches:h,duration:performance.now()-n}}function ms(r,e){const t=new Set,n=Wn(e),s=_n(e);if(n.length>0){let a=!0;for(const o of n){const i=r.tokens.get(o.term),l=hs(r,o.term),d=new Set;if(i)for(const u of i.documentIds)d.add(u);for(const u of l)for(const m of u.documentIds)d.add(m);if(a){for(const u of d)t.add(u);a=!1}else for(const u of t)d.has(u)||t.delete(u)}}for(const a of s){const o=r.tokens.get(a.term);if(o)for(const i of o.documentIds)t.add(i)}if(n.length===0&&s.length===0)for(const a of r.documents.keys())t.add(a);return t}function hs(r,e,t=.7){const n=[];for(const[s,a]of r.tokens){if(s===e)continue;En(e,s)>=t&&n.push(a)}return n}function ws(r,e,t){const n=ps(t);for(const s of n){const a=r.tokens.get(s.term);if(a&&a.documentIds.has(e.id))return!0}return!1}function ys(r,e,t,n){let s=0;const a=[],o=Wn(t),i=_n(t),l=[...o,...i],d=r.documents.size;for(const u of l){const m=r.tokens.get(u.term);if(m&&m.documentIds.has(e.id)){const h=m.termFrequency.get(e.id)||1,k=m.documentIds.size,E=Math.log(d/k),y=h*ue.tfWeight*(E*ue.idfWeight);s+=y,a.push(u.term),e.title&&e.title.toLowerCase().includes(u.original.toLowerCase())&&(s+=ue.exactTitleBoost),e.domain&&u.term===e.domain.toLowerCase()&&(s+=ue.domainBoost)}else{let h=!1;for(const[k,E]of r.tokens)if(E.documentIds.has(e.id)){const y=En(u.term,k);if(y>=.7){const _=E.termFrequency.get(e.id)||1,S=E.documentIds.size,O=Math.log(d/S),D=_*ue.tfWeight*(O*ue.idfWeight)*y*ue.partialMatchPenalty;s+=D,a.push(k),h=!0;break}}!h&&!u.isOr&&(s*=.1)}}if(n&&e.lastAccessed){const u=ks(e.lastAccessed);s*=1+u}return s=Math.min(1,s/(l.length*5)),{score:s,matchedTerms:[...new Set(a)]}}function ks(r){const e=Date.now(),t=new Date(r).getTime(),n=(e-t)/(1e3*60*60),s=Math.pow(.5,n/ue.recencyHalfLife);return ue.maxRecencyBoost*s}function bs(r,e,t=10){if(e.length<2)return[];const n=e.toLowerCase(),s=[];for(const[a,o]of r.tokens)a.startsWith(n)&&s.push({term:a,count:o.documentIds.size});return s.sort((a,o)=>o.count-a.count).slice(0,t).map(a=>a.term)}function Ss(r,e,t=10){const n=Z(e,{stem:!1});if(n.length===0)return[];const s=new Map;for(const o of n){const i=r.tokens.get(o);if(i)for(const l of i.documentIds)s.set(l,(s.get(l)||0)+1);for(const[l,d]of r.tokens)if(l.startsWith(o))for(const u of d.documentIds)s.set(u,(s.get(u)||0)+.5)}return Array.from(s.entries()).sort((o,i)=>i[1]-o[1]).slice(0,t).map(([o])=>r.documents.get(o)).filter(o=>o!==void 0)}const Ts="https://api.anthropic.com/v1/messages",As="2023-06-01",Is="claude-sonnet-4-20250514",Es=1024;class ge extends Error{constructor(e,t,n){super(e),this.statusCode=t,this.errorType=n,this.name="ClaudeAPIError"}}class Ms{constructor(){M(this,"apiKey",null);M(this,"model",Is)}setApiKey(e){this.apiKey=e}getApiKeyMasked(){return this.apiKey?this.apiKey.length<=8?"****":`${this.apiKey.slice(0,4)}...${this.apiKey.slice(-4)}`:null}isConfigured(){return this.apiKey!==null&&this.apiKey.length>0}setModel(e){this.model=e}async sendMessage(e,t,n){var a,o;if(!this.apiKey)throw new ge("Claude API key not configured");const s={model:(n==null?void 0:n.model)||this.model,max_tokens:(n==null?void 0:n.maxTokens)||Es,...t&&{system:t},messages:e,...(n==null?void 0:n.temperature)!==void 0&&{temperature:n.temperature},...(n==null?void 0:n.stopSequences)&&{stop_sequences:n.stopSequences}};try{const i=await fetch(Ts,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.apiKey,"anthropic-version":As,"anthropic-dangerous-direct-browser-access":"true"},body:JSON.stringify(s)});if(!i.ok){const u=await i.json().catch(()=>({}));throw new ge(((a=u.error)==null?void 0:a.message)||`API request failed with status ${i.status}`,i.status,(o=u.error)==null?void 0:o.type)}return(await i.json()).content.filter(u=>u.type==="text").map(u=>u.text).join("")}catch(i){throw i instanceof ge?i:new ge(i instanceof Error?i.message:"Unknown error occurred")}}async ask(e,t){return this.sendMessage([{role:"user",content:e}],t)}async testConnection(){try{return await this.sendMessage([{role:"user",content:'Respond with just the word "OK"'}],'You are a connection test. Respond with just "OK".',{maxTokens:10}),{success:!0}}catch(e){return{success:!1,error:e instanceof ge?e.message:"Connection test failed"}}}}let vt=null;function ye(){return vt||(vt=new Ms),vt}const Cs=`You are a workspace organization assistant for a browser extension called Mnemonic. Analyze the user's browser workspaces and suggest improvements.
  2  
  3  Types of suggestions you can make:
  4  1. "organize" - Group related standalone workspaces under a new parent workspace
  5  2. "merge" - Combine similar workspaces that have overlapping content
  6  3. "split" - Divide a workspace that contains unrelated tabs
  7  4. "rename" - Suggest better names for workspaces with unclear names
  8  5. "transcendent" - Suggest workspaces that should be marked as transcendent (persist across context switches, like Email or Calendar)
  9  
 10  Response format (JSON array):
 11  [
 12    {
 13      "type": "organize",
 14      "description": "Brief explanation of why this change helps",
 15      "affectedWorkspaces": ["workspace-id-1", "workspace-id-2"],
 16      "suggestedAction": {
 17        "type": "createParent",
 18        "params": { "name": "Suggested Parent Name", "children": ["id1", "id2"] }
 19      },
 20      "confidence": 0.85
 21    }
 22  ]
 23  
 24  Guidelines:
 25  - Be concise and practical
 26  - Only suggest changes that would meaningfully improve organization
 27  - Return empty array [] if no suggestions are needed
 28  - Confidence should be between 0 and 1
 29  - Consider tab domains and titles when grouping`,xs=`You categorize browser tabs into workspaces. Given a list of tabs and existing workspaces, assign each tab to the most appropriate workspace.
 30  
 31  Rules:
 32  1. Prefer existing workspaces when there's a good fit
 33  2. Suggest "NEW: [name]" for tabs that don't fit existing workspaces
 34  3. Group related tabs together in new workspaces
 35  4. Keep suggestions practical (3-7 tabs per workspace is ideal)
 36  5. Consider the domain and page title when categorizing
 37  
 38  Respond with JSON only: { "workspaceName": ["tab1 title", "tab2 title"], ... }`,vs=`You suggest concise, descriptive names for parent workspaces based on their child workspaces.
 39  
 40  Guidelines:
 41  - Names should be 1-3 words
 42  - Capture the common theme
 43  - Be specific but not too narrow
 44  - Avoid generic names like "Misc" or "Other"
 45  
 46  Respond with exactly 3 names, one per line, no numbering or explanation.`,Ps=`You suggest a concise, descriptive name for a browser workspace based on the tabs it contains. Also suggest the best parent workspace to organize it under, if any.
 47  
 48  Guidelines for naming:
 49  - Name should be 1-4 words maximum
 50  - Capture the main theme or purpose of the tabs
 51  - Be specific but memorable (e.g., "React Docs" not "Programming Documentation")
 52  - Avoid generic names like "Research" or "Work" unless truly appropriate
 53  
 54  Guidelines for parent suggestion:
 55  - Suggest an existing parent workspace if the tabs clearly fit that category
 56  - Suggest null if the workspace should be standalone
 57  - Consider both the tab content and the parent workspace names
 58  
 59  Response format (JSON only):
 60  {
 61    "name": "Suggested Workspace Name",
 62    "parentId": "parent-id-or-null",
 63    "reasoning": "Brief explanation of why this name and parent were chosen"
 64  }`,Ws=`Identify workspaces that should be marked as "transcendent" - workspaces that should persist across all context switches because they are always needed.
 65  
 66  Common transcendent workspaces:
 67  - Email clients (Gmail, Outlook, etc.)
 68  - Calendar applications
 69  - Chat/messaging (Slack, Discord, etc.)
 70  - Password managers
 71  - Note-taking apps used across projects
 72  - Music/media players
 73  
 74  Return a JSON array of workspace IDs that should be transcendent:
 75  ["workspace-id-1", "workspace-id-2"]
 76  
 77  Only suggest workspaces that truly belong across all contexts.`,_s=`You generate concise, abstract summaries describing what a workspace is FOR, based primarily on its name.
 78  
 79  Guidelines:
 80  - Write 1-2 sentences maximum
 81  - The WORKSPACE NAME is the primary indicator of purpose - use it as your main guide
 82  - The tabs are secondary context to help understand the general domain, but DO NOT describe their specific content
 83  - Describe the workspace's PURPOSE and intended use, not its current contents
 84  - The summary should remain accurate even if the tabs change completely
 85  - DO NOT mention specific websites, page titles, articles, topics, or content
 86  - DO NOT reference specific URLs, domains, services, or current events
 87  - Use language that describes the workspace's function: "A workspace for...", "Dedicated to...", "Used for..."
 88  - Keep it generic enough that any related content would fit
 89  
 90  Example - Workspace named "News Research":
 91  Good: "A workspace dedicated to news gathering and current events research. Used for collecting and organizing topical information from various sources."
 92  Bad: "Research into political developments and government affairs with focus on congressional oversight."
 93  
 94  Example - Workspace named "Frontend Dev":
 95  Good: "A workspace for frontend development work and web UI implementation. Supports coding, documentation, and technical reference needs."
 96  Bad: "Learning focused on React patterns and Next.js architecture with component design exploration."
 97  
 98  Respond with just the summary text, no JSON or formatting.`,Os=`You generate concise, abstract summaries describing what a parent workspace context is FOR, based primarily on its name.
 99  
100  Guidelines:
101  - Write 1-2 sentences maximum
102  - The PARENT WORKSPACE NAME is the primary indicator of purpose - use it as your main guide
103  - Child workspace names provide secondary context about the scope, but DO NOT list them
104  - Describe the parent context's PURPOSE and intended use as a container/project
105  - The summary should remain accurate even if child workspaces are added or removed
106  - DO NOT mention specific child workspace names
107  - Use language that describes the context's function: "A project context for...", "An organizational container for...", "A workspace collection dedicated to..."
108  - Keep it generic enough that related child workspaces would fit
109  
110  Example - Parent named "E-commerce Project":
111  Good: "A project context for e-commerce development work. Organizes related workspaces for building and maintaining online retail functionality."
112  Bad: "Contains the 'API Development' workspace for building endpoints and the 'Database Design' workspace for schema work."
113  
114  Respond with just the summary text, no JSON or formatting.`;function On(r){return r.map(e=>{var o,i,l;const t=e.isTranscendent?" [TRANSCENDENT]":"";if(e.type==="parent")return`[Parent${t}] ${e.name} (ID: ${e.id}, ${((o=e.children)==null?void 0:o.length)||0} children)`;const n=(i=e.tabs)==null?void 0:i.slice(0,5).map(d=>{try{return`${new URL(d.url).hostname.replace("www.","")}: ${d.title.slice(0,40)}`}catch{return d.title.slice(0,50)}}),s=((l=e.tabs)==null?void 0:l.length)||0,a=s>5?` +${s-5} more`:"";return`[${e.type}${t}] ${e.name} (ID: ${e.id}):
115    ${n==null?void 0:n.join(`
116    `)}${a}`}).join(`
117  
118  `)}function Pt(r){return r.map(e=>{try{const t=new URL(e.url).hostname.replace("www.",""),n=e.enrichedTitle||e.title;return e.description&&e.description!==n?`- ${n} [${t}]: ${e.description.slice(0,150)}`:`- ${n} [${t}]`}catch{return`- ${e.title} [${e.url}]`}}).join(`
119  `)}function Ns(r){return r.map(e=>`- ${e.name} (${e.type}, ID: ${e.id})`).join(`
120  `)}class Ds{constructor(){M(this,"client",ye())}async getSuggestions(e){if(!this.client.isConfigured())return{success:!1,suggestions:[],error:"Claude API key not configured"};if(e.length===0)return{success:!0,suggestions:[]};const n=[{role:"user",content:`Analyze these browser workspaces and suggest organizational improvements:
121  
122  ${On(e.map(s=>({id:s.id,name:s.name,type:s.type,isTranscendent:s.isTranscendent,tabs:"tabs"in s?s.tabs:void 0,children:"children"in s?s.children:void 0})))}
123  
124  Provide suggestions in JSON format.`}];try{const s=await this.client.sendMessage(n,Cs,{maxTokens:2048});return{success:!0,suggestions:this.parseSuggestions(s)}}catch(s){const a=s instanceof ge?s.message:"Failed to get suggestions";return console.error("[Claude] Suggestion error:",a),{success:!1,suggestions:[],error:a}}}async suggestParentName(e){if(!this.client.isConfigured())return["New Project","Workspace Group","Collection"];const n=[{role:"user",content:`Suggest 3 concise names for a parent workspace containing these child workspaces:
125  
126  ${e.map(s=>`${s.name}: ${s.tabs.slice(0,5).map(a=>a.title).join(", ")}${s.tabs.length>5?"...":""}`).join(`
127  `)}`}];try{const a=(await this.client.sendMessage(n,vs,{maxTokens:100})).split(`
128  `).map(o=>o.trim()).filter(o=>o.length>0&&o.length<50).slice(0,3);return a.length>0?a:["New Project","Workspace Group","Collection"]}catch{return["New Project","Workspace Group","Collection"]}}async categorizeOrphanTabs(e,t){if(!this.client.isConfigured())return{success:!1,categories:[],error:"Claude API key not configured"};if(e.length===0)return{success:!0,categories:[]};const n=Pt(e.map(o=>({url:o.url,title:o.title}))),s=Ns(t.map(o=>({name:o.name,type:o.type,id:o.id}))),a=[{role:"user",content:`Categorize these tabs into existing workspaces or suggest new ones:
129  
130  Tabs:
131  ${n}
132  
133  Existing workspaces:
134  ${s}
135  
136  Respond with JSON mapping workspace names to arrays of tab titles.`}];try{const o=await this.client.sendMessage(a,xs,{maxTokens:2048});return{success:!0,categories:this.parseCategorization(o)}}catch(o){const i=o instanceof ge?o.message:"Failed to categorize tabs";return{success:!1,categories:[],error:i}}}async suggestTranscendent(e){if(!this.client.isConfigured())return[];const t=e.filter(a=>"tabs"in a&&a.tabs.length>0);if(t.length===0)return[];const s=[{role:"user",content:`Identify which of these workspaces should be marked as transcendent (persist across all context switches):
137  
138  ${On(t.map(a=>({id:a.id,name:a.name,type:a.type,isTranscendent:a.isTranscendent,tabs:"tabs"in a?a.tabs:void 0})))}`}];try{const o=(await this.client.sendMessage(s,Ws,{maxTokens:500})).match(/\[[\s\S]*?\]/);if(o){const i=JSON.parse(o[0]);if(Array.isArray(i))return i.filter(l=>typeof l=="string")}return[]}catch{return[]}}async suggestWorkspaceNameAndParent(e,t){if(console.log("[SuggestionEngine] suggestWorkspaceNameAndParent called"),console.log("[SuggestionEngine] Client configured:",this.client.isConfigured()),!this.client.isConfigured())return console.log("[SuggestionEngine] Client not configured, returning error"),{success:!1,name:null,parentId:null,reasoning:null,error:"Claude API key not configured"};if(e.length===0)return console.log("[SuggestionEngine] No tabs provided"),{success:!1,name:null,parentId:null,reasoning:null,error:"No tabs provided"};const n=Pt(e),s=t.length>0?t.map(o=>`- ${o.name} (ID: ${o.id})`).join(`
139  `):"No parent workspaces available",a=[{role:"user",content:`Suggest a name and parent workspace for a new workspace containing these tabs:
140  
141  Tabs:
142  ${n}
143  
144  Available parent workspaces:
145  ${s}
146  
147  Respond with JSON only.`}];console.log("[SuggestionEngine] Sending request to Claude API...");try{const o=await this.client.sendMessage(a,Ps,{maxTokens:300});console.log("[SuggestionEngine] Got response:",o);const i=o.match(/\{[\s\S]*\}/);if(i){const l=JSON.parse(i[0]),d=l.parentId==="null"||l.parentId===null?null:l.parentId,u=d&&t.some(m=>m.id===d)?d:null;return{success:!0,name:l.name||null,parentId:u,reasoning:l.reasoning||null}}return console.log("[SuggestionEngine] Failed to parse JSON from response"),{success:!1,name:null,parentId:null,reasoning:null,error:"Failed to parse response"}}catch(o){return console.error("[SuggestionEngine] API error:",o),{success:!1,name:null,parentId:null,reasoning:null,error:o instanceof ge?o.message:"Failed to get naming suggestion"}}}async generateSummaryFromTabs(e,t){if(!this.client.isConfigured())return{success:!1,summary:null,error:"Claude API key not configured"};if(t.length===0)return{success:!1,summary:null,error:"No tabs provided"};const n=Pt(t),s=[{role:"user",content:`Generate a brief summary for the workspace "${e}" based on these tabs:
148  
149  ${n}`}];try{return{success:!0,summary:(await this.client.sendMessage(s,_s,{maxTokens:200})).trim()}}catch(a){return{success:!1,summary:null,error:a instanceof ge?a.message:"Failed to generate summary"}}}async generateSummaryFromChildren(e,t){if(!this.client.isConfigured())return{success:!1,summary:null,error:"Claude API key not configured"};if(t.length===0)return{success:!1,summary:null,error:"No child workspaces provided"};const n=t.map(a=>a.summary?`- ${a.name}: ${a.summary}`:`- ${a.name}`).join(`
150  `),s=[{role:"user",content:`Generate a brief summary for the parent workspace context "${e}" based on these child workspaces:
151  
152  ${n}`}];try{return{success:!0,summary:(await this.client.sendMessage(s,Os,{maxTokens:200})).trim()}}catch(a){return{success:!1,summary:null,error:a instanceof ge?a.message:"Failed to generate summary"}}}parseSuggestions(e){try{const t=e.match(/\[[\s\S]*\]/);if(t){const n=JSON.parse(t[0]);if(Array.isArray(n))return n.filter(s=>s&&typeof s.type=="string"&&typeof s.description=="string"&&Array.isArray(s.affectedWorkspaces)&&s.suggestedAction)}}catch{}return[]}parseCategorization(e){try{const t=e.match(/\{[\s\S]*\}/);if(t){const n=JSON.parse(t[0]);return Object.entries(n).map(([s,a])=>({workspaceName:s,tabTitles:Array.isArray(a)?a:[],isNew:s.startsWith("NEW:")}))}}catch{}return[]}}let Wt=null;function De(){return Wt||(Wt=new Ds),Wt}const Fs=[/^perplexity$/i,/^google$/i,/^youtube$/i,/^twitter$/i,/^facebook$/i,/^reddit$/i,/^github$/i,/^linkedin$/i,/^slack$/i,/^discord$/i,/^notion$/i,/^figma$/i,/^chatgpt$/i,/^claude$/i,/^home$/i,/^dashboard$/i,/^untitled$/i,/^new tab$/i,/^loading\.\.\.?$/i];function Us(r,e){if(!r||r.trim().length===0)return!0;const t=r.trim();if(t.length<4)return!0;for(const n of Fs)if(n.test(t))return!0;try{const s=new URL(e).hostname.replace(/^www\./,""),o=s.split(".")[0];if(t.toLowerCase()===o.toLowerCase()||t.toLowerCase()===s.toLowerCase())return!0;const i=t.toLowerCase().replace(/[^a-z0-9]/g,""),l=s.toLowerCase().replace(/[^a-z0-9]/g,"");if(i===l)return!0}catch{}return!1}function _t(r){return r.replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim()}function Ce(r){return r.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&apos;/g,"'").replace(/&#x([0-9a-fA-F]+);/g,(e,t)=>String.fromCharCode(parseInt(t,16))).replace(/&#(\d+);/g,(e,t)=>String.fromCharCode(parseInt(t,10)))}function Bs(r,e){const t=r.match(e);return t&&t[1]?Ce(_t(t[1])).trim():null}function Ot(r,e){const t=new RegExp(`<meta[^>]*name=["']${e}["'][^>]*content=["']([^"']*)["']`,"i");let n=r.match(t);if(n&&n[1])return Ce(n[1]).trim();const s=new RegExp(`<meta[^>]*content=["']([^"']*)["'][^>]*name=["']${e}["']`,"i");if(n=r.match(s),n&&n[1])return Ce(n[1]).trim();const a=new RegExp(`<meta[^>]*property=["']${e}["'][^>]*content=["']([^"']*)["']`,"i");if(n=r.match(a),n&&n[1])return Ce(n[1]).trim();const o=new RegExp(`<meta[^>]*content=["']([^"']*)["'][^>]*property=["']${e}["']`,"i");return n=r.match(o),n&&n[1]?Ce(n[1]).trim():null}function Ls(r){const e={title:null,heading:null,description:null,firstParagraph:null};try{e.title=Bs(r,/<title[^>]*>([^<]*)<\/title>/i);const t=r.match(/<h1[^>]*>([\s\S]*?)<\/h1>/i);if(t&&t[1]){const s=Ce(_t(t[1])).trim();s.length>0&&(e.heading=s.slice(0,200))}const n=Ot(r,"og:title");if(n&&(!e.heading||n.length>e.heading.length)&&(e.heading=n.slice(0,200)),e.description=Ot(r,"description"),e.description&&(e.description=e.description.slice(0,300)),!e.description){const s=Ot(r,"og:description");s&&(e.description=s.slice(0,300))}if(!e.description&&!e.firstParagraph){const s=/<p[^>]*>([\s\S]*?)<\/p>/gi;let a;for(;(a=s.exec(r))!==null;){const o=Ce(_t(a[1])).trim();if(o.length>50){e.firstParagraph=o.slice(0,300);break}}}}catch(t){console.error("[TabContentExtractor] Error parsing HTML:",t)}return e}function $s(r,e){const t=[];return e.heading&&e.heading!==r?t.push(e.heading):e.title&&e.title!==r&&t.push(e.title),e.description?t.push(e.description):e.firstParagraph&&t.push(e.firstParagraph),t.length>0?t.join(" - ").slice(0,500):r}const Nt={status:"disconnected",lastSyncTime:null,lastExternalMtime:null,error:null,configDir:null,hostVersion:null},Nn={version:1,lastModified:new Date().toISOString(),browsers:{}},Dn="http://127.0.0.1:8765",Rs=1e4,ke="mnemonic_bridge_url";class Fn{constructor(){M(this,"baseUrl",Dn);M(this,"state",{...Nt});M(this,"listeners",new Set);M(this,"reconnectAttempts",0);M(this,"maxReconnectAttempts",3);M(this,"connected",!1);M(this,"lastKnownBrowserTimestamps",{})}getState(){return{...this.state}}getBaseUrl(){return this.baseUrl}setBaseUrl(e){this.baseUrl=e.replace(/\/+$/,"")}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){const e=this.getState();for(const t of this.listeners)t(e)}updateState(e){this.state={...this.state,...e},this.notify()}async request(e,t={}){var o;const n=`${this.baseUrl}${e}`,s=new AbortController,a=setTimeout(()=>s.abort(),Rs);try{const i=await fetch(n,{...t,signal:s.signal,headers:{"Content-Type":"application/json",...t.headers}});if(clearTimeout(a),!i.ok){const l=await i.json().catch(()=>({}));throw new Error(((o=l.detail)==null?void 0:o.error)||l.error||`HTTP ${i.status}`)}return await i.json()}catch(i){throw clearTimeout(a),i instanceof Error&&i.name==="AbortError"?new Error("Request timed out"):i}}async connect(){if(this.connected)return!0;this.updateState({status:"connecting",error:null});try{const e=await g.storage.local.get(ke);e[ke]&&(this.baseUrl=e[ke]);const t=await this.health();if(t.status==="ok")return this.connected=!0,this.updateState({status:"connected",hostVersion:t.version.api_version,configDir:t.config_dir}),this.reconnectAttempts=0,console.log("[Mnemonic] REST bridge connected:",t),!0;throw new Error("Health check failed")}catch(e){const t=e instanceof Error?e.message:"Connection failed";return this.updateState({status:"error",error:t}),this.connected=!1,console.error("[Mnemonic] REST bridge connection failed:",e),this.reconnectAttempts<this.maxReconnectAttempts&&(this.reconnectAttempts++,setTimeout(()=>{console.log(`[Mnemonic] Attempting reconnection (${this.reconnectAttempts}/${this.maxReconnectAttempts})`),this.connect()},1e3*this.reconnectAttempts)),!1}}disconnect(){this.connected=!1,this.updateState({status:"disconnected",error:null})}isConnected(){return this.connected&&this.state.status==="connected"}async ensureConnected(){return this.isConnected()?!0:this.connect()}async health(){return this.request("/health")}async getInfo(){return this.request("/info")}async read(){const e=await this.request("/workspaces");return e.success&&e.mtime&&this.updateState({lastExternalMtime:e.mtime}),e}async write(e){this.updateState({status:"syncing"});try{const t=await this.request("/workspaces",{method:"POST",body:JSON.stringify({data:e})});return t.success?this.updateState({status:"connected",lastSyncTime:new Date().toISOString(),lastExternalMtime:t.mtime||null}):this.updateState({status:"error",error:"Write failed"}),t}catch(t){const n=t instanceof Error?t.message:"Write failed";throw this.updateState({status:"error",error:n}),t}}async delete(){return this.request("/workspaces",{method:"DELETE"})}async restore(){return this.request("/workspaces/restore",{method:"POST"})}async getBrowserTimestamps(){const e=await this.read();if(!e.success||!e.data)return{};const t=e.data,n={};for(const[s,a]of Object.entries(t.browsers||{}))a!=null&&a.lastUpdated&&(n[s]=a.lastUpdated);return n}updateKnownBrowserTimestamps(e){this.lastKnownBrowserTimestamps={...e}}isFreshStartup(){return Object.keys(this.lastKnownBrowserTimestamps).length===0}async checkForChanges(){console.log("[Mnemonic:Bridge] checkForChanges() called"),console.log("[Mnemonic:Bridge] lastKnownBrowserTimestamps:",this.lastKnownBrowserTimestamps),console.log("[Mnemonic:Bridge] lastExternalMtime:",this.state.lastExternalMtime);try{const e=await this.getInfo();if(console.log("[Mnemonic:Bridge] File info:",{success:e.success,exists:e.exists,mtime:e.mtime}),!e.success||!e.exists)return console.log("[Mnemonic:Bridge] File does not exist or info failed"),!1;const t=e.mtime||0,n=this.state.lastExternalMtime||0;if(console.log("[Mnemonic:Bridge] Mtime comparison:",{externalMtime:t,lastKnownMtime:n,changed:t>n}),t<=n)return console.log("[Mnemonic:Bridge] File mtime unchanged, no changes"),!1;console.log("[Mnemonic:Bridge] File mtime changed, checking browser timestamps...");const s=await this.getBrowserTimestamps();console.log("[Mnemonic:Bridge] Current browser timestamps in file:",s);for(const[a,o]of Object.entries(s)){const i=this.lastKnownBrowserTimestamps[a];if(console.log("[Mnemonic:Bridge] Comparing browser:",a,{fileTimestamp:o,lastKnown:i}),!i||new Date(o)>new Date(i))return console.log("[Mnemonic:Bridge] Browser changes detected:",{browser:a,timestamp:o,lastKnown:i}),!0}return console.log("[Mnemonic:Bridge] No browser timestamp changes detected"),!1}catch(e){return console.error("[Mnemonic:Bridge] checkForChanges error:",e),!1}}async listBackups(){return this.request("/backups")}async previewBackup(e){return this.request(`/backups/${encodeURIComponent(e)}`)}async restoreFromBackup(e){return this.request("/backups/restore",{method:"POST",body:JSON.stringify({filename:e})})}async deleteBackup(e){return this.request(`/backups/${encodeURIComponent(e)}`,{method:"DELETE"})}async pruneBackups(){return this.request("/backups/prune",{method:"POST"})}async searchBackups(e){return this.request(`/backups/search?workspace=${encodeURIComponent(e)}`)}async restoreSelectiveFromBackup(e,t){return this.request("/backups/restore-selective",{method:"POST",body:JSON.stringify({filename:e,workspace_ids:t})})}async pollTransfers(e){return this.request(`/transfers/${encodeURIComponent(e)}`)}async sendTransfer(e){return this.request("/transfers",{method:"POST",body:JSON.stringify(e)})}async saveBridgeUrl(e){this.setBaseUrl(e),await g.storage.local.set({[ke]:e})}async loadBridgeUrl(){const e=await g.storage.local.get(ke);return e[ke]&&(this.baseUrl=e[ke]),this.baseUrl}}let Dt=null;function ae(){return Dt||(Dt=new Fn),Dt}const js=Object.freeze(Object.defineProperty({__proto__:null,BRIDGE_URL_STORAGE_KEY:ke,DEFAULT_BRIDGE_URL:Dn,RestBridge:Fn,getRestBridge:ae},Symbol.toStringTag,{value:"Module"})),Ks="MnemonicSync",be="handles",Ft="syncDirectory",me="mnemonic-workspaces.json",Un="mnemonic-workspaces.backup.json";function Bn(){return"showDirectoryPicker"in window}class zs{constructor(){M(this,"directoryHandle",null);M(this,"state",{...Nt});M(this,"listeners",new Set);M(this,"lastKnownMtime",0)}getState(){return{...this.state}}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){const e=this.getState();for(const t of this.listeners)t(e)}updateState(e){this.state={...this.state,...e},this.notify()}async openDB(){return new Promise((e,t)=>{const n=indexedDB.open(Ks,1);n.onerror=()=>t(n.error),n.onsuccess=()=>e(n.result),n.onupgradeneeded=s=>{const a=s.target.result;a.objectStoreNames.contains(be)||a.createObjectStore(be)}})}async storeHandle(e){const t=await this.openDB();return new Promise((n,s)=>{const a=t.transaction(be,"readwrite"),i=a.objectStore(be).put(e,Ft);i.onerror=()=>{t.close(),s(i.error)},i.onsuccess=()=>n(),a.oncomplete=()=>t.close(),a.onerror=()=>t.close(),a.onabort=()=>t.close()})}async retrieveHandle(){try{const e=await this.openDB();return new Promise((t,n)=>{const s=e.transaction(be,"readonly"),o=s.objectStore(be).get(Ft);o.onerror=()=>{e.close(),n(o.error)},o.onsuccess=()=>t(o.result||null),s.oncomplete=()=>e.close(),s.onerror=()=>e.close(),s.onabort=()=>e.close()})}catch{return null}}async clearHandle(){try{const e=await this.openDB();return new Promise((t,n)=>{const s=e.transaction(be,"readwrite"),o=s.objectStore(be).delete(Ft);o.onerror=()=>{e.close(),n(o.error)},o.onsuccess=()=>t(),s.oncomplete=()=>e.close(),s.onerror=()=>e.close(),s.onabort=()=>e.close()})}catch{}}async verifyPermission(e,t=!0){const n={mode:t?"readwrite":"read"};return await e.queryPermission(n)==="granted"||await e.requestPermission(n)==="granted"}async connect(){if(!Bn())return this.updateState({status:"error",error:"File System Access API not supported in this browser"}),!1;this.updateState({status:"connecting",error:null});try{const e=await this.retrieveHandle();return e&&await this.verifyPermission(e)?(this.directoryHandle=e,this.updateState({status:"connected",configDir:e.name}),console.log("[Mnemonic] Filesystem bridge connected to:",e.name),!0):(this.updateState({status:"disconnected",error:'No directory selected. Click "Select Directory" to choose a sync folder.'}),!1)}catch(e){const t=e instanceof Error?e.message:"Connection failed";return this.updateState({status:"error",error:t}),console.error("[Mnemonic] Filesystem bridge connection failed:",e),!1}}async selectDirectory(){if(!Bn())return this.updateState({status:"error",error:"File System Access API not supported in this browser"}),!1;try{const e=await window.showDirectoryPicker({id:"mnemonic-sync",mode:"readwrite",startIn:"documents"});return await this.storeHandle(e),this.directoryHandle=e,this.updateState({status:"connected",configDir:e.name,error:null}),console.log("[Mnemonic] Selected sync directory:",e.name),!0}catch(e){if(e instanceof Error&&e.name==="AbortError")return this.updateState({status:"disconnected",error:"Directory selection cancelled"}),!1;const t=e instanceof Error?e.message:"Failed to select directory";return this.updateState({status:"error",error:t}),!1}}async disconnect(){await this.clearHandle(),this.directoryHandle=null,this.updateState({status:"disconnected",error:null,configDir:null})}isConnected(){return this.directoryHandle!==null&&this.state.status==="connected"}async getInfo(){if(!this.directoryHandle)return{success:!1,error:"Not connected",exists:!1};try{const t=await(await this.directoryHandle.getFileHandle(me,{create:!1})).getFile();return{success:!0,exists:!0,path:`${this.directoryHandle.name}/${me}`,mtime:t.lastModified,size:t.size,directoryName:this.directoryHandle.name}}catch(e){return e instanceof Error&&e.name==="NotFoundError"?{success:!0,exists:!1,path:`${this.directoryHandle.name}/${me}`,directoryName:this.directoryHandle.name}:{success:!1,error:e instanceof Error?e.message:"Failed to get file info",exists:!1}}}async read(){if(!this.directoryHandle)return{success:!1,error:"Not connected",exists:!1};try{const t=await(await this.directoryHandle.getFileHandle(me,{create:!1})).getFile(),n=await t.text(),s=JSON.parse(n);return this.lastKnownMtime=t.lastModified,this.updateState({lastExternalMtime:t.lastModified}),{success:!0,data:s,exists:!0,mtime:t.lastModified}}catch(e){return e instanceof Error&&e.name==="NotFoundError"?{success:!0,exists:!1}:{success:!1,error:e instanceof Error?e.message:"Failed to read file",exists:!1}}}async write(e){if(!this.directoryHandle)return{success:!1,error:"Not connected"};this.updateState({status:"syncing"});try{await this.createBackup();const t=await this.directoryHandle.getFileHandle(me,{create:!0}),n=await t.createWritable(),s=JSON.stringify(e,null,2);await n.write(s),await n.close();const a=await t.getFile();return this.lastKnownMtime=a.lastModified,this.updateState({status:"connected",lastSyncTime:new Date().toISOString(),lastExternalMtime:a.lastModified}),{success:!0,mtime:a.lastModified,path:`${this.directoryHandle.name}/${me}`}}catch(t){const n=t instanceof Error?t.message:"Write failed";return this.updateState({status:"error",error:n}),{success:!1,error:n}}}async createBackup(){if(this.directoryHandle)try{const n=await(await(await this.directoryHandle.getFileHandle(me,{create:!1})).getFile()).text(),a=await(await this.directoryHandle.getFileHandle(Un,{create:!0})).createWritable();await a.write(n),await a.close()}catch{}}async restore(){if(!this.directoryHandle)return{success:!1,error:"Not connected"};try{const n=await(await(await this.directoryHandle.getFileHandle(Un,{create:!1})).getFile()).text();JSON.parse(n);const s=await this.directoryHandle.getFileHandle(me,{create:!0}),a=await s.createWritable();await a.write(n),await a.close();const o=await s.getFile();return this.lastKnownMtime=o.lastModified,this.updateState({lastExternalMtime:o.lastModified}),{success:!0}}catch(e){return e instanceof Error&&e.name==="NotFoundError"?{success:!1,error:"No backup file found"}:{success:!1,error:e instanceof Error?e.message:"Restore failed"}}}async delete(){if(!this.directoryHandle)return{success:!1,error:"Not connected"};try{return await this.directoryHandle.removeEntry(me),{success:!0}}catch(e){return e instanceof Error&&e.name==="NotFoundError"?{success:!0}:{success:!1,error:e instanceof Error?e.message:"Delete failed"}}}async checkForChanges(){if(!this.directoryHandle)return!1;try{const e=await this.getInfo();if(!e.success||!e.exists)return!1;const t=e.mtime||0;return t>this.lastKnownMtime?(console.log("[Mnemonic] Filesystem external changes detected:",{external:t,lastKnown:this.lastKnownMtime}),!0):!1}catch{return!1}}async ping(){if(!this.directoryHandle)return{success:!1,error:"Not connected"};try{return await this.verifyPermission(this.directoryHandle)?{success:!0,directoryName:this.directoryHandle.name}:{success:!1,error:"Permission denied"}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Ping failed"}}}}let Ut=null;function Gs(){return Ut||(Ut=new zs),Ut}const Bt="syncAncestorState";async function Hs(){try{const e=(await g.storage.local.get(Bt))[Bt];return!e||!e.workspaces||!e.timestamp?null:e}catch(r){return console.error("[Mnemonic:Ancestor] Failed to load ancestor state:",r),null}}async function Vs(r){try{await g.storage.local.set({[Bt]:r}),console.log("[Mnemonic:Ancestor] Saved ancestor state with",Object.keys(r.workspaces).length,"workspaces")}catch(e){throw console.error("[Mnemonic:Ancestor] Failed to save ancestor state:",e),e}}function qs(r,e){return!r||!r.workspaces?null:r.workspaces[e]||null}function de(r){try{const e=new URL(r);e.hash="",e.pathname.length>1&&(e.pathname=e.pathname.replace(/\/+$/,"")),e.searchParams.sort();const t=e.toString();return t.endsWith("/")&&e.pathname==="/"?t.slice(0,-1):t}catch{return r}}function Ys(r,e,t){const n=r.map(de),s=e.map(de),a=t.map(de),o=new Set(a),i=new Set(n),l=new Set(s),d=n.filter(y=>!o.has(y)),u=new Set(a.filter(y=>!i.has(y))),m=s.filter(y=>!o.has(y)),h=new Set(a.filter(y=>!l.has(y))),k=new Set(a);for(const y of u)k.delete(y);for(const y of h)k.delete(y);for(const y of d)k.add(y);for(const y of m)k.add(y);const E=d.filter(y=>m.some(_=>de(_)===de(y)));return{mergedUrls:[...k],localAdded:d,externalAdded:m,conflicts:E}}function Js(r,e,t){const n=new Map;for(const o of e)n.set(de(o.url),o);const s=new Map;for(const o of t)s.set(de(o.url),o);const a=[];for(const o of r){const i=de(o),l=n.get(i),d=s.get(i);l?a.push(l):d?a.push(d):a.push({url:o,title:o,pinned:!1})}return a}function Ln(r){return r.map(e=>e.url)}const it="todoistSettings",xe="todoistOAuthState",He={authorizationEndpoint:"https://todoist.com/oauth/authorize",tokenEndpoint:"https://todoist.com/oauth/access_token",scope:"data:read_write"};function Lt(r){const e=new Uint8Array(r);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}function $n(){return Lt(64)}async function Zs(r){const t=new TextEncoder().encode(r),n=await crypto.subtle.digest("SHA-256",t);return btoa(String.fromCharCode(...new Uint8Array(n))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}class Xs{constructor(){M(this,"clientId",null);M(this,"clientSecret",null)}setOAuthCredentials(e,t){this.clientId=e,this.clientSecret=t||null}isOAuthConfigured(){return this.clientId!==null}async loadSettings(){try{const t=(await g.storage.local.get(it))[it];return t?{...wt,...t}:wt}catch(e){return console.error("[Mnemonic/Todoist] Failed to load settings:",e),wt}}async saveSettings(e){try{const n={...await this.loadSettings(),...e};await g.storage.local.set({[it]:n})}catch(t){throw console.error("[Mnemonic/Todoist] Failed to save settings:",t),t}}async clearSettings(){try{await g.storage.local.remove([it,xe])}catch(e){throw console.error("[Mnemonic/Todoist] Failed to clear settings:",e),e}}async getAccessToken(){return(await this.loadSettings()).accessToken||null}async isAuthenticated(){return await this.getAccessToken()!==null}async initiateOAuth(){if(!this.clientId)throw new Error("OAuth not configured. Call setOAuthCredentials() first or use API token authentication.");const e=Lt(32),t=$n();await Zs(t);const n={state:e,codeVerifier:t,createdAt:Date.now()};await g.storage.local.set({[xe]:n});const s=new URLSearchParams({client_id:this.clientId,scope:He.scope,state:e});return`${He.authorizationEndpoint}?${s.toString()}`}async launchOAuthFlow(){if(!this.clientId)return{success:!1,error:"OAuth not configured"};try{const e=Lt(32),t=$n(),n={state:e,codeVerifier:t,createdAt:Date.now()};await g.storage.local.set({[xe]:n});const s=g.identity.getRedirectURL(),a=new URL(He.authorizationEndpoint);a.searchParams.set("client_id",this.clientId),a.searchParams.set("scope",He.scope),a.searchParams.set("state",e),a.searchParams.set("redirect_uri",s);const o=await g.identity.launchWebAuthFlow({url:a.toString(),interactive:!0}),i=new URL(o),l=i.searchParams.get("code"),d=i.searchParams.get("state"),u=i.searchParams.get("error");if(u)return{success:!1,error:`OAuth error: ${u}`};if(!l)return{success:!1,error:"No authorization code received"};const m=await this.getStoredOAuthState();if(!m||m.state!==d)return{success:!1,error:"State mismatch - possible CSRF attack"};const h=await this.exchangeCodeForToken(l,s);return h.success?(await this.saveSettings({enabled:!0,authMethod:"oauth",accessToken:h.accessToken}),await g.storage.local.remove(xe),{success:!0}):{success:!1,error:h.error}}catch(e){return{success:!1,error:e instanceof Error?e.message:"OAuth flow failed"}}}async exchangeCodeForToken(e,t){if(!this.clientId||!this.clientSecret)return{success:!1,error:"OAuth credentials not configured"};try{const n=await fetch(He.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.clientId,client_secret:this.clientSecret,code:e,redirect_uri:t})});return n.ok?{success:!0,accessToken:(await n.json()).access_token}:{success:!1,error:`Token exchange failed: ${await n.text()}`}}catch(n){return{success:!1,error:n instanceof Error?n.message:"Token exchange failed"}}}async getStoredOAuthState(){try{const t=(await g.storage.local.get(xe))[xe];return t?Date.now()-t.createdAt>3e5?(await g.storage.local.remove(xe),null):t:null}catch{return null}}async authenticateWithApiToken(e){if(!e||e.trim().length===0)return{success:!1,error:"API token is required"};try{const t=await fetch("https://api.todoist.com/api/v1/projects",{headers:{Authorization:`Bearer ${e}`}});return t.ok?(await this.saveSettings({enabled:!0,authMethod:"api_token",accessToken:e}),{success:!0}):t.status===401||t.status===403?{success:!1,error:"Invalid API token"}:{success:!1,error:`API error: ${t.statusText}`}}catch(t){return{success:!1,error:t instanceof Error?t.message:"Connection failed"}}}async disconnect(){await this.clearSettings()}async getAuthMethod(){return(await this.loadSettings()).authMethod||null}}const ve=new Xs;var Ve=(r=>(r.UNAUTHORIZED="UNAUTHORIZED",r.RATE_LIMITED="RATE_LIMITED",r.NOT_FOUND="NOT_FOUND",r.BAD_REQUEST="BAD_REQUEST",r.NETWORK_ERROR="NETWORK_ERROR",r.OFFLINE="OFFLINE",r.TIMEOUT="TIMEOUT",r.SERVER_ERROR="SERVER_ERROR",r.UNKNOWN="UNKNOWN",r))(Ve||{});class j extends Error{constructor(e,t,n=!1,s){super(e),this.code=t,this.retryable=n,this.retryAfter=s,this.name="TodoistError"}getUserMessage(){switch(this.code){case"UNAUTHORIZED":return"Authentication failed. Please reconnect your Todoist account.";case"RATE_LIMITED":return this.retryAfter?`Rate limited. Please try again in ${this.retryAfter} seconds.`:"Rate limited. Please try again in a moment.";case"NOT_FOUND":return"The requested resource was not found.";case"BAD_REQUEST":return"Invalid request. Please check your input.";case"NETWORK_ERROR":return"Network error. Please check your internet connection.";case"OFFLINE":return"You appear to be offline. Please check your connection.";case"TIMEOUT":return"Request timed out. Please try again.";case"SERVER_ERROR":return"Todoist server error. Please try again later.";default:return"An unexpected error occurred."}}}function $t(r){if(typeof navigator<"u"&&!navigator.onLine)return new j("Device is offline","OFFLINE",!0);if(r instanceof TypeError&&(r.message.includes("fetch")||r.message.includes("network")))return new j("Network request failed","NETWORK_ERROR",!0);if(r instanceof DOMException&&r.name==="AbortError")return new j("Request timed out","TIMEOUT",!0);if(r instanceof Response)return Rn(r);if(Qs(r)){const e={status:r.status,statusText:r.statusText||"",headers:new Headers};return Rn(e)}return r instanceof Error?r.message.includes("401")||r.message.includes("unauthorized")?new j(r.message,"UNAUTHORIZED",!1):r.message.includes("429")||r.message.includes("rate limit")?new j(r.message,"RATE_LIMITED",!0):new j(r.message,"UNKNOWN",!1):new j("An unexpected error occurred","UNKNOWN",!1)}function Rn(r){const e=r.status;switch(e){case 400:return new j("Bad request","BAD_REQUEST",!1);case 401:case 403:return new j("Authentication failed","UNAUTHORIZED",!1);case 404:return new j("Resource not found","NOT_FOUND",!1);case 429:{const t=r.headers.get("Retry-After"),n=t?parseInt(t,10):void 0;return new j("Rate limited","RATE_LIMITED",!0,n)}case 500:case 502:case 503:case 504:return new j("Server error","SERVER_ERROR",!0);default:return new j(`HTTP error ${e}`,"UNKNOWN",e>=500)}}function Qs(r){return typeof r=="object"&&r!==null&&"status"in r&&typeof r.status=="number"}async function $(r,e={}){const{maxRetries:t=3,baseDelay:n=1e3,maxDelay:s=1e4,shouldRetry:a=i=>i.retryable}=e;let o=null;for(let i=0;i<=t;i++)try{return await r()}catch(l){if(o=l instanceof j?l:$t(l),i<t&&a(o)){let d=Math.min(n*Math.pow(2,i),s);o.retryAfter&&(d=o.retryAfter*1e3),console.log(`[Mnemonic/Todoist] Retrying in ${d}ms (attempt ${i+1}/${t})`),await ea(d)}else throw o}throw o||new j("Retry failed","UNKNOWN",!1)}function ea(r){return new Promise(e=>setTimeout(e,r))}const Rt="https://api.todoist.com/api/v1",ct="Mnemonic";function ta(r){return r.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function qe(r){if(r==null)return r;if(Array.isArray(r))return r.map(e=>qe(e));if(typeof r=="object"){const e={};for(const[t,n]of Object.entries(r)){const s=ta(t);e[s]=qe(n)}return e}return r}async function X(r,e={},t){const n=await fetch(`${Rt}${r}`,{...e,headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json",...e.headers}});if(!n.ok)throw n;if(n.status===204)return!0;const s=await n.json();return qe(s)}async function Fe(r,e){const t=[];let n=null;do{const s=r.includes("?")?"&":"?",a=n?`${Rt}${r}${s}cursor=${encodeURIComponent(n)}`:`${Rt}${r}`,o=await fetch(a,{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}});if(!o.ok)throw o;const i=await o.json();if(i&&typeof i=="object"&&"results"in i){const l=qe(i.results);t.push(...l),n=i.next_cursor||null}else Array.isArray(i)&&t.push(...qe(i)),n=null}while(n);return t}class na{constructor(){M(this,"masterProjectId",null);M(this,"accessToken",null)}async initializeFromStorage(){const e=await ve.loadSettings();return!e.enabled||!e.accessToken?{connected:!1,masterProjectName:ct,error:"Not connected to Todoist"}:this.initialize(e.accessToken)}async initialize(e){try{this.accessToken=e;let n=(await $(()=>this.getProjects())).find(s=>s.name===ct&&!s.parentId);return n||(n=await $(()=>this.addProject({name:ct}))),this.masterProjectId=n.id,await ve.saveSettings({masterProjectId:n.id,lastSync:new Date().toISOString()}),{connected:!0,authMethod:(await ve.loadSettings()).authMethod,accessToken:e,masterProjectId:n.id,masterProjectName:n.name,lastSync:new Date().toISOString()}}catch(t){const n=t instanceof j?t:$t(t);return n.code===Ve.UNAUTHORIZED&&(await ve.clearSettings(),this.masterProjectId=null,this.accessToken=null),{connected:!1,masterProjectName:ct,error:n.getUserMessage()}}}async disconnect(){await ve.disconnect(),this.masterProjectId=null,this.accessToken=null}isConnected(){return this.accessToken!==null&&this.masterProjectId!==null}getMasterProjectId(){return this.masterProjectId}ensureInitialized(){if(!this.accessToken||!this.masterProjectId)throw new j("Todoist client not initialized",Ve.UNAUTHORIZED,!1);return this.accessToken}async getProjects(){const e=this.accessToken;if(!e)throw new j("Not authenticated",Ve.UNAUTHORIZED,!1);return Fe("/projects",e)}async getWorkspaceProjects(){const e=this.ensureInitialized();console.log("[Mnemonic/Todoist] getWorkspaceProjects: Fetching all projects from Todoist API..."),console.log("[Mnemonic/Todoist] getWorkspaceProjects: masterProjectId =",this.masterProjectId);const t=await $(()=>Fe("/projects",e));console.log("[Mnemonic/Todoist] getWorkspaceProjects: Total projects from API:",t.length),console.log("[Mnemonic/Todoist] getWorkspaceProjects: All projects:",t.map(o=>({id:o.id,name:o.name,parentId:o.parentId})));const n=t.filter(o=>o.parentId===this.masterProjectId);console.log("[Mnemonic/Todoist] getWorkspaceProjects: Mnemonic children (direct):",n.map(o=>({id:o.id,name:o.name})));const s=t.filter(o=>n.some(i=>i.id===o.parentId));console.log("[Mnemonic/Todoist] getWorkspaceProjects: Mnemonic grandchildren:",s.map(o=>({id:o.id,name:o.name})));const a=[...n,...s];return console.log("[Mnemonic/Todoist] getWorkspaceProjects: Returning",a.length,"workspace projects"),a}async addProject(e){const t=this.accessToken;if(!t)throw new j("Not authenticated",Ve.UNAUTHORIZED,!1);const n={name:e.name};return e.parentId&&(n.parent_id=e.parentId),X("/projects",{method:"POST",body:JSON.stringify(n)},t)}async createWorkspaceProject(e,t,n){const s=this.ensureInitialized(),a=t==="child"&&n?n:this.masterProjectId;return await $(()=>X("/projects",{method:"POST",body:JSON.stringify({name:e,parent_id:a})},s))}async updateProject(e,t){const n=this.ensureInitialized();return await $(()=>X(`/projects/${e}`,{method:"POST",body:JSON.stringify({name:t})},n))}async deleteProject(e){const t=this.ensureInitialized();return await $(()=>X(`/projects/${e}`,{method:"DELETE"},t))}async getProject(e){const t=this.ensureInitialized();return await $(()=>X(`/projects/${e}`,{},t))}async getProjectTasks(e){const t=this.ensureInitialized();return await $(()=>Fe(`/tasks?project_id=${e}`,t))}async getAllWorkspaceTasks(){const e=this.ensureInitialized(),t=await this.getWorkspaceProjects(),s=[this.masterProjectId,...t.map(o=>o.id)].map(o=>$(()=>Fe(`/tasks?project_id=${o}`,e)));return(await Promise.all(s)).flat()}async getTask(e){const t=this.ensureInitialized();return await $(()=>X(`/tasks/${e}`,{},t))}async createTask(e,t){const n=this.ensureInitialized();return await $(()=>X("/tasks",{method:"POST",body:JSON.stringify({content:t.content,description:t.description,project_id:e,due_string:t.dueString,due_date:t.dueDate,due_datetime:t.dueDatetime,priority:t.priority,labels:t.labels,section_id:t.sectionId})},n))}async updateTask(e){const t=this.ensureInitialized();return await $(()=>X(`/tasks/${e.taskId}`,{method:"POST",body:JSON.stringify({content:e.content,description:e.description,due_string:e.dueString,due_date:e.dueDate,due_datetime:e.dueDatetime,priority:e.priority,labels:e.labels})},t))}async completeTask(e){const t=this.ensureInitialized();return await $(()=>X(`/tasks/${e}/close`,{method:"POST"},t))}async reopenTask(e){const t=this.ensureInitialized();return await $(()=>X(`/tasks/${e}/reopen`,{method:"POST"},t))}async deleteTask(e){const t=this.ensureInitialized();return await $(()=>X(`/tasks/${e}`,{method:"DELETE"},t))}async getProjectSections(e){const t=this.ensureInitialized();return await $(()=>Fe(`/sections?project_id=${e}`,t))}async createSection(e,t){const n=this.ensureInitialized();return await $(()=>X("/sections",{method:"POST",body:JSON.stringify({name:t,project_id:e})},n))}async updateSection(e,t){const n=this.ensureInitialized();return await $(()=>X(`/sections/${e}`,{method:"POST",body:JSON.stringify({name:t})},n))}async deleteSection(e){const t=this.ensureInitialized();return await $(()=>X(`/sections/${e}`,{method:"DELETE"},t))}async getLabels(){const e=this.ensureInitialized();return await $(()=>Fe("/labels",e))}async createLabel(e,t){const n=this.ensureInitialized();return await $(()=>X("/labels",{method:"POST",body:JSON.stringify({name:e,color:t})},n))}async updateLabel(e,t,n){const s=this.ensureInitialized();return await $(()=>X(`/labels/${e}`,{method:"POST",body:JSON.stringify({name:t,color:n})},s))}async deleteLabel(e){const t=this.ensureInitialized();return await $(()=>X(`/labels/${e}`,{method:"DELETE"},t))}}const ne=new na;class ra{constructor(){M(this,"mappings",new Map);M(this,"initialized",!1)}async loadMappings(){var e;console.log("[Mnemonic/Todoist] loadMappings: Loading mappings from storage...");try{const t=await ve.loadSettings();console.log("[Mnemonic/Todoist] loadMappings: Settings loaded, projectMappings count:",((e=t.projectMappings)==null?void 0:e.length)||0),t.projectMappings&&(this.mappings=new Map(t.projectMappings.map(n=>[n.workspaceId,n])),console.log("[Mnemonic/Todoist] loadMappings: Loaded mappings:",Array.from(this.mappings.values()).map(n=>({workspaceId:n.workspaceId,workspaceName:n.workspaceName,todoistProjectId:n.todoistProjectId})))),this.initialized=!0,console.log("[Mnemonic/Todoist] loadMappings: Initialization complete, total mappings:",this.mappings.size)}catch(t){console.error("[Mnemonic/Todoist] Failed to load mappings:",t),this.mappings=new Map}}async saveMappings(){const e=Array.from(this.mappings.values());await ve.saveSettings({projectMappings:e})}async ensureLoaded(){this.initialized||await this.loadMappings()}async getProjectId(e){var t;return await this.ensureLoaded(),(t=this.mappings.get(e))==null?void 0:t.todoistProjectId}async getWorkspaceId(e){await this.ensureLoaded();for(const t of this.mappings.values())if(t.todoistProjectId===e)return t.workspaceId}async getMapping(e){return await this.ensureLoaded(),this.mappings.get(e)}async syncWorkspace(e,t){if(console.log("[Mnemonic/Todoist] syncWorkspace: Starting sync for workspace:",{id:e.id,name:e.name,type:e.type}),await this.ensureLoaded(),!ne.isConnected())throw console.log("[Mnemonic/Todoist] syncWorkspace: Client not connected, throwing error"),new j("Todoist client not connected","UNAUTHORIZED",!1);const n=this.mappings.get(e.id);if(console.log("[Mnemonic/Todoist] syncWorkspace: Existing mapping for workspace:",n?{todoistProjectId:n.todoistProjectId,workspaceName:n.workspaceName}:"none"),n){if(n.workspaceName!==e.name){console.log("[Mnemonic/Todoist] syncWorkspace: Name changed, updating project");try{await ne.updateProject(n.todoistProjectId,e.name),n.workspaceName=e.name,n.todoistProjectName=e.name,n.lastSynced=new Date().toISOString(),await this.saveMappings()}catch(o){if((o instanceof j?o:$t(o)).code==="NOT_FOUND")return console.log("[Mnemonic/Todoist] syncWorkspace: Project not found in Todoist, removing mapping and re-syncing"),this.mappings.delete(e.id),this.syncWorkspace(e,t);throw o}}return console.log("[Mnemonic/Todoist] syncWorkspace: Returning existing mapping"),n}console.log("[Mnemonic/Todoist] syncWorkspace: No existing mapping, checking for existing Todoist projects by name...");let s;try{const o=await ne.getWorkspaceProjects();console.log("[Mnemonic/Todoist] syncWorkspace: Found",o.length,"existing workspace projects"),console.log("[Mnemonic/Todoist] syncWorkspace: Looking for project matching workspace name:",e.name.toLowerCase());const i=o.find(l=>l.name.toLowerCase()===e.name.toLowerCase());i?(console.log(`[Mnemonic/Todoist] syncWorkspace: Found existing project "${i.name}" (id: ${i.id}) for workspace "${e.name}"`),s=i):(console.log("[Mnemonic/Todoist] syncWorkspace: No matching project found, creating new project..."),s=await ne.createWorkspaceProject(e.name,e.type,t),console.log("[Mnemonic/Todoist] syncWorkspace: Created new project:",{id:s.id,name:s.name}))}catch(o){console.error("[Mnemonic/Todoist] syncWorkspace: Failed to check for existing projects:",o),console.log("[Mnemonic/Todoist] syncWorkspace: Fallback - creating new project..."),s=await ne.createWorkspaceProject(e.name,e.type,t)}const a={workspaceId:e.id,workspaceName:e.name,workspaceType:e.type,todoistProjectId:s.id,todoistProjectName:s.name,parentProjectId:t,lastSynced:new Date().toISOString()};return this.mappings.set(e.id,a),await this.saveMappings(),a}async syncAllWorkspaces(e){await this.ensureLoaded();const t={success:!0,tasksUpdated:0,tasksFailed:0,projectsCreated:0,errors:[]};if(!ne.isConnected())return t.success=!1,t.errors.push("Todoist client not connected"),t;const n=e.filter(i=>i.type==="parent"),s=e.filter(i=>i.type==="standalone"),a=e.filter(i=>i.type==="child"),o=new Set(this.mappings.keys());for(const i of n)try{const l=await this.syncWorkspace(i);o.has(i.id)||t.projectsCreated++;const d=a.filter(u=>u.parentId===i.id);for(const u of d)try{await this.syncWorkspace(u,l.todoistProjectId),o.has(u.id)||t.projectsCreated++}catch(m){const h=m instanceof Error?m.message:"Unknown error";t.errors.push(`Failed to sync child workspace ${u.name}: ${h}`),t.success=!1}}catch(l){const d=l instanceof Error?l.message:"Unknown error";t.errors.push(`Failed to sync parent workspace ${i.name}: ${d}`),t.success=!1}for(const i of s)try{await this.syncWorkspace(i),o.has(i.id)||t.projectsCreated++}catch(l){const d=l instanceof Error?l.message:"Unknown error";t.errors.push(`Failed to sync standalone workspace ${i.name}: ${d}`),t.success=!1}return t}async removeMapping(e,t=!1){await this.ensureLoaded();const n=this.mappings.get(e);if(n){if(t&&ne.isConnected())try{await ne.deleteProject(n.todoistProjectId)}catch(s){console.error("[Mnemonic/Todoist] Failed to delete Todoist project:",s)}this.mappings.delete(e),await this.saveMappings()}}async getAllMappings(){return await this.ensureLoaded(),Array.from(this.mappings.values())}async reconcile(){if(await this.ensureLoaded(),!ne.isConnected())return 0;try{const e=await ne.getWorkspaceProjects(),t=new Set(e.map(a=>a.id)),n=ne.getMasterProjectId();n&&t.add(n);let s=0;for(const[a,o]of this.mappings)t.has(o.todoistProjectId)||(this.mappings.delete(a),s++);return s>0&&await this.saveMappings(),s}catch(e){return console.error("[Mnemonic/Todoist] Failed to reconcile mappings:",e),0}}async findPotentialMatches(e){if(console.log("[Mnemonic/Todoist] findPotentialMatches: Starting with",e.length,"workspaces"),await this.ensureLoaded(),!ne.isConnected())return console.log("[Mnemonic/Todoist] findPotentialMatches: Client not connected, returning empty"),new Map;const t=new Map;try{const n=await ne.getWorkspaceProjects();console.log("[Mnemonic/Todoist] findPotentialMatches: Retrieved",n.length,"Todoist projects"),console.log("[Mnemonic/Todoist] findPotentialMatches: Project names:",n.map(a=>a.name));const s=e.filter(a=>!this.mappings.has(a.id));console.log("[Mnemonic/Todoist] findPotentialMatches: Unmapped workspaces:",s.length),console.log("[Mnemonic/Todoist] findPotentialMatches: Unmapped workspace names:",s.map(a=>a.name));for(const a of s){const o=n.find(i=>i.name.toLowerCase()===a.name.toLowerCase());o?(console.log(`[Mnemonic/Todoist] findPotentialMatches: MATCH - workspace "${a.name}" -> project "${o.name}" (${o.id})`),t.set(a.id,o)):console.log(`[Mnemonic/Todoist] findPotentialMatches: NO MATCH for workspace "${a.name}"`)}}catch(n){console.error("[Mnemonic/Todoist] findPotentialMatches: Failed to find potential matches:",n)}return console.log("[Mnemonic/Todoist] findPotentialMatches: Returning",t.size,"matches"),t}async linkToExistingProject(e,t){if(await this.ensureLoaded(),!ne.isConnected())throw new j("Todoist client not connected","UNAUTHORIZED",!1);const n=await ne.getProject(t),s={workspaceId:e.id,workspaceName:e.name,workspaceType:e.type,todoistProjectId:n.id,todoistProjectName:n.name,parentProjectId:n.parentId||void 0,lastSynced:new Date().toISOString()};return this.mappings.set(e.id,s),await this.saveMappings(),s}async clearAllMappings(){this.mappings.clear(),await this.saveMappings(),this.initialized=!1}async getAllMappingsMap(){return await this.ensureLoaded(),new Map(this.mappings)}async restoreMappingsFromWorkspaces(e){console.log("[Mnemonic/Todoist] restoreMappingsFromWorkspaces: Starting with",e.length,"workspaces"),await this.ensureLoaded();let t=0;for(const n of e){if(!n.todoistProjectId){console.log(`[Mnemonic/Todoist] restoreMappingsFromWorkspaces: Skipping "${n.name}" - no todoistProjectId`);continue}if(this.mappings.has(n.id)){console.log(`[Mnemonic/Todoist] restoreMappingsFromWorkspaces: Skipping "${n.name}" - already has mapping`);continue}console.log(`[Mnemonic/Todoist] restoreMappingsFromWorkspaces: Restoring mapping for "${n.name}" -> ${n.todoistProjectId}`);const s={workspaceId:n.id,workspaceName:n.name,workspaceType:n.type,todoistProjectId:n.todoistProjectId,todoistProjectName:n.name,lastSynced:new Date().toISOString()};this.mappings.set(n.id,s),t++}return t>0?(await this.saveMappings(),console.log(`[Mnemonic/Todoist] restoreMappingsFromWorkspaces: Restored ${t} mappings from synced workspaces`)):console.log("[Mnemonic/Todoist] restoreMappingsFromWorkspaces: No mappings to restore"),t}async detectAndLinkExistingProjects(e){if(console.log("[Mnemonic/Todoist] detectAndLinkExistingProjects: Starting with",e.length,"workspaces"),await this.ensureLoaded(),!ne.isConnected())return console.log("[Mnemonic/Todoist] detectAndLinkExistingProjects: Client not connected, returning empty"),new Map;const t=new Map;try{console.log("[Mnemonic/Todoist] detectAndLinkExistingProjects: Calling findPotentialMatches...");const n=await this.findPotentialMatches(e);console.log("[Mnemonic/Todoist] detectAndLinkExistingProjects: findPotentialMatches returned",n.size,"matches");for(const[s,a]of n){const o=e.find(l=>l.id===s);if(!o){console.log("[Mnemonic/Todoist] detectAndLinkExistingProjects: Could not find workspace for id:",s);continue}console.log(`[Mnemonic/Todoist] detectAndLinkExistingProjects: Creating mapping for "${o.name}" -> "${a.name}" (${a.id})`);const i={workspaceId:o.id,workspaceName:o.name,workspaceType:o.type,todoistProjectId:a.id,todoistProjectName:a.name,parentProjectId:a.parentId||void 0,lastSynced:new Date().toISOString()};this.mappings.set(s,i),t.set(s,i)}t.size>0?(await this.saveMappings(),console.log(`[Mnemonic/Todoist] detectAndLinkExistingProjects: Auto-linked ${t.size} workspaces to existing projects`)):console.log("[Mnemonic/Todoist] detectAndLinkExistingProjects: No new mappings created")}catch(n){console.error("[Mnemonic/Todoist] detectAndLinkExistingProjects: Failed to detect and link existing projects:",n)}return t}}const jn=new ra;function jt(){return typeof g<"u"&&"getBrowserInfo"in g.runtime?"firefox":typeof chrome<"u"&&chrome.runtime&&!("getBrowserInfo"in chrome.runtime)?"chrome":"unknown"}const sa=6e4;function aa(r){var t;const e={};for(const n of r){const s=n.tabs||[];e[n.id]={tabUrls:s.map(a=>de(a.url)),metadata:{lastModified:((t=n.metadata)==null?void 0:t.lastModified)||new Date().toISOString(),archivedAt:n.archivedAt||null}}}return e}const oa=5e3;class ia{constructor(){M(this,"restBridge");M(this,"filesystemBridge");M(this,"backendType","none");M(this,"pollInterval",null);M(this,"writeDebounceTimer",null);M(this,"pendingWrite",null);M(this,"listeners",new Set);M(this,"initialized",!1);this.restBridge=ae(),this.filesystemBridge=Gs()}async initialize(e){return this.backendType=e,e==="none"?(this.initialized=!0,!0):e==="native"?await this.restBridge.connect()?(this.startPolling(),this.initialized=!0,this.emitEvent("status_changed",{status:"connected"}),!0):(this.emitEvent("sync_error",{error:"Failed to connect to REST bridge"}),!1):e==="filesystem"?await this.filesystemBridge.connect()?(this.startPolling(),this.initialized=!0,this.emitEvent("status_changed",{status:"connected"}),!0):(this.initialized=!0,this.emitEvent("status_changed",{status:"disconnected"}),!0):!1}shutdown(){this.stopPolling(),this.writeDebounceTimer&&(clearTimeout(this.writeDebounceTimer),this.writeDebounceTimer=null),this.backendType==="native"?this.restBridge.disconnect():this.backendType,this.initialized=!1}getState(){return this.backendType==="native"?this.restBridge.getState():this.backendType==="filesystem"?this.filesystemBridge.getState():{...Nt}}async selectDirectory(){if(this.backendType!=="filesystem")return!1;const e=await this.filesystemBridge.selectDirectory();return e&&(this.startPolling(),this.emitEvent("status_changed",{status:"connected"})),e}getActiveBridge(){return this.backendType==="native"?this.restBridge:this.backendType==="filesystem"?this.filesystemBridge:null}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}emitEvent(e,t){const n={type:e,timestamp:new Date().toISOString(),data:t};for(const s of this.listeners)try{s(n)}catch(a){console.error("[Mnemonic] Sync event listener error:",a)}}syncToExternal(e){this.backendType!=="none"&&(this.pendingWrite=e,this.writeDebounceTimer&&clearTimeout(this.writeDebounceTimer),this.writeDebounceTimer=setTimeout(()=>{this.performWrite()},oa))}async performWrite(){if(!this.pendingWrite)return;const e=this.pendingWrite;this.pendingWrite=null,this.writeDebounceTimer=null;const t=this.getActiveBridge();if(t)try{this.emitEvent("sync_started");let n;if(this.backendType==="native"?n=await this.writeWithBrowserStructure(e):n=await t.write(e),n.success)console.log("[Mnemonic] Synced to external storage"),this.emitEvent("sync_completed",{mtime:n.mtime});else throw new Error("Write failed")}catch(n){const s=n instanceof Error?n.message:"Sync failed";console.error("[Mnemonic] Sync to external failed:",s),this.emitEvent("sync_error",{error:s})}}async writeWithBrowserStructure(e){var h,k,E;const t=jt(),n=await this.restBridge.read();let s;n.success&&n.data&&typeof n.data=="object"?(s=n.data,s.browsers||(s.browsers={})):s={...Nn,browsers:{}};const a=((h=e.workspaces)==null?void 0:h.length)??0,o=((E=(k=s.browsers[t])==null?void 0:k.workspaces)==null?void 0:E.length)??0;if(a===0&&o>0)return console.log("[Mnemonic] Skipping sync: local is empty but external has",o,"workspaces"),{success:!0};let i;try{i=await jn.getAllMappingsMap()}catch{i=new Map}const l=e.workspaces.map(y=>{const{windowId:_,mainWindowId:S,fingerprint:O,...D}=y;D.tabs&&Array.isArray(D.tabs)&&(D.tabs=D.tabs.map(oe=>{const{favIconUrl:T,...A}=oe;return A}));const U=i.get(y.id);return U!=null&&U.todoistProjectId&&(D.todoistProjectId=U.todoistProjectId),D});let d;try{d=(await g.storage.local.get("deviceId")).deviceId,d||(d=crypto.randomUUID(),await g.storage.local.set({deviceId:d}))}catch{d="unknown-device"}const u={pauseMediaSites:e.settings.pauseMediaSites,autoSave:e.settings.autoSave,autoSaveInterval:e.settings.autoSaveInterval,confirmContextSwitch:e.settings.confirmContextSwitch,restoreWindowPositions:e.settings.restoreWindowPositions,useSmartPositioning:e.settings.useSmartPositioning,lazyLoadTabs:e.settings.lazyLoadTabs};s.browsers[t]={deviceId:d,lastUpdated:new Date().toISOString(),workspaces:l,settings:u},s.lastModified=new Date().toISOString();const m=await this.restBridge.write(s);return{success:m.success,mtime:m.mtime}}async forceSyncToExternal(e){if(this.backendType==="none")return!0;const t=this.getActiveBridge();if(!t)return!1;this.writeDebounceTimer&&(clearTimeout(this.writeDebounceTimer),this.writeDebounceTimer=null),this.pendingWrite=null;try{this.emitEvent("sync_started");let n;if(this.backendType==="native"?n=await this.writeWithBrowserStructure(e):n=await t.write(e),n.success)return this.emitEvent("sync_completed",{mtime:n.mtime}),!0;throw new Error("Write failed")}catch(n){const s=n instanceof Error?n.message:"Sync failed";return this.emitEvent("sync_error",{error:s}),!1}}async syncFromExternal(){var t;if(this.backendType==="none")return null;const e=this.getActiveBridge();if(!e)return null;try{const n=await e.read();if(!n.success||!n.data)return null;if(this.backendType==="native"){const s=n.data,a=jt();if(!((t=s.browsers)!=null&&t[a]))return null;const o=s.browsers[a],i=_e(),l={...i.settings,...o.settings||{}};try{await jn.restoreMappingsFromWorkspaces(o.workspaces)}catch(d){console.warn("[Mnemonic] Failed to restore Todoist mappings:",d)}return{...i,workspaces:o.workspaces,settings:l,metadata:{...i.metadata,lastModified:o.lastUpdated}}}else{const s=n.data,a=_e();return{...a,...s,context:{...a.context,...s.context},contextHistory:{...a.contextHistory,...s.contextHistory},settings:{...a.settings,...s.settings},metadata:{...a.metadata,...s.metadata}}}}catch(n){return console.error("[Mnemonic] Sync from external failed:",n),null}}async checkAndMergeExternal(){var t,n;if(console.log("[Mnemonic:Sync] checkAndMergeExternal() called, backendType:",this.backendType),this.backendType==="none")return!1;const e=this.getActiveBridge();if(!e)return console.log("[Mnemonic:Sync] No active bridge available"),!1;try{const s=this.backendType==="native"&&this.restBridge.isFreshStartup();s&&console.log("[Mnemonic:Sync] Fresh startup detected - using per-workspace merge for accurate conflict resolution"),console.log("[Mnemonic:Sync] Checking for external changes...");const a=await e.checkForChanges();if(console.log("[Mnemonic:Sync] checkForChanges result:",a),!a)return console.log("[Mnemonic:Sync] No external changes detected, skipping merge"),!1;console.log("[Mnemonic:Sync] External changes detected, fetching external data...");const o=await this.syncFromExternal();if(!o)return console.log("[Mnemonic:Sync] Failed to fetch external data"),!1;console.log("[Mnemonic:Sync] External data fetched, workspaces:",(t=o.workspaces)==null?void 0:t.length);const i=await I.read();if(console.log("[Mnemonic:Sync] Local data loaded, workspaces:",(n=i==null?void 0:i.workspaces)==null?void 0:n.length),await this.mergeExternalChanges(i,o,s),this.backendType==="native"){const l=await this.restBridge.getBrowserTimestamps();this.restBridge.updateKnownBrowserTimestamps(l),console.log("[Mnemonic:Sync] Updated known browser timestamps:",l)}return!0}catch(s){return console.error("[Mnemonic] Check/merge external failed:",s),!1}}mergeTabs(e,t){if(t.length===0&&e.length>0)return console.log("[Mnemonic] Protecting tabs: external empty, keeping local"),e;const n=e.filter(o=>o.pinned),s=new Set(n.map(o=>o.url));n.length>0&&console.log(`[Mnemonic] Protecting ${n.length} local pinned tabs`);const a=[...n];for(const o of t)s.has(o.url)||a.push(o);return[...a.filter(o=>o.pinned),...a.filter(o=>!o.pinned)]}async performPerWorkspaceMerge(e,t){var u,m;console.log("[Mnemonic:Sync:Merge] === performPerWorkspaceMerge called (three-way) ==="),console.log("[Mnemonic:Sync:Merge] Local workspaces:",e.workspaces.length),console.log("[Mnemonic:Sync:Merge] External workspaces:",t.workspaces.length);const n=await Hs();console.log("[Mnemonic:Sync:Merge] Ancestor state:",n!==null?`found (${Object.keys(n.workspaces).length} workspaces)`:"none (will use two-way fallback)");const a=new Map(e.workspaces.map(h=>[h.id,h])),o=[],i=new Map;for(const h of t.workspaces){const k=a.get(h.id);if(k){const E=k.tabs||[],y=h.tabs||[];if(console.log(`[Mnemonic:Sync:Merge] Workspace "${h.name}" (${h.id}):`),console.log(`[Mnemonic:Sync:Merge]   Local tabs: ${E.length}, External tabs: ${y.length}`),k.syncEnabled===!1)console.log("[Mnemonic:Sync:Merge]   -> Sync disabled, keeping local"),o.push(k);else{const _=qs(n,h.id);if(_){console.log(`[Mnemonic:Sync:Merge]   -> Using three-way merge (ancestor has ${_.tabUrls.length} tabs)`);const S=Ln(E),O=Ln(y),D=_.tabUrls,U=Ys(S,O,D);console.log(`[Mnemonic:Sync:Merge]   Local added: ${U.localAdded.length}, External added: ${U.externalAdded.length}`),console.log(`[Mnemonic:Sync:Merge]   Merged result: ${U.mergedUrls.length} tabs`),U.conflicts.length>0&&console.log(`[Mnemonic:Sync:Merge]   Conflicts (both added): ${U.conflicts.length}`);const oe=Js(U.mergedUrls,E,y);if(U.externalAdded.length>0){const A=y.filter(P=>U.externalAdded.some(N=>de(P.url)===de(N)));A.length>0&&(i.set(h.id,A),console.log(`[Mnemonic:Sync:Merge]   Workspace "${h.name}" gained ${A.length} tabs from external`))}const T=[...oe.filter(A=>A.pinned),...oe.filter(A=>!A.pinned)];o.push({...h,tabs:T,syncEnabled:k.syncEnabled??!0,archivedAt:k.archivedAt??h.archivedAt,metadata:{...h.metadata,lastModified:new Date().toISOString()}})}else{const S=new Date(((u=k.metadata)==null?void 0:u.lastModified)||0).getTime(),O=new Date(((m=h.metadata)==null?void 0:m.lastModified)||0).getTime();if(console.log("[Mnemonic:Sync:Merge]   -> No ancestor, using two-way merge"),console.log(`[Mnemonic:Sync:Merge]   Local time: ${S}, External time: ${O}`),O>S){console.log("[Mnemonic:Sync:Merge]   -> External newer, merging tabs");const D=this.mergeTabs(E,y),U=new Set(E.map(T=>T.url)),oe=y.filter(T=>!U.has(T.url));oe.length>0&&i.set(h.id,oe),o.push({...h,tabs:D,syncEnabled:k.syncEnabled??!0,archivedAt:k.archivedAt??h.archivedAt})}else console.log("[Mnemonic:Sync:Merge]   -> Local newer or equal, keeping local"),o.push(k)}}a.delete(h.id)}else console.log(`[Mnemonic:Sync:Merge] Workspace "${h.name}" is new from external`),o.push(h)}for(const[,h]of a)o.push(h);const l={...e,workspaces:o,metadata:{...e.metadata,lastModified:new Date().toISOString()}};await I.write(l),this.emitEvent("external_change",{action:"per_workspace_merged"}),this.notifyUI(),this.syncToExternal(l);const d={workspaces:aa(o),timestamp:new Date().toISOString(),sourceBrowser:jt()};await Vs(d),console.log("[Mnemonic:Sync:Merge] Saved new ancestor state"),await this.openExternallySyncedTabs(i)}async openExternallySyncedTabs(e){if(console.log("[Mnemonic:Sync:OpenTabs] === openExternallySyncedTabs called ==="),console.log("[Mnemonic:Sync:OpenTabs] Workspaces with new tabs:",e.size),e.size===0){console.log("[Mnemonic:Sync:OpenTabs] No workspaces with new tabs, returning");return}const t=R(),n=t.getMappings();console.log("[Mnemonic:Sync:OpenTabs] Current window tracker mappings:",n.length);for(const s of n)console.log(`[Mnemonic:Sync:OpenTabs]   - Window ${s.windowId} -> Workspace ${s.workspaceId}`);for(const[s,a]of e){console.log(`[Mnemonic:Sync:OpenTabs] Processing workspace ${s} with ${a.length} new tabs`);const o=t.getWorkspaceWindow(s);if(o===void 0){console.log(`[Mnemonic:Sync:OpenTabs] No active window for workspace ${s}, skipping tab opening`);continue}console.log(`[Mnemonic:Sync:OpenTabs] Opening ${a.length} externally-synced tabs in window ${o}`);try{const i=await g.tabs.query({windowId:o}),l=new Set(i.map(d=>d.url));for(const d of a){if(l.has(d.url)){console.log(`[Mnemonic:Sync] Tab already exists, skipping: ${d.url}`);continue}try{await g.tabs.create({windowId:o,url:d.url,pinned:d.pinned||!1,active:!1}),console.log(`[Mnemonic:Sync] Opened synced tab: ${d.url}`)}catch(u){console.error(`[Mnemonic:Sync] Failed to open tab ${d.url}:`,u)}}}catch(i){console.error(`[Mnemonic:Sync] Failed to query/create tabs for window ${o}:`,i)}}}async mergeExternalChanges(e,t,n=!1){var i,l,d,u,m;if(console.log("[Mnemonic:Sync] mergeExternalChanges() called, forcePerWorkspaceMerge:",n),console.log("[Mnemonic:Sync] Local config exists:",!!e),console.log("[Mnemonic:Sync] External workspaces count:",(i=t.workspaces)==null?void 0:i.length),!e){console.log("[Mnemonic:Sync] No local config, replacing with external"),await I.write(t),this.emitEvent("external_change",{action:"replaced"}),this.notifyUI();return}const s=new Date(((l=e.metadata)==null?void 0:l.lastModified)||0).getTime(),a=new Date(((d=t.metadata)==null?void 0:d.lastModified)||0).getTime();if(console.log("[Mnemonic:Sync] Merge comparison:",{localMtime:s,externalMtime:a,localTimestamp:(u=e.metadata)==null?void 0:u.lastModified,externalTimestamp:(m=t.metadata)==null?void 0:m.lastModified,localNewer:s>a,externalNewer:a>s}),n){console.log("[Mnemonic:Sync] Fresh startup - forcing per-workspace merge for reliable conflict resolution"),await this.performPerWorkspaceMerge(e,t);return}const o=Math.abs(a-s);if(console.log("[Mnemonic:Sync] Time difference:",o,"ms, threshold: 5000ms"),o<5e3){console.log("[Mnemonic:Sync] Near-simultaneous edits, using per-workspace merge"),await this.performPerWorkspaceMerge(e,t);return}if(a>s){console.log("[Mnemonic:Sync] External is newer, applying changes");const h=new Map(e.workspaces.map(y=>[y.id,y]));new Map(t.workspaces.map(y=>[y.id,y]));const k=[];for(const y of t.workspaces){const _=h.get(y.id);if(_){if(_.syncEnabled===!1)console.log(`[Mnemonic] Keeping local workspace (sync disabled): ${_.name}`),k.push(_);else{const S=_.tabs||[],O=y.tabs||[],D=this.mergeTabs(S,O);k.push({...y,tabs:D,syncEnabled:_.syncEnabled??!0,archivedAt:_.archivedAt??y.archivedAt})}h.delete(y.id)}else k.push(y)}for(const[,y]of h)if(y.syncEnabled===!1)console.log(`[Mnemonic] Keeping local-only workspace (sync disabled): ${y.name}`),k.push(y);else{const S=(y.tabs||[]).filter(O=>O.pinned).length;S>0&&(console.warn(`[Mnemonic] Workspace "${y.name}" deleted externally but has ${S} pinned tabs - keeping`),k.push(y))}const E={...t,workspaces:k};await I.write(E),this.emitEvent("external_change",{action:"merged"}),this.notifyUI()}else console.log("[Mnemonic] Local is newer, keeping local"),this.syncToExternal(e)}notifyUI(){g.runtime.sendMessage({type:"WORKSPACES_UPDATED_EXTERNALLY"}).catch(()=>{})}startPolling(){this.pollInterval||(this.pollInterval=setInterval(()=>{this.checkAndMergeExternal()},sa))}stopPolling(){this.pollInterval&&(clearInterval(this.pollInterval),this.pollInterval=null)}async testConnection(){if(this.backendType==="none")return{success:!0};if(this.backendType==="native")try{const e=await this.restBridge.health();if(e.status==="ok"){const t=await this.restBridge.getInfo();return{success:!0,info:{version:e.version.api_version,configDir:e.config_dir,fileExists:t.exists,filePath:t.path}}}else return{success:!1,error:"Health check failed"}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Connection failed"}}if(this.backendType==="filesystem")try{const e=await this.filesystemBridge.ping();if(e.success){const t=await this.filesystemBridge.getInfo();return{success:!0,info:{directoryName:e.directoryName,fileExists:t.exists,filePath:t.path,fileSize:t.size}}}else return{success:!1,error:e.error}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Connection failed"}}return{success:!1,error:"Unknown backend type"}}async restoreFromBackup(){if(this.backendType==="none")return!1;const e=this.getActiveBridge();if(!e)return!1;try{if((await e.restore()).success){const n=await this.syncFromExternal();if(n)return await I.write(n),this.notifyUI(),!0}return!1}catch(t){return console.error("[Mnemonic] Restore from backup failed:",t),!1}}async forcePullFromExternal(){var t;if(this.backendType==="none"||!this.getActiveBridge())return!1;try{console.log("[Mnemonic] Force pulling from external...");const n=await this.syncFromExternal();return n?(console.log("[Mnemonic] External data found, workspaces:",((t=n.workspaces)==null?void 0:t.length)||0),n.workspaces&&n.workspaces.length>0?(await I.write(n),this.emitEvent("external_change",{action:"restored"}),this.notifyUI(),console.log("[Mnemonic] Successfully restored workspaces from external"),!0):!1):(console.log("[Mnemonic] No external data found"),!1)}catch(n){return console.error("[Mnemonic] Force pull from external failed:",n),!1}}getBackendType(){return this.backendType}isFilesystemSupported(){return"showDirectoryPicker"in window}}let Kt=null;function ce(){return Kt||(Kt=new ia),Kt}const lt=1e4;class Kn{constructor(e){M(this,"bridge");this.bridge=e||ae()}async fetchEncrypted(){var s;const e=this.bridge.getBaseUrl(),t=new AbortController,n=setTimeout(()=>t.abort(),lt);try{const a=await fetch(`${e}/credentials`,{method:"GET",signal:t.signal,headers:{"Content-Type":"application/json"}});if(clearTimeout(n),!a.ok){const i=await a.json().catch(()=>({}));throw new Error(((s=i.detail)==null?void 0:s.error)||i.error||`HTTP ${a.status}`)}const o=await a.json();return!o.success||!o.exists?null:o.data}catch(a){throw clearTimeout(n),a instanceof Error&&a.name==="AbortError"?new Error("Request timed out"):a}}async pushEncrypted(e){var a;const t=this.bridge.getBaseUrl(),n=new AbortController,s=setTimeout(()=>n.abort(),lt);try{const o=await fetch(`${t}/credentials`,{method:"POST",signal:n.signal,headers:{"Content-Type":"application/json"},body:JSON.stringify({data:e})});if(clearTimeout(s),!o.ok){const l=await o.json().catch(()=>({}));throw new Error(((a=l.detail)==null?void 0:a.error)||l.error||`HTTP ${o.status}`)}if(!(await o.json()).success)throw new Error("Failed to write credentials");console.log("[Mnemonic] Credentials synced to daemon")}catch(o){throw clearTimeout(s),o instanceof Error&&o.name==="AbortError"?new Error("Request timed out"):o}}async hasRemoteCredentials(){const e=this.bridge.getBaseUrl(),t=new AbortController,n=setTimeout(()=>t.abort(),lt);try{const s=await fetch(`${e}/credentials/info`,{method:"GET",signal:t.signal,headers:{"Content-Type":"application/json"}});if(clearTimeout(n),!s.ok)return!1;const a=await s.json();return a.success&&a.exists}catch{return clearTimeout(n),!1}}async getCredentialsInfo(){const e=this.bridge.getBaseUrl(),t=new AbortController,n=setTimeout(()=>t.abort(),lt);try{const s=await fetch(`${e}/credentials/info`,{method:"GET",signal:t.signal,headers:{"Content-Type":"application/json"}});if(clearTimeout(n),!s.ok)return{exists:!1};const a=await s.json();return{exists:a.exists||!1,mtime:a.mtime,size:a.size}}catch{return clearTimeout(n),{exists:!1}}}}let zt=null;function ca(){return zt||(zt=new Kn),zt}const Se=Object.freeze(Object.defineProperty({__proto__:null,CredentialsSync:Kn,getCredentialsSync:ca},Symbol.toStringTag,{value:"Module"})),Ye="Mnemonic";async function zn(){const e=(await g.bookmarks.search({title:Ye})).find(a=>!a.url&&a.title===Ye);if(e)return e.id;const n=typeof g<"u"&&g.runtime.getURL("").startsWith("moz-extension://")?"unfiled_____":"2";return(await g.bookmarks.create({parentId:n,title:Ye})).id}async function Gn(r,e){const n=(await g.bookmarks.getChildren(r)).find(s=>!s.url&&s.title===e);return(n==null?void 0:n.id)||null}async function Hn(r){const e=await g.bookmarks.getChildren(r);for(const t of e)await g.bookmarks.removeTree(t.id)}async function la(r){try{const e=await zn();let t=await Gn(e,r.name);t?await Hn(t):t=(await g.bookmarks.create({parentId:e,title:r.name})).id;let n=0;for(const s of r.tabs)s.url&&!s.url.startsWith("chrome://")&&!s.url.startsWith("about:")&&(await g.bookmarks.create({parentId:t,title:s.title||s.url,url:s.url}),n++);return{success:!0,folderId:t,bookmarkCount:n}}catch(e){return{success:!1,bookmarkCount:0,error:e instanceof Error?e.message:"Failed to export workspace"}}}async function da(r,e){try{const t=await zn();let n=await Gn(t,r.name);n?await Hn(n):n=(await g.bookmarks.create({parentId:t,title:r.name})).id;let s=0;for(const a of e){const o=await g.bookmarks.create({parentId:n,title:a.name});for(const i of a.tabs)i.url&&!i.url.startsWith("chrome://")&&!i.url.startsWith("about:")&&(await g.bookmarks.create({parentId:o.id,title:i.title||i.url,url:i.url}),s++)}return{success:!0,folderId:n,bookmarkCount:s}}catch(t){return{success:!1,bookmarkCount:0,error:t instanceof Error?t.message:"Failed to export context"}}}async function ua(){try{const e=(await g.bookmarks.search({title:Ye})).find(s=>!s.url&&s.title===Ye);if(!e)return[];const t=await g.bookmarks.getChildren(e.id),n=[];for(const s of t)if(!s.url){const a=await Vn(s.id,s.title);n.push(a)}return n}catch(r){return console.error("Failed to get Mnemonic bookmark folders:",r),[]}}async function Vn(r,e){const t=await g.bookmarks.getChildren(r),n={id:r,title:e,children:[],bookmarks:[]};for(const s of t)if(s.url)n.bookmarks.push({title:s.title||s.url,url:s.url});else{const a=await Vn(s.id,s.title);n.children.push(a)}return n}function qn(r){const e=r.children.length>0;return r.bookmarks.length>0,{type:e&&r.children.some(n=>n.bookmarks.length>0)?"nested":"flat",bookmarkCount:r.bookmarks.length+r.children.reduce((n,s)=>n+s.bookmarks.length,0),subfolderCount:r.children.length,subfolders:r.children.map(n=>({name:n.title,bookmarkCount:n.bookmarks.length}))}}function Gt(r){return r.filter(e=>e.url&&!e.url.startsWith("javascript:")).map(e=>({url:e.url,title:e.title,pinned:!1}))}function ga(r){const e=[...r.bookmarks,...r.children.flatMap(t=>t.bookmarks)];return Gt(e)}function pa(r){return r.children.length>0?{parentName:r.name,children:r.children.map(e=>({name:e.title,tabs:Gt(e.bookmarks)}))}:{parentName:r.title,children:[{name:r.title,tabs:Gt(r.bookmarks)}]}}function Yn(r){return qn(r).type==="nested"?"context":"standalone"}let K={...dn},x=Mn();const Ht="searchIndexCache",Vt="claudeSettings";let dt=null;const Je=new Map,fa=2e3;let ut=null,Ue=!1;function F(){g.runtime.sendMessage({type:"WORKSPACE_STATUS_CHANGED"}).catch(()=>{})}function ma(){g.runtime.sendMessage({type:"AUDIBLE_STATE_CHANGED"}).catch(()=>{})}function gt(){return typeof g<"u"&&"getBrowserInfo"in g.runtime?"firefox":typeof chrome<"u"&&chrome.runtime&&!("getBrowserInfo"in chrome.runtime)?"chrome":"unknown"}let Jn=null;function ha(){if(Jn)return;const r=gt(),e=ae();Jn=setInterval(async()=>{try{if(!e.isConnected())return;const t=await e.pollTransfers(r);if(t.transfers&&t.transfers.length>0)for(const n of t.transfers)await wa(n)}catch{}},5e3),console.log("[Mnemonic] Transfer polling started for",r)}async function wa(r){const{target_workspace_id:e,target_workspace_name:t,tab:n}=r;try{const s=f.getById(e);if(!s){console.warn("[Mnemonic:Transfer] Workspace not found:",e,t);return}if(!q(s)){console.warn("[Mnemonic:Transfer] Target is not a tab workspace:",t);return}const a=s.tabs||[];if(a.some(d=>d.url===n.url)){console.log("[Mnemonic:Transfer] Tab already in workspace, skipping:",n.url);return}const o={url:n.url,title:n.title,pinned:n.pinned||!1};await f.updateTabs(e,[...a,o]),console.log("[Mnemonic:Transfer] Added tab to",t,":",n.url);const l=R().getWorkspaceWindow(e);if(l)try{await g.tabs.create({windowId:l,url:n.url,pinned:n.pinned||!1,active:!1}),await g.windows.update(l,{focused:!0}),console.log("[Mnemonic:Transfer] Opened tab in window",l)}catch(d){console.warn("[Mnemonic:Transfer] Could not open tab in window:",d)}F()}catch(s){console.error("[Mnemonic:Transfer] Error processing transfer:",s)}}async function Zn(){try{await g.storage.local.set({[Vt]:K}),console.log("[Mnemonic] Claude settings saved")}catch(r){console.error("[Mnemonic] Failed to save Claude settings:",r)}}function Be(r){g.action.setBadgeText({text:r?"!":""}),g.action.setBadgeBackgroundColor({color:"#EF4444"})}async function ya(){try{const e=(await g.storage.local.get(Vt))[Vt];e&&(K={...dn,...e},K.apiKey&&(ye().setApiKey(K.apiKey),console.log("[Mnemonic] Claude API key restored from storage")))}catch(r){console.error("[Mnemonic] Failed to load Claude settings:",r)}}async function qt(r,e=10){const t={tabs:[],enrichedCount:0,errors:[]},n=[];for(let i=0;i<r.length;i++){const l=r[i];Us(l.title,l.url)&&n.push({index:i,...l})}const a=n.slice(0,e).map(async i=>{var l;try{if(!i.url.startsWith("http://")&&!i.url.startsWith("https://"))return{index:i.index,enriched:null};const d=new AbortController,u=setTimeout(()=>d.abort(),5e3),m=await fetch(i.url,{method:"GET",signal:d.signal,headers:{Accept:"text/html","User-Agent":"Mozilla/5.0 (compatible; Mnemonic/1.0)"}});if(clearTimeout(u),!m.ok)return{index:i.index,enriched:null};const h=(l=m.body)==null?void 0:l.getReader();if(!h)return{index:i.index,enriched:null};let k="";const E=new TextDecoder,y=50*1024;try{for(;k.length<y;){const{done:O,value:D}=await h.read();if(O)break;k+=E.decode(D,{stream:!0})}}finally{await h.cancel().catch(()=>{})}const _=Ls(k),S=$s(i.title,_);return{index:i.index,enriched:{heading:_.heading,description:S}}}catch(d){return console.warn(`[Mnemonic] Failed to enrich tab ${i.url}:`,d),t.errors.push(`${i.url}: ${d instanceof Error?d.message:"Unknown error"}`),{index:i.index,enriched:null}}}),o=await Promise.all(a);for(let i=0;i<r.length;i++){const l=r[i],d=o.find(u=>u.index===i);d!=null&&d.enriched?(t.tabs.push({url:l.url,title:l.title,enrichedTitle:d.enriched.heading||void 0,description:d.enriched.description,wasEnriched:!0}),t.enrichedCount++):t.tabs.push({url:l.url,title:l.title,wasEnriched:!1})}return t}function z(){dt&&clearTimeout(dt),dt=setTimeout(()=>{Yt(),dt=null},5e3)}async function Le(r){const e=fe();if(!Ue){console.log("[Mnemonic] Auto-save blocked - waiting for initial sync to complete"),e.log("auto_save_skipped",{windowId:r,reason:"initial_sync_pending"});return}const n=R().getWindowMapping(r);if(!n)return;e.log("auto_save_triggered",{windowId:r,workspaceId:n.workspaceId});const s=Je.get(r);s&&clearTimeout(s);const a=setTimeout(async()=>{Je.delete(r);try{try{await g.windows.get(r)}catch{console.log(`[Mnemonic] Auto-save skipped - window ${r} no longer exists`),e.log("auto_save_skipped",{windowId:r,workspaceId:n.workspaceId,reason:"window_gone"});return}const o=await f.getById(n.workspaceId);if(!o||!q(o))return;const i=await Oe(r);await f.updateTabs(n.workspaceId,i),console.log(`[Mnemonic] Auto-saved ${i.length} tabs for workspace ${n.workspaceId}`),e.log("auto_save_completed",{windowId:r,workspaceId:n.workspaceId,tabCount:i.length}),Y(x,await f.getById(n.workspaceId)),z(),g.runtime.sendMessage({type:"TABS_UPDATED",payload:{workspaceId:n.workspaceId,windowId:r,tabCount:i.length}}).catch(()=>{})}catch(o){console.error("[Mnemonic] Auto-save failed:",o)}},fa);Je.set(r,a)}async function Yt(){try{const r=is(x);await g.storage.local.set({[Ht]:r}),console.log("[Mnemonic] Search index saved to storage")}catch(r){console.error("[Mnemonic] Failed to save search index:",r)}}async function ka(){try{const e=(await g.storage.local.get(Ht))[Ht];if(e)return x=cs(e),console.log("[Mnemonic] Search index loaded from storage:",x.stats),!0}catch(r){console.error("[Mnemonic] Failed to load search index:",r)}return!1}async function ba(r){if(!x.stats.lastUpdated)return!1;const e=new Date(x.stats.lastUpdated);if((new Date().getTime()-e.getTime())/(1e3*60*60)>24)return!1;let s=r.length;for(const i of r)"tabs"in i&&Array.isArray(i.tabs)&&(s+=i.tabs.length),"resources"in i&&Array.isArray(i.resources)&&(s+=i.resources.length);const a=x.stats.documentCount;return Math.abs(a-s)/s<.2}async function ie(){try{await g.contextMenus.removeAll();const r=await f.getAll(),e=r.filter(l=>l.type==="standalone"&&!l.archivedAt),t=r.filter(l=>l.type==="parent"&&!l.archivedAt),n=r.filter(l=>l.type==="child"&&!l.archivedAt),s=e.length>0,a=t.length>0,o=s||n.length>0,i=[{id:"add-to-workspace",title:"Add to Workspace"},{id:"add-to-workspace-open",title:"Add to Workspace and Open"}];for(const l of i){if(g.contextMenus.create({id:l.id,title:l.title,contexts:["link"]}),!o){g.contextMenus.create({id:`${l.id}-empty`,title:"No workspaces available",parentId:l.id,contexts:["link"],enabled:!1});continue}const u=l.id==="add-to-workspace-open"?"add-open":"add";if(s){g.contextMenus.create({id:`${l.id}-standalone-header`,title:"── Standalone ──",parentId:l.id,contexts:["link"],enabled:!1});for(const m of e)g.contextMenus.create({id:`${u}-${m.id}`,title:m.name,parentId:l.id,contexts:["link"]})}if(a){g.contextMenus.create({id:`${l.id}-contexts-header`,title:"── Contexts ──",parentId:l.id,contexts:["link"],enabled:!1});for(const m of t){const h=m,k=n.filter(E=>E.parentId===h.id);if(k.length===0)g.contextMenus.create({id:`${u}-parent-${h.id}`,title:`${h.name} (no workspaces)`,parentId:l.id,contexts:["link"],enabled:!1});else{g.contextMenus.create({id:`${u}-parent-${h.id}`,title:h.name,parentId:l.id,contexts:["link"]});for(const E of k)g.contextMenus.create({id:`${u}-${E.id}`,title:E.name,parentId:`${u}-parent-${h.id}`,contexts:["link"]})}}}}console.log("[Mnemonic] Context menus built successfully")}catch(r){console.error("[Mnemonic] Failed to build context menus:",r)}}async function Sa(r,e){const t=r.menuItemId;if(t.endsWith("-header")||t.endsWith("-empty")||t.includes("-parent-"))return;const n=t.startsWith("add-open-"),s=n?t.replace("add-open-",""):t.replace("add-","");if(!s||!r.linkUrl){console.warn("[Mnemonic] Context menu click missing workspace ID or link URL");return}const a=r.linkUrl;if(a.startsWith("javascript:")||a.startsWith("data:")||a.startsWith("about:")||a.startsWith("chrome:")||a.startsWith("moz-extension:")||a.startsWith("chrome-extension:")){console.log("[Mnemonic] Skipping special URL:",a);return}try{const o=await f.getById(s);if(!o){console.error("[Mnemonic] Workspace not found:",s);return}if(!q(o)){console.error("[Mnemonic] Cannot add link to parent workspace");return}const i=r.linkText||a,l={url:a,title:i,pinned:!1},u=[...o.tabs,l];await f.updateTabs(s,u),console.log(`[Mnemonic] Added link to workspace "${o.name}":`,a);const m=await f.getById(s);if(m&&(Y(x,m),z()),F(),n){const h=await I.getSettings();await Sn(o,{lazyLoad:h.lazyLoadTabs})}}catch(o){console.error("[Mnemonic] Failed to add link to workspace:",o)}}function Xn(r,e,t){const n=r.filter(a=>{var o;return a.url===e.url&&!((o=a.url)!=null&&o.startsWith(t))});if(n.length===0)return;if(n.length===1)return n[0];const s=e.index;return n.reduce((a,o)=>{const i=o.index,l=(a==null?void 0:a.index)??1/0;return Math.abs(i-s)<Math.abs(l-s)?o:a},n[0])}const Ta=br(()=>{console.log("[Mnemonic] Background service worker initialized"),Aa(),g.runtime.onInstalled.addListener(async e=>{e.reason==="install"?(console.log("[Mnemonic] First install - initializing storage"),await I.initialize()):e.reason==="update"&&(console.log("[Mnemonic] Extension updated from",e.previousVersion),await Ia())}),g.runtime.onMessage.addListener((e,t,n)=>(Ea(e,n),!0));const r=R();g.windows.onCreated.addListener(async e=>{if(console.log("[Mnemonic] Window created:",e.id),e.id){const t=await nt(e.id);if(t){const n=await f.getById(t.params.workspaceId);n&&r.setMapping({windowId:e.id,workspaceId:n.id,isMainWindow:n.type==="parent",isTranscendent:n.isTranscendent})}}}),g.windows.onRemoved.addListener(e=>{console.log("[Mnemonic] Window removed:",e);const t=Je.get(e);t&&(clearTimeout(t),Je.delete(e),console.log(`[Mnemonic] Cancelled pending auto-save timer for closing window ${e}`),fe().log("auto_save_cancelled",{windowId:e,reason:"window_removed"})),fe().log("window_removed",{windowId:e}),r.removeWindow(e)}),g.windows.onFocusChanged.addListener(async e=>{if(e===g.windows.WINDOW_ID_NONE)return;const t=r.getWindowMapping(e);if(t)try{const n=await f.getById(t.workspaceId);if(n&&(n.metadata.lastAccessed=new Date().toISOString(),q(n)))try{const s=await g.tabs.query({windowId:e}),a=g.runtime.getURL("workspace-dashboard.html");let o,i="";const l=n.autoFocusPlayingTab?s.find(d=>{var u;return d.audible&&!((u=d.url)!=null&&u.startsWith(a))}):void 0;n.refocusTab&&n.refocusTabOverridesPlaying?(o=Xn(s,n.refocusTab,a),i=o?"refocus tab (priority)":""):l?(o=l,i="currently playing"):n.refocusTab&&(o=Xn(s,n.refocusTab,a),i=o?"refocus tab":""),o!=null&&o.id&&(await g.tabs.update(o.id,{active:!0}),console.log(`[Mnemonic] Focused ${i} "${o.title}" in workspace "${n.name}"`))}catch(s){console.warn("[Mnemonic] Refocus/playing tab focus failed:",s)}}catch{}}),g.tabs.onUpdated.addListener(async(e,t,n)=>{var a;if(t.audible!==void 0&&ma(),(t.url||t.title||t.pinned!==void 0||t.groupId!==void 0)&&n.windowId&&r.getWindowMapping(n.windowId)){const i=g.runtime.getURL("workspace-dashboard.html");if((a=n.url)!=null&&a.startsWith(i))return;await Le(n.windowId)}}),g.tabs.onCreated.addListener(async e=>{var t,n;if(e.windowId&&r.getWindowMapping(e.windowId)){const a=g.runtime.getURL("workspace-dashboard.html");if((t=e.url)!=null&&t.startsWith(a)||(n=e.pendingUrl)!=null&&n.startsWith(a))return;await Le(e.windowId)}}),g.tabs.onMoved.addListener(async(e,t)=>{r.getWindowMapping(t.windowId)&&await Le(t.windowId)}),g.tabs.onAttached.addListener(async(e,t)=>{r.getWindowMapping(t.newWindowId)&&await Le(t.newWindowId)}),g.tabs.onDetached.addListener(async(e,t)=>{r.getWindowMapping(t.oldWindowId)&&await Le(t.oldWindowId)}),g.tabs.onRemoved.addListener(async(e,t)=>{if(t.isWindowClosing)return;const n=t.windowId,s=r.getWindowMapping(n);if(s)if(await nt(n))await Le(n);else{const o=await f.getById(s.workspaceId);if(o){const i=r.markAsUntracked(n,o.name,"dashboard_closed");i&&(console.log("[Mnemonic] Window untracked - dashboard tab closed:",{windowId:n,workspace:o.name}),g.runtime.sendMessage({type:"WINDOW_UNTRACKED",payload:i}).catch(()=>{}))}}}),g.contextMenus.onClicked.addListener(Sa)});async function pt(){const r=R(),e=await f.getAll(),t=await r.scanAllWindows(e),n=r.getMappings();if(console.log("[Mnemonic] Window scan complete, found",n.length,"window-workspace associations"),t.length>0){console.log("[Mnemonic] Creating dashboard tabs for",t.length,"fingerprint-matched windows");const s=g.runtime.getURL("workspace-dashboard.html");for(const a of t)try{const o=a.workspace,i=new URL(s);if(i.searchParams.set("workspaceId",o.id),i.searchParams.set("type",o.type),i.searchParams.set("transcendent",o.isTranscendent.toString()),o.type==="child"){const d=o;i.searchParams.set("parentId",d.parentId)}const l=await g.tabs.create({windowId:a.windowId,url:i.toString(),pinned:!0,active:!1,index:0});l.id&&await g.tabs.move(l.id,{index:0}),console.log(`[Mnemonic] Created dashboard tab for workspace "${o.name}" in window ${a.windowId}`)}catch(o){console.error(`[Mnemonic] Failed to create dashboard tab for window ${a.windowId}:`,o)}}}async function Aa(){var r;try{await fe().load(),await I.initialize();const e=await I.read();if(e&&gn(e)){console.log("[Mnemonic] Running migrations...");const l=pn(e);await I.write(l)}if(e){const{config:l,report:d}=Or(e);d.wasRepaired&&(console.log("[Mnemonic] Repaired hierarchy issues:",d.fixes.length),await I.write(l))}const t=await f.validate();t.valid||console.warn("[Mnemonic] Validation errors:",t.errors);const n=await f.getAll();await ka()&&await ba(n)?console.log("[Mnemonic] Using cached search index"):(x=at(n),console.log("[Mnemonic] Search index built:",x.stats),await Yt()),await ya();const a=ce();let o=await I.read(),i=((r=o==null?void 0:o.settings)==null?void 0:r.syncBackend)||"none";if(i==="none"){console.log("[Mnemonic] No sync backend configured, checking for native bridge...");try{const{getRestBridge:l}=await Promise.resolve().then(()=>js),u=l().health(),m=new Promise((k,E)=>setTimeout(()=>E(new Error("timeout")),2e3)),h=await Promise.race([u,m]);h&&h.status==="ok"&&(console.log("[Mnemonic] Native bridge detected, auto-configuring..."),i="native",await I.updateSettings({syncBackend:"native"}),o=await I.read())}catch{console.log("[Mnemonic] Native bridge not available, continuing without sync")}}if(i!=="none")if(console.log("[Mnemonic] Initializing sync manager with backend:",i),await a.initialize(i)){if(console.log("[Mnemonic] Sync manager initialized successfully"),i==="native"){console.log("[Mnemonic:Init] Scanning windows to establish mappings before sync...");try{await pt();const u=R().getMappings();console.log("[Mnemonic:Init] Window scan complete, mappings found:",u.length);for(const m of u)console.log(`[Mnemonic:Init]   Window ${m.windowId} -> Workspace ${m.workspaceId}`)}catch(d){console.error("[Mnemonic:Init] Pre-sync window scan error:",d)}}if(i==="native"){console.log("[Mnemonic] Checking for external changes before initial sync...");try{await a.checkAndMergeExternal()?(console.log("[Mnemonic] Applied external changes on startup"),o=await I.read()):(console.log("[Mnemonic] No external changes detected"),o&&(console.log("[Mnemonic] Performing initial sync to REST bridge..."),a.syncToExternal(o)))}catch(d){console.error("[Mnemonic] Error checking external changes on startup:",d)}Ue=!0,console.log("[Mnemonic:Init] Initial sync complete, auto-save and storage sync enabled"),ha()}else Ue=!0,console.log("[Mnemonic:Init] Non-native backend, auto-save enabled")}else console.warn("[Mnemonic] Failed to initialize sync manager"),Ue=!0;else Ue=!0,console.log("[Mnemonic:Init] No sync backend, auto-save enabled");if(!K.apiKey&&i==="native")try{const{getCredentialVault:l}=await Promise.resolve().then(()=>he),{getCredentialsSync:d}=await Promise.resolve().then(()=>Se),u=l();if(u.setCredentialsSync(d()),await u.isUnlocked()){const m=await u.getCredential("claude");m&&m.apiKey&&(ye().setApiKey(m.apiKey),K.apiKey=m.apiKey,K.enabled=!0,m.autoSuggest!==void 0&&(K.autoSuggest=m.autoSuggest),console.log("[Mnemonic] Claude API key restored from vault"))}}catch(l){console.warn("[Mnemonic] Failed to restore credentials from vault:",l)}ut&&(ut(),ut=null),ut=I.onChanged(async l=>{if(!Ue){console.log("[Mnemonic] Storage sync blocked - waiting for initial sync to complete");return}a.getBackendType()==="native"&&l.newValue&&(console.log("[Mnemonic] Storage changed, syncing to REST bridge..."),a.syncToExternal(l.newValue))}),console.log("[Mnemonic] Scanning windows for workspace matching..."),await pt(),await ie(),console.log("[Mnemonic] Extension initialized successfully")}catch(e){console.error("[Mnemonic] Initialization error:",e)}}async function Ia(){try{const r=await I.read();if(r&&gn(r)){console.log("[Mnemonic] Migrating configuration...");const e=pn(r);await I.write(e),console.log("[Mnemonic] Migration complete")}}catch(r){console.error("[Mnemonic] Update migration error:",r)}}async function Ea(r,e){var t;try{switch(r.type){case"PING":e({status:"ok",timestamp:Date.now()});break;case"GET_WORKSPACES":const n=await f.getAll();e(n);break;case"GET_PARENTS":const s=await f.getParents();e(s);break;case"GET_CHILDREN":const{parentId:a}=r.payload,o=await f.getChildren(a);e(o);break;case"GET_WORKSPACE":const{id:i}=r.payload,l=await f.getById(i);e(l);break;case"CREATE_PARENT":const d=r.payload,u=await f.createParent(d.name,d);Y(x,u),z(),e({success:!0,workspace:u}),ie();break;case"CREATE_CHILD":const m=r.payload,h=await f.createChild(m.parentId,m.name,m.tabs||[],{openInContextSwitch:m.openInContextSwitch,syncEnabled:m.syncEnabled});Y(x,h),z(),e({success:!0,workspace:h}),F(),ie();break;case"CREATE_STANDALONE":const k=r.payload,E=await f.createStandalone(k.name,k.tabs||[],{openInContextSwitch:k.openInContextSwitch,syncEnabled:k.syncEnabled});Y(x,E),z(),e({success:!0,workspace:E}),F(),ie();break;case"RENAME_WORKSPACE":const y=r.payload;await f.rename(y.id,y.name);const _=await f.getById(y.id);_&&(Y(x,_),z()),e({success:!0}),ie();break;case"UPDATE_WORKSPACE":const S=r.payload;await f.update(S.id,S.updates);const O=await f.getById(S.id);O&&(Y(x,O),z()),e({success:!0});break;case"DELETE_WORKSPACE":const D=r.payload;await f.delete(D.id,{keepChildren:D.keepChildren??!0}),ot(x,D.id),z(),e({success:!0}),F(),ie();break;case"MOVE_WORKSPACE":const U=r.payload;await f.move(U.id,U.newParentId);const oe=await f.getById(U.id);oe&&(Y(x,oe),z()),e({success:!0}),ie();break;case"SET_TRANSCENDENT":const T=r.payload;await f.setTranscendent(T.id,T.isTranscendent);const A=await f.getById(T.id);A&&(Y(x,A),z()),e({success:!0});break;case"CONVERT_TO_PARENT":const P=r.payload;await f.convertToParent(P.id);const N=await f.getById(P.id);N&&(Y(x,N),z()),e({success:!0});break;case"CREATE_GROUP":try{const c=r.payload,p=await f.createGroup(c.parentId,c.name,{color:c.color});e({success:!0,group:p}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to create group"})}break;case"RENAME_GROUP":try{const c=r.payload;await f.renameGroup(c.parentId,c.groupId,c.name),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to rename group"})}break;case"DELETE_GROUP":try{const c=r.payload;await f.deleteGroup(c.parentId,c.groupId),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to delete group"})}break;case"SET_CHILD_GROUP":try{const c=r.payload;await f.setChildGroup(c.childId,c.groupId),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to set child group"})}break;case"TOGGLE_GROUP_COLLAPSED":try{const c=r.payload;await f.toggleGroupCollapsed(c.parentId,c.groupId),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to toggle group"})}break;case"UPDATE_GROUP_COLOR":try{const c=r.payload;await f.updateGroupColor(c.parentId,c.groupId,c.color),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to update group color"})}break;case"SET_OPEN_IN_CONTEXT_SWITCH":const J=r.payload;await f.setOpenInContextSwitch(J.id,J.openInContextSwitch),e({success:!0});break;case"SET_SYNC_ENABLED":const re=r.payload;await f.setSyncEnabled(re.id,re.syncEnabled),e({success:!0});break;case"SET_REFOCUS_TAB":try{const c=r.payload,p=await f.getById(c.workspaceId);if(!p||!q(p)){e({success:!1,error:"Workspace not found or not a tab workspace"});break}await f.update(c.workspaceId,{refocusTab:{url:c.url,index:c.index}}),console.log(`[Mnemonic] Set refocus tab for workspace "${p.name}":`,c.url),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to set refocus tab"})}break;case"CLEAR_REFOCUS_TAB":try{const c=r.payload,p=await f.getById(c.workspaceId);if(!p||!q(p)){e({success:!1,error:"Workspace not found or not a tab workspace"});break}await f.update(c.workspaceId,{refocusTab:void 0}),console.log(`[Mnemonic] Cleared refocus tab for workspace "${p.name}"`),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to clear refocus tab"})}break;case"SET_AUTO_FOCUS_PLAYING_TAB":try{const c=r.payload,p=await f.getById(c.workspaceId);if(!p||!q(p)){e({success:!1,error:"Workspace not found or not a tab workspace"});break}await f.update(c.workspaceId,{autoFocusPlayingTab:c.enabled}),console.log(`[Mnemonic] Set autoFocusPlayingTab=${c.enabled} for workspace "${p.name}"`),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to set auto focus playing tab"})}break;case"SET_REFOCUS_TAB_OVERRIDES_PLAYING":try{const c=r.payload,p=await f.getById(c.workspaceId);if(!p||!q(p)){e({success:!1,error:"Workspace not found or not a tab workspace"});break}await f.update(c.workspaceId,{refocusTabOverridesPlaying:c.enabled}),console.log(`[Mnemonic] Set refocusTabOverridesPlaying=${c.enabled} for workspace "${p.name}"`),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to set refocus tab overrides playing"})}break;case"UPDATE_TABS":const se=r.payload;await f.updateTabs(se.id,se.tabs);const v=await f.getById(se.id);v&&(Y(x,v),z()),e({success:!0});break;case"UPDATE_SUMMARY":const Q=r.payload;await f.updateSummary(Q.id,Q.text,Q.isUserGenerated);const G=await f.getById(Q.id);G&&(Y(x,G),z()),e({success:!0});break;case"ENRICH_TABS":const we=r.payload;try{const c=await qt(we.tabs,we.maxTabs||10);e({success:!0,result:c})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to enrich tabs"})}break;case"GENERATE_WORKSPACE_SUMMARY":const Ae=r.payload;try{if(!K.enabled||!K.apiKey){e({success:!1,error:"Claude not configured"});break}const c=await f.getById(Ae.workspaceId);if(!c){e({success:!1,error:"Workspace not found"});break}if(!q(c)){e({success:!1,error:"Cannot generate summary for parent workspace"});break}const p=ye();p.setApiKey(K.apiKey),K.model&&p.setModel(K.model);const w=await qt(c.tabs,15),C=await De().generateSummaryFromTabs(c.name,w.tabs.map(W=>({url:W.url,title:W.title,enrichedTitle:W.enrichedTitle,description:W.description})));C.success&&C.summary?(await f.updateSummary(Ae.workspaceId,C.summary,!1),e({success:!0,summary:C.summary})):e({success:!1,error:C.error||"Failed to generate summary"})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to generate summary"})}break;case"EXPORT_CONFIG":const le=await I.export();e({success:!0,data:le});break;case"IMPORT_CONFIG":const Qe=r.payload,sr=await I.import(Qe.data);e({success:sr.success,error:sr.error});break;case"VALIDATE":const Wa=await f.validate();e(Wa);break;case"GET_SETTINGS":const _a=await I.getSettings();e(_a);break;case"UPDATE_SETTINGS":const Oa=r.payload;await I.updateSettings(Oa),e({success:!0});break;case"INIT_SYNC_BACKEND":try{const c=r.payload;console.log("[Mnemonic] INIT_SYNC_BACKEND called with backend:",c.backendType);const p=ce(),w=await p.initialize(c.backendType);if(console.log("[Mnemonic] Sync initialize result:",w),w&&c.backendType==="native"){const b=await f.getAll();if(console.log("[Mnemonic] Current local workspaces count:",b.length),b.length===0){console.log("[Mnemonic] Native sync enabled with empty local storage, pulling from external...");try{const C=await p.forcePullFromExternal();console.log("[Mnemonic] Pulled existing sync data, result:",C)}catch(C){console.log("[Mnemonic] No existing sync data or pull failed:",C)}}console.log("[Mnemonic] Sync backend initialized, scanning windows..."),setTimeout(async()=>{try{await pt()}catch(C){console.error("[Mnemonic] Post-sync window scan error:",C)}},1e3)}e({success:w})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to init sync"})}break;case"SELECT_SYNC_DIRECTORY":try{const p=await ce().selectDirectory();e({success:p})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to select directory"})}break;case"SWITCH_CONTEXT":const Na=r.payload,Da=await f.getAll(),Fa=await I.getSettings(),Ua=await Zr(Na,Da,{lazyLoad:Fa.lazyLoadTabs});e(Ua),F();break;case"QUICK_SWITCH":const Ba=r.payload,ar=await f.getById(Ba.workspaceId);if(ar){const c=await I.getSettings(),p=await Sn(ar,{lazyLoad:c.lazyLoadTabs});e({success:p!==null,windowId:p}),F()}else e({success:!1,error:"Workspace not found"});break;case"CLOSE_WORKSPACE_WINDOWS":const La=r.payload,$a=await Xr(La.workspaceId);e({success:$a}),F();break;case"SAVE_WINDOW_STATE":const et=r.payload,tn=await f.getById(et.workspaceId);if(tn&&q(tn)){const c=await Oe(et.windowId),p=await rt(et.windowId),w=await Qr(tn,et.windowId);await f.updateTabs(et.workspaceId,c),p&&(w.windowPosition=p),e({success:!0,tabs:c.length,position:p})}else e({success:!1,error:"Workspace not found or not a tab workspace"});break;case"GET_WINDOW_MAPPINGS":const Ra=R();e(Ra.getMappings());break;case"IDENTIFY_WINDOW":const ja=r.payload,Ka=R(),za=await f.getAll(),Ga=await Ka.identifyWindow(ja.windowId,za);e(Ga);break;case"SCAN_ALL_WINDOWS":const or=R(),Ha=await f.getAll();await or.scanAllWindows(Ha),e({success:!0,mappings:or.getMappings()});break;case"SEARCH":const nn=r.payload;let ir=fs(x,nn.query,nn.options);if(nn.generateMissingSummaries&&K.enabled&&K.apiKey){const c=ir.results.filter(p=>p.document.type==="workspace"&&!p.document.summary).slice(0,3);if(c.length>0){const p=De();for(const w of c)try{const b=await f.getById(w.document.id);if(!b||b.summary)continue;let C;if(b.type==="parent"){const B=(await f.getAll()).filter(H=>H.type==="child"&&H.parentId===b.id).map(H=>{var te;return{name:H.name,summary:(te=H.summary)==null?void 0:te.text}}),L=await p.generateSummaryFromChildren(b.name,B);C=L==null?void 0:L.summary}else{const W=b;if(W.tabs&&W.tabs.length>0){const ee=await qt(W.tabs,10),B=await p.generateSummaryFromTabs(b.name,ee);C=B==null?void 0:B.summary}}if(C){await f.updateSummary(b.id,C,!1),w.document.summary=C;const W=await f.getById(b.id);W&&Y(x,W)}}catch(b){console.warn(`Failed to generate summary for workspace ${w.document.id}:`,b)}}}e(ir);break;case"GET_SEARCH_SUGGESTIONS":const cr=r.payload,Va=bs(x,cr.prefix,cr.limit);e(Va);break;case"QUICK_SEARCH":const lr=r.payload,qa=Ss(x,lr.query,lr.limit);e(qa);break;case"REBUILD_SEARCH_INDEX":const Ya=await f.getAll();x=at(Ya),console.log("[Mnemonic] Search index rebuilt:",x.stats),await Yt(),e({success:!0,stats:x.stats});break;case"UPDATE_SEARCH_INDEX":const dr=r.payload,ur=await f.getById(dr.workspaceId);ur?(Y(x,ur),e({success:!0})):(ot(x,dr.workspaceId),e({success:!0,removed:!0})),z();break;case"SET_CLAUDE_API_KEY":const ht=r.payload;ye().setApiKey(ht.apiKey),K.apiKey=ht.apiKey,K.enabled=ht.apiKey!==null,ht.apiKey||Be(!1),Zn(),e({success:!0,enabled:K.enabled});break;case"GET_CLAUDE_SETTINGS":e({...K,apiKey:K.apiKey?"****":null,isConfigured:ye().isConfigured()});break;case"UPDATE_CLAUDE_SETTINGS":const rn=r.payload;K={...K,...rn},rn.model&&ye().setModel(rn.model),Zn(),e({success:!0});break;case"TEST_CLAUDE_CONNECTION":const gr=ye();if(!gr.isConfigured())e({success:!1,error:"API key not configured"});else{const c=await gr.testConnection();Be(!c.success),e(c)}break;case"GET_WORKSPACE_SUGGESTIONS":const Ja=De(),Za=await f.getAll(),pr=await Ja.getSuggestions(Za);Be(!pr.success),e(pr);break;case"SUGGEST_PARENT_NAME":const Xa=r.payload,Qa=(await Promise.all(Xa.childWorkspaceIds.map(c=>f.getById(c)))).filter(c=>c!==null&&c.type==="child"),eo=await De().suggestParentName(Qa);e({success:!0,suggestions:eo});break;case"CATEGORIZE_TABS":const to=r.payload,no=await f.getAll(),fr=await De().categorizeOrphanTabs(to.tabs,no);Be(!fr.success),e(fr);break;case"SUGGEST_TRANSCENDENT":try{const c=await f.getAll(),p=await De().suggestTranscendent(c);Be(!1),e({success:!0,workspaceIds:p})}catch(c){Be(!0),e({success:!1,error:c instanceof Error?c.message:"Failed to get suggestions"})}break;case"GET_UNTRACKED_WINDOWS":e({windows:R().getUntrackedWindows()});break;case"RETRACK_WINDOW":const sn=r.payload,mr=await f.getById(sn.workspaceId);mr?(R().retrackWindow(sn.windowId,sn.workspaceId,mr.isTranscendent),e({success:!0})):e({success:!1,error:"Workspace not found"});break;case"CLEAR_UNTRACKED":const ro=r.payload;R().clearUntracked(ro.windowId),e({success:!0});break;case"GET_CONTEXT_SWITCH_CONFIRMATION":const so=r.payload,ao=await f.getAll(),oo=await Jr(so.targetParentId,ao);e({success:!0,confirmation:oo});break;case"INITIALIZE_SYNC":const an=r.payload;console.log("[Mnemonic] INITIALIZE_SYNC called with backend:",an.backendType);const on=ce(),cn=await on.initialize(an.backendType);if(console.log("[Mnemonic] Sync initialize result:",cn),cn&&an.backendType==="native"){const c=await f.getAll();if(console.log("[Mnemonic] Current local workspaces count:",c.length),c.length===0){console.log("[Mnemonic] Native sync enabled with empty local storage, pulling from external...");try{const p=await on.forcePullFromExternal();console.log("[Mnemonic] Pulled existing sync data, result:",p)}catch(p){console.log("[Mnemonic] No existing sync data or pull failed:",p)}}else console.log("[Mnemonic] Local storage has workspaces, skipping pull")}e({success:cn,state:on.getState()});break;case"GET_SYNC_STATE":e({state:ce().getState()});break;case"SYNC_NOW":const hr=ce(),wr=await I.read();if(wr){const c=await hr.forceSyncToExternal(wr);e({success:c,state:hr.getState()})}else e({success:!1,error:"No configuration to sync"});break;case"CHECK_EXTERNAL_CHANGES":try{const c=await ce().checkAndMergeExternal();e({success:!0,hasChanges:c})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to check external changes"})}break;case"TEST_SYNC_CONNECTION":try{const c=await ce().testConnection();e(c)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Connection test failed"})}break;case"RESTORE_SYNC_BACKUP":try{const c=await ce().restoreFromBackup();e({success:c})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to restore backup"})}break;case"GET_BACKUPS":try{const c=ae();if(!await c.ensureConnected()){e({success:!1,error:"REST bridge not connected"});break}const p=await c.listBackups();e(p)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to list backups"})}break;case"PREVIEW_BACKUP":try{const c=r.payload,p=ae();if(!await p.ensureConnected()){e({success:!1,error:"REST bridge not connected"});break}const w=await p.previewBackup(c.filename);e(w)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to preview backup"})}break;case"RESTORE_VERSIONED_BACKUP":try{const c=r.payload,p=ae();if(!await p.ensureConnected()){e({success:!1,error:"REST bridge not connected"});break}const w=await p.restoreFromBackup(c.filename);w.success&&await ce().forcePullFromExternal(),e(w)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to restore from backup"})}break;case"DELETE_BACKUP":try{const c=r.payload,p=ae();if(!await p.ensureConnected()){e({success:!1,error:"REST bridge not connected"});break}const w=await p.deleteBackup(c.filename);e(w)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to delete backup"})}break;case"PRUNE_BACKUPS":try{const c=ae();if(!await c.ensureConnected()){e({success:!1,error:"REST bridge not connected"});break}const p=await c.pruneBackups();e(p)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to prune backups"})}break;case"SEARCH_BACKUPS":try{const c=r.payload,p=ae();if(!await p.ensureConnected()){e({success:!1,error:"REST bridge not connected"});break}const w=await p.searchBackups(c.query);e(w)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to search backups"})}break;case"RESTORE_SELECTIVE_BACKUP":try{const c=r.payload,p=ae();if(!await p.ensureConnected()){e({success:!1,error:"REST bridge not connected"});break}const w=await p.restoreSelectiveFromBackup(c.filename,c.workspaceIds);w.success&&await ce().forcePullFromExternal(),e(w)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to restore selective backup"})}break;case"GET_AUDIBLE_TABS":try{const c=await g.tabs.query({audible:!0}),p=R();let w=p.getMappings();if(w.length===0){const B=await f.getAll();await p.scanAllWindows(B),w=p.getMappings()}const b=[],C=[];for(const B of c)if(B.windowId&&B.id){const L=w.find(te=>te.windowId===B.windowId),H=L==null?void 0:L.workspaceId;H&&!b.includes(H)&&b.push(H),C.push({tabId:B.id,windowId:B.windowId,title:B.title||"Untitled",url:B.url||"",workspaceId:H})}const W=await f.getAll(),ee=[];for(const B of W)B.type==="parent"&&W.filter(te=>te.type==="child"&&te.parentId===B.id).some(te=>b.includes(te.id))&&ee.push(B.id);e({success:!0,audibleWorkspaceIds:b,parentWithAudibleChildren:ee,audibleTabs:C})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to get audible tabs"})}break;case"PAUSE_ALL_MEDIA":try{const c=await g.tabs.query({});let p=0;const w=()=>{let b=0;if(document.querySelectorAll("video").forEach(C=>{try{C.paused||(C.pause(),b++)}catch{}}),document.querySelectorAll("audio").forEach(C=>{try{C.paused||(C.pause(),b++)}catch{}}),window.location.hostname.includes("youtube.com")){const C=document.querySelector("#movie_player")||document.querySelector(".html5-video-player");C&&(C.focus(),C.dispatchEvent(new KeyboardEvent("keydown",{key:"k",code:"KeyK",keyCode:75,which:75,bubbles:!0,cancelable:!0})),b++)}return b};for(const b of c)if(b.id&&b.url&&(b.url.startsWith("http://")||b.url.startsWith("https://")))try{await g.tabs.sendMessage(b.id,{type:"PAUSE_MEDIA"}),p++}catch{try{await g.scripting.executeScript({target:{tabId:b.id},func:w}),p++}catch{}}e({success:!0,pausedCount:p})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to pause media"})}break;case"FOCUS_TAB":try{const c=r.payload;await g.windows.update(c.windowId,{focused:!0}),await g.tabs.update(c.tabId,{active:!0}),e({success:!0})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to focus tab"})}break;case"GET_SHARED_WORKSPACES":try{const c=ae(),p=ce();if(!c.isConnected()&&!await c.connect()){e({success:!1,error:"REST bridge not connected"});break}if(p.getBackendType()==="native"){const C=await I.read();C&&(console.log("[Mnemonic] Pushing current workspaces before reading shared file..."),await p.forceSyncToExternal(C))}const w=await c.read();if(!w.success){e({success:!1,error:"Failed to read shared file"});break}let b;w.data&&typeof w.data=="object"?(b=w.data,b.browsers||(b.browsers={})):b={...Nn,lastModified:new Date().toISOString(),browsers:{}},e({success:!0,data:b})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to get shared workspaces"})}break;case"PULL_WORKSPACES":try{const c=r.payload,p=ae();if(!p.isConnected()&&!await p.connect()){e({success:!1,error:"REST bridge not connected"});break}const w=await p.read();if(!w.success||!w.data){e({success:!1,error:"No shared data available"});break}const C=w.data.browsers[c.sourceBrowser];if(!C){e({success:!1,error:`No workspaces from ${c.sourceBrowser}`});break}const W=C.workspaces.filter(V=>c.workspaceIds.includes(V.id)),ee=[];for(const V of W)V.type==="parent"&&V.children&&ee.push(...V.children);const B=C.workspaces.filter(V=>ee.includes(V.id)),L=[...W,...B],H=new Map;for(const V of L)H.set(V.id,crypto.randomUUID());const te=await I.read();if(!te){e({success:!1,error:"Failed to read storage"});break}for(const V of L){const Ke=H.get(V.id),ze=V.parentId?H.get(V.parentId)||V.parentId:null,ln=(t=V.children)==null?void 0:t.map(yr=>H.get(yr)||yr),io={...V,id:Ke,parentId:ze,children:ln,metadata:{...V.metadata,created:new Date().toISOString(),lastModified:new Date().toISOString(),lastAccessed:new Date().toISOString()}};te.workspaces.push(io)}await I.write(te),x=at(te.workspaces),e({success:!0,pulledCount:L.length})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to pull workspaces"})}break;case"CHECK_BRIDGE_STATUS":try{const c=ae(),p=c.isConnected();if(console.log("[Mnemonic] Bridge status check - isConnected:",p),p)e({success:!0,connected:!0,browserKey:gt()});else{console.log("[Mnemonic] Attempting to connect to REST bridge...");const w=await c.connect();console.log("[Mnemonic] Connection result:",w),e({success:!0,connected:w,browserKey:gt()})}}catch(c){console.error("[Mnemonic] Bridge status check failed:",c),e({success:!0,connected:!1})}break;case"SEND_TAB_TRANSFER":try{const c=r.payload,p=ae();if(!p.isConnected()&&!await p.connect()){e({success:!1,error:"Bridge not connected"});break}const w=await p.sendTransfer({source_browser:gt(),target_browser:c.target_browser,target_workspace_id:c.target_workspace_id,target_workspace_name:c.target_workspace_name,tab:c.tab});e({success:w.success,transfer_id:w.transfer_id})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Transfer failed"})}break;case"ARCHIVE_WORKSPACE":try{const c=r.payload;await f.archive(c.id),ot(x,c.id),z(),e({success:!0}),F(),ie()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to archive workspace"})}break;case"ARCHIVE_CONTEXT":try{const c=r.payload,p=await f.archiveContext(c.parentId);(await f.getArchived()).forEach(b=>ot(x,b.id)),z(),e({success:!0,archivedCount:p.archivedCount}),F(),ie()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to archive context"})}break;case"RESTORE_WORKSPACE":try{const c=r.payload;await f.restore(c.id);const p=await f.getById(c.id);p&&Y(x,p),z(),e({success:!0}),F(),ie()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to restore workspace"})}break;case"RESTORE_CONTEXT":try{const c=r.payload,p=await f.restoreContext(c.parentId),w=await f.getActive();x=at(w),z(),e({success:!0,restoredCount:p.restoredCount}),F(),ie()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to restore context"})}break;case"PERMANENTLY_DELETE_WORKSPACE":try{const c=r.payload;await f.permanentlyDelete(c.id),e({success:!0}),F(),ie()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to permanently delete workspace"})}break;case"GET_ARCHIVED_WORKSPACES":try{const c=await f.getArchived();e(c)}catch(c){e({error:c instanceof Error?c.message:"Failed to get archived workspaces"})}break;case"EXPORT_TO_BOOKMARKS":try{const c=r.payload,p=await f.getById(c.workspaceId);if(!p){e({success:!1,error:"Workspace not found"});break}if(p.type==="parent"){e({success:!1,error:"Use EXPORT_CONTEXT_TO_BOOKMARKS for parent workspaces"});break}const w=await la(p);e(w)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to export to bookmarks"})}break;case"EXPORT_CONTEXT_TO_BOOKMARKS":try{const c=r.payload,p=await f.getById(c.parentId);if(!p||p.type!=="parent"){e({success:!1,error:"Parent workspace not found"});break}const b=(await f.getAll()).filter(W=>W.type==="child"&&W.parentId===c.parentId),C=await da(p,b);e(C)}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to export context to bookmarks"})}break;case"GET_BOOKMARK_FOLDERS":try{const p=(await ua()).map(w=>({...w,structure:qn(w),recommendedMode:Yn(w)}));e({success:!0,folders:p})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to get bookmark folders"})}break;case"IMPORT_FROM_BOOKMARKS":try{const c=r.payload,{folderData:p,mode:w,parentId:b}=c;if((w==="auto"?Yn(p):w)==="standalone"||b){const W=ga(p);if(W.length===0){e({success:!1,error:"No valid bookmarks to import"});break}const ee=await f.create({name:p.title,type:b?"child":"standalone",parentId:b||null,tabs:W});Y(x,ee),z(),e({success:!0,workspaceId:ee.id,tabCount:W.length}),F(),ie()}else{const W=pa(p);if(W.children.length===0||W.children.every(L=>L.tabs.length===0)){e({success:!1,error:"No valid bookmarks to import"});break}const ee=await f.create({name:W.parentName,type:"parent",parentId:null});let B=0;for(const L of W.children)if(L.tabs.length>0){const H=await f.create({name:L.name,type:"child",parentId:ee.id,tabs:L.tabs});Y(x,H),B+=L.tabs.length}Y(x,ee),z(),e({success:!0,parentId:ee.id,childrenCount:W.children.filter(L=>L.tabs.length>0).length,tabCount:B}),F(),ie()}}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to import from bookmarks"})}break;case"MOVE_TAB":try{const c=r.payload,p=await f.getById(c.sourceWorkspaceId),w=await f.getById(c.targetWorkspaceId);if(!p){e({success:!1,error:"Source workspace not found"});break}if(!w){e({success:!1,error:"Target workspace not found"});break}if(!q(p)){e({success:!1,error:"Source workspace cannot contain tabs"});break}if(!q(w)){e({success:!1,error:"Target workspace cannot contain tabs"});break}const b=p,C=w,W=[...b.tabs];if(c.tabIndex<0||c.tabIndex>=W.length){e({success:!1,error:"Invalid tab index"});break}W.splice(c.tabIndex,1),await f.updateTabs(c.sourceWorkspaceId,W,{allowEmpty:!0});const ee=[...C.tabs,c.tab];await f.updateTabs(c.targetWorkspaceId,ee);const B=R(),L=B.getWorkspaceWindow(c.sourceWorkspaceId);if(L!==void 0)try{const ze=(await g.tabs.query({windowId:L})).find(ln=>ln.url===c.tab.url);ze!=null&&ze.id&&await g.tabs.remove(ze.id)}catch(Ke){console.warn("[Mnemonic] Failed to close tab in source window:",Ke)}const H=B.getWorkspaceWindow(c.targetWorkspaceId);if(H!==void 0)try{await g.tabs.create({windowId:H,url:c.tab.url,pinned:c.tab.pinned||!1,active:!1})}catch(Ke){console.warn("[Mnemonic] Failed to open tab in target window:",Ke)}const te=await f.getById(c.sourceWorkspaceId),V=await f.getById(c.targetWorkspaceId);te&&Y(x,te),V&&Y(x,V),z(),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to move tab"})}break;case"RESCAN_WINDOW_MAPPINGS":try{console.log("[Mnemonic] Manual rescan of window mappings requested"),await pt(),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to rescan window mappings"})}break;case"CLEAR_MANUAL_MAPPINGS":try{const c=r.payload,p=await f.getAll();if(c!=null&&c.workspaceId){const w=p.find(b=>b.id===c.workspaceId);w&&(w.type==="child"||w.type==="standalone")&&(await f.update(w.id,{manuallyAssignedWindowId:null}),console.log("[Mnemonic] Cleared manual mapping for workspace:",w.name))}else for(const w of p)(w.type==="child"||w.type==="standalone")&&w.manuallyAssignedWindowId&&(await f.update(w.id,{manuallyAssignedWindowId:null}),console.log("[Mnemonic] Cleared manual mapping for workspace:",w.name));e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to clear manual mappings"})}break;case"SET_MANUAL_MAPPING":try{const c=r.payload;await f.update(c.workspaceId,{manuallyAssignedWindowId:c.windowId}),console.log("[Mnemonic] Set manual mapping for workspace:",c.workspaceId,"→ window:",c.windowId),e({success:!0}),F()}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to set manual mapping"})}break;case"VAULT_STATUS":try{const{getCredentialVault:c}=await Promise.resolve().then(()=>he),{getCredentialsSync:p}=await Promise.resolve().then(()=>Se),w=c();w.setCredentialsSync(p());const b=await w.getStatus();e({success:!0,...b})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to get vault status"})}break;case"VAULT_SETUP":try{const c=r.payload,{getCredentialVault:p}=await Promise.resolve().then(()=>he),{getCredentialsSync:w}=await Promise.resolve().then(()=>Se),b=p();b.setCredentialsSync(w()),await b.setupMasterPassword(c.password),e({success:!0})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to setup master password"})}break;case"VAULT_UNLOCK":try{const c=r.payload,{getCredentialVault:p}=await Promise.resolve().then(()=>he),{getCredentialsSync:w}=await Promise.resolve().then(()=>Se),b=p();b.setCredentialsSync(w());const C=await b.unlock(c.password);e({success:C,error:C?void 0:"Incorrect password"})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to unlock vault"})}break;case"VAULT_LOCK":try{const{getCredentialVault:c}=await Promise.resolve().then(()=>he);await c().lock(),e({success:!0})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to lock vault"})}break;case"VAULT_STORE_CREDENTIAL":try{const c=r.payload,{getCredentialVault:p}=await Promise.resolve().then(()=>he),{getCredentialsSync:w}=await Promise.resolve().then(()=>Se),b=p();b.setCredentialsSync(w()),await b.storeCredential(c.type,c.credentials),e({success:!0})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to store credential"})}break;case"VAULT_GET_CREDENTIAL":try{const c=r.payload,{getCredentialVault:p}=await Promise.resolve().then(()=>he),{getCredentialsSync:w}=await Promise.resolve().then(()=>Se),b=p();b.setCredentialsSync(w());const C=await b.getCredential(c.type);e({success:!0,credential:C})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to get credential"})}break;case"VAULT_REMOVE_CREDENTIAL":try{const c=r.payload,{getCredentialVault:p}=await Promise.resolve().then(()=>he),{getCredentialsSync:w}=await Promise.resolve().then(()=>Se),b=p();b.setCredentialsSync(w()),await b.removeCredential(c.type),e({success:!0})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to remove credential"})}break;case"VAULT_CHANGE_PASSWORD":try{const c=r.payload,{getCredentialVault:p}=await Promise.resolve().then(()=>he),{getCredentialsSync:w}=await Promise.resolve().then(()=>Se),b=p();b.setCredentialsSync(w()),await b.changeMasterPassword(c.oldPassword,c.newPassword),e({success:!0})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to change password"})}break;case"GET_DEBUG_LOGS":try{const p=fe().getEntries();e({success:!0,entries:p})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to get debug logs"})}break;case"CLEAR_DEBUG_LOGS":try{await fe().clear(),e({success:!0})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to clear debug logs"})}break;case"EXPORT_DEBUG_LOGS":try{const c=fe().export();e({success:!0,data:c})}catch(c){e({success:!1,error:c instanceof Error?c.message:"Failed to export debug logs"})}break;default:e({error:`Unknown message type: ${r.type}`})}}catch(n){const s=n instanceof Error?n.message:"Unknown error";console.error("[Mnemonic] Message handler error:",s),e({error:s})}}function go(){}function ft(r,...e){}const Ma={debug:(...r)=>ft(console.debug,...r),log:(...r)=>ft(console.log,...r),warn:(...r)=>ft(console.warn,...r),error:(...r)=>ft(console.error,...r)};let Jt;try{Jt=Ta.main(),Jt instanceof Promise&&console.warn("The background's main() function return a promise, but it must be synchronous")}catch(r){throw Ma.error("The background crashed on startup!"),r}const Ca=Jt,$e=1e5,Qn=256,xa=16,va=12;function Pe(r){let e="";for(let t=0;t<r.length;t++)e+=String.fromCharCode(r[t]);return btoa(e)}function We(r){const e=atob(r),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}function Zt(){return crypto.getRandomValues(new Uint8Array(xa))}function er(){return crypto.getRandomValues(new Uint8Array(va))}async function Ze(r,e,t=$e){const s=new TextEncoder().encode(r),a=await crypto.subtle.importKey("raw",s,"PBKDF2",!1,["deriveKey"]);return await crypto.subtle.deriveKey({name:"PBKDF2",salt:e,iterations:t,hash:"SHA-256"},a,{name:"AES-GCM",length:Qn},!0,["encrypt","decrypt"])}async function Te(r,e){const n=new TextEncoder().encode(r),s=er(),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:s},e,n);return{ciphertext:Pe(new Uint8Array(a)),iv:Pe(s)}}async function mt(r,e,t){const n=We(r),s=We(e),a=await crypto.subtle.decrypt({name:"AES-GCM",iv:s},t,n);return new TextDecoder().decode(a)}async function tr(r){const e=await crypto.subtle.exportKey("raw",r);return Pe(new Uint8Array(e))}async function nr(r){const e=We(r);return crypto.subtle.importKey("raw",e,{name:"AES-GCM",length:Qn},!0,["encrypt","decrypt"])}async function Xt(r,e,t,n){try{return await mt(e,t,r)===n}catch{return!1}}const Re="mnemonicDeviceKey",je="keyDerivationSalt",Qt="keyCreatedAt",Xe="mnemonic-vault-verification-v1";class rr{constructor(){M(this,"cachedKey",null);M(this,"cachedSalt",null);M(this,"credentialsSync",null)}setCredentialsSync(e){this.credentialsSync=e}async isUnlocked(){if(this.cachedKey)return!0;try{const e=await g.storage.local.get([Re,je]);if(e[Re]&&e[je])return this.cachedKey=await nr(e[Re]),this.cachedSalt=We(e[je]),!0}catch(e){console.error("[Mnemonic Vault] Failed to restore cached key:",e)}return!1}async getStatus(){const e=await this.isUnlocked(),t=await this.hasEncryptedCredentials(),n={claude:!1,todoist:!1,logseq:!1};if(e&&t)try{const s=await this.fetchCredentialsFile();s&&(n.claude=!!s.credentials.claude,n.todoist=!!s.credentials.todoist,n.logseq=!!s.credentials.logseq)}catch{}return{exists:t,unlocked:e,credentials:n,lastModified:void 0}}async setupMasterPassword(e){if(!e||e.length<8)throw new Error("Password must be at least 8 characters");const t=Zt(),n=await Ze(e,t,$e),s=await Te(Xe,n);await this.cacheDeviceKey(n,t);const a={version:1,encryption:{method:"AES-256-GCM",keyDerivation:"PBKDF2-SHA256",iterations:$e,saltBase64:Pe(t),testCiphertext:s.ciphertext,testIV:s.iv},credentials:{},integrationStates:{},lastModified:new Date().toISOString()};await this.migrateExistingCredentials(n,a),await this.pushCredentialsFile(a),console.log("[Mnemonic Vault] Master password set up successfully")}async unlock(e){const t=await this.fetchCredentialsFile();if(!t)throw new Error("No encrypted credentials found");const n=We(t.encryption.saltBase64),s=await Ze(e,n,t.encryption.iterations);return await Xt(s,t.encryption.testCiphertext,t.encryption.testIV,Xe)?(await this.cacheDeviceKey(s,n),console.log("[Mnemonic Vault] Vault unlocked successfully"),!0):(console.log("[Mnemonic Vault] Unlock failed - incorrect password"),!1)}async lock(){this.cachedKey=null,this.cachedSalt=null,await g.storage.local.remove([Re,je,Qt]),console.log("[Mnemonic Vault] Vault locked")}async storeCredential(e,t){var i;if(!this.cachedKey)throw new Error("Vault is locked");let n=await this.fetchCredentialsFile();if(!n)throw new Error("No credentials file found - set up master password first");const s=JSON.stringify(t),a=await Te(s,this.cachedKey),o=new Date().toISOString();n.credentials[e]={encryptedBlob:a.ciphertext,ivBase64:a.iv,createdAt:((i=n.credentials[e])==null?void 0:i.createdAt)||o,updatedAt:o},n.lastModified=o,await this.pushCredentialsFile(n),console.log(`[Mnemonic Vault] Stored ${e} credentials`)}async getCredential(e){if(!this.cachedKey)throw new Error("Vault is locked");const t=await this.fetchCredentialsFile();if(!t)return null;const n=t.credentials[e];if(!n)return null;try{const s=await mt(n.encryptedBlob,n.ivBase64,this.cachedKey);return JSON.parse(s)}catch(s){throw console.error(`[Mnemonic Vault] Failed to decrypt ${e} credentials:`,s),new Error(`Failed to decrypt ${e} credentials`)}}async removeCredential(e){if(!this.cachedKey)throw new Error("Vault is locked");const t=await this.fetchCredentialsFile();t&&(delete t.credentials[e],t.lastModified=new Date().toISOString(),await this.pushCredentialsFile(t),console.log(`[Mnemonic Vault] Removed ${e} credentials`))}async hasEncryptedCredentials(){if(!this.credentialsSync)return!1;try{return await this.credentialsSync.hasRemoteCredentials()}catch{return!1}}async changeMasterPassword(e,t){var k;if(!t||t.length<8)throw new Error("New password must be at least 8 characters");const n=await this.fetchCredentialsFile();if(!n)throw new Error("No credentials file found");const s=We(n.encryption.saltBase64),a=await Ze(e,s,n.encryption.iterations);if(!await Xt(a,n.encryption.testCiphertext,n.encryption.testIV,Xe))throw new Error("Current password is incorrect");const i={};for(const E of["claude","todoist","logseq"]){const y=n.credentials[E];if(y){const _=await mt(y.encryptedBlob,y.ivBase64,a);i[E]=JSON.parse(_)}}const l=Zt(),d=await Ze(t,l,$e),u=await Te(Xe,d),m=new Date().toISOString(),h={version:1,encryption:{method:"AES-256-GCM",keyDerivation:"PBKDF2-SHA256",iterations:$e,saltBase64:Pe(l),testCiphertext:u.ciphertext,testIV:u.iv},credentials:{},integrationStates:n.integrationStates,lastModified:m};for(const[E,y]of Object.entries(i)){const _=await Te(JSON.stringify(y),d);h.credentials[E]={encryptedBlob:_.ciphertext,ivBase64:_.iv,createdAt:((k=n.credentials[E])==null?void 0:k.createdAt)||m,updatedAt:m}}await this.cacheDeviceKey(d,l),await this.pushCredentialsFile(h),console.log("[Mnemonic Vault] Master password changed successfully")}async updateIntegrationState(e,t){const n=await this.fetchCredentialsFile();if(!n)return;const s=n.integrationStates[e]||{enabled:!1};n.integrationStates[e]={...s,...t,configuredAt:s.configuredAt||new Date().toISOString()},n.lastModified=new Date().toISOString(),await this.pushCredentialsFile(n)}async cacheDeviceKey(e,t){this.cachedKey=e,this.cachedSalt=t;const n=await tr(e);await g.storage.local.set({[Re]:n,[je]:Pe(t),[Qt]:new Date().toISOString()})}async fetchCredentialsFile(){if(!this.credentialsSync)throw new Error("Credentials sync not configured");return this.credentialsSync.fetchEncrypted()}async pushCredentialsFile(e){if(!this.credentialsSync)throw new Error("Credentials sync not configured");await this.credentialsSync.pushEncrypted(e)}async migrateExistingCredentials(e,t){var s,a,o;const n=new Date().toISOString();try{const i=await g.storage.local.get("claudeSettings");if((s=i.claudeSettings)!=null&&s.apiKey){const l={apiKey:i.claudeSettings.apiKey,model:i.claudeSettings.model,autoSuggest:i.claudeSettings.autoSuggest},d=await Te(JSON.stringify(l),e);t.credentials.claude={encryptedBlob:d.ciphertext,ivBase64:d.iv,createdAt:n,updatedAt:n},t.integrationStates.claude={enabled:i.claudeSettings.enabled||!1,configuredAt:n},await g.storage.local.remove("claudeSettings"),console.log("[Mnemonic Vault] Migrated Claude credentials")}}catch(i){console.warn("[Mnemonic Vault] Failed to migrate Claude credentials:",i)}try{const i=await g.storage.local.get("todoistSettings");if((a=i.todoistSettings)!=null&&a.accessToken){const l={authMethod:i.todoistSettings.authMethod||"api_token",accessToken:i.todoistSettings.accessToken,masterProjectId:i.todoistSettings.masterProjectId},d=await Te(JSON.stringify(l),e);t.credentials.todoist={encryptedBlob:d.ciphertext,ivBase64:d.iv,createdAt:n,updatedAt:n},t.integrationStates.todoist={enabled:i.todoistSettings.enabled||!1,configuredAt:n},await g.storage.local.remove("todoistSettings"),console.log("[Mnemonic Vault] Migrated Todoist credentials")}}catch(i){console.warn("[Mnemonic Vault] Failed to migrate Todoist credentials:",i)}try{const i=await g.storage.local.get("logseqSettings");if((o=i.logseqSettings)!=null&&o.authToken){const l={apiUrl:i.logseqSettings.apiUrl,authToken:i.logseqSettings.authToken,autoSync:i.logseqSettings.autoSync,syncInterval:i.logseqSettings.syncInterval},d=await Te(JSON.stringify(l),e);t.credentials.logseq={encryptedBlob:d.ciphertext,ivBase64:d.iv,createdAt:n,updatedAt:n},t.integrationStates.logseq={enabled:i.logseqSettings.enabled||!1,configuredAt:n,settings:{apiUrl:i.logseqSettings.apiUrl}};const u={...i.logseqSettings};delete u.authToken,await g.storage.local.set({logseqSettings:u}),console.log("[Mnemonic Vault] Migrated Logseq credentials")}}catch(i){console.warn("[Mnemonic Vault] Failed to migrate Logseq credentials:",i)}}}let en=null;function Pa(){return en||(en=new rr),en}const he=Object.freeze(Object.defineProperty({__proto__:null,CredentialVault:rr,DEFAULT_ITERATIONS:$e,DEVICE_KEY_STORAGE_KEY:Re,KEY_CREATED_STORAGE_KEY:Qt,KEY_SALT_STORAGE_KEY:je,KEY_VERIFICATION_PLAINTEXT:Xe,decrypt:mt,deriveKey:Ze,encrypt:Te,exportKey:tr,fromBase64:We,generateIV:er,generateSalt:Zt,getCredentialVault:Pa,importKey:nr,toBase64:Pe,verifyKey:Xt},Symbol.toStringTag,{value:"Module"}));return Ca}();
153  background;