brep-io-kernel 1.0.114 → 1.0.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{browserTests-CNW_Q1Eq.js → browserTests-Ba-j4QtC.js} +1 -1
- package/dist/assets/main-BIULpEDy.js +139 -0
- package/dist/assets/{main-cad-BbbLaaDU.js → main-cad-UslVOqSO.js} +24 -24
- package/dist/cad.html +1 -1
- package/dist/index.html +1 -1
- package/dist/viewer.html +1 -1
- package/package.json +1 -1
- package/src/main-cad.js +21 -0
- package/src/main.js +50 -0
- package/dist/assets/main-IixyJmnb.js +0 -138
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var S0=Object.defineProperty;var i=(e,t)=>S0(e,"name",{value:t,configurable:!0});import{g as Ie,V as Oe,F as Re}from"./main-cad-
|
|
1
|
+
var S0=Object.defineProperty;var i=(e,t)=>S0(e,"name",{value:t,configurable:!0});import{g as Ie,V as Oe,F as Re}from"./main-cad-UslVOqSO.js";import{q as b}from"./WorkspaceFileBrowserWidget-BmFd0-0D.js";import{P as r0}from"./PartHistory-DrlQKMRY.js";import{computeFilletCenterline as b0}from"./fillet-DYiRsY2u.js";import{aL as P0,as as E0,a3 as Be}from"./featureDialogs-9yw6QAxS.js";import{e as F0,O as A0,C as n0,f as Le,h as Ne,g as je,E as a0,B as N0,_ as ue,i as k0,j as M0,k as T0,l as ze}from"./FeatureRegistry-DeBqycXh.js";import"./annUtils-BEJ5epFt.js";import"./preload-helper-ZNr0Qq7Q.js";import"./deepClone-Dj59xCHB.js";import"./brep-home-banner-Dg39_YS1.js";import"./AnnotationRegistry-DwCye4nq.js";import"./AssemblyConstraintRegistry-Dt_6gkJB.js";import"./chamfer-DUQ4wPBK.js";const C=typeof process<"u"&&process.versions&&process.versions.node&&typeof window>"u";function $(){if(!C)return E;if(typeof require=="function"){const e=require("node:path");return(e.default??e).posix}if(typeof module<"u"&&module&&typeof module.createRequire=="function"){const t=module.createRequire(typeof __filename<"u"?__filename:process.cwd())("node:path");return(t.default??t).posix}return E}i($,"getNodePosixSync");const s0="/",C0=":";function U(e){if(typeof e!="string")throw new TypeError("Path must be a string")}i(U,"_assertString");function fe(e){return e.startsWith(s0)}i(fe,"_isAbsolute");function i0(e,t){const o=e.split("/"),n=[];for(let r=0;r<o.length;r++){const a=o[r];!a||a==="."||(a===".."?n.length&&n[n.length-1]!==".."?n.pop():t&&n.push(".."):n.push(a))}return n.join("/")}i(i0,"_normalizeString");function l0(e){if(U(e),e==="")return".";const t=fe(e),o=e.endsWith("/");let n=i0(e,!t);return n===""&&!t&&(n="."),n!==""&&o&&(n+="/"),(t?"/":"")+n}i(l0,"_normalize");function D0(...e){let t="";for(let o=0;o<e.length;o++){const n=e[o];U(n),n!==""&&(t===""?t=n:t+="/"+n)}return l0(t)}i(D0,"_join");function _e(...e){let t="",o=!1;for(let r=e.length-1;r>=0;r--){const a=e[r];if(a!==void 0&&(U(a),a!==""&&(t=a+"/"+t,a.startsWith("/")))){o=!0;break}}o||(t="/"+t,o=!0);const n=i0(t,!1);return(o?"/":"")+n||(o?"/":".")}i(_e,"_resolve");function $0(e,t){if(U(e),U(t),e===t||(e=_e(e),t=_e(t),e===t))return"";const o=e.slice(1).split("/").filter(Boolean),n=t.slice(1).split("/").filter(Boolean);let r=0;const a=Math.min(o.length,n.length);for(;r<a&&o[r]===n[r];r++);const s=o.slice(r).map(()=>".."),l=n.slice(r);return s.concat(l).join("/")||""}i($0,"_relative");function c0(e){if(U(e),e.length===0)return".";const t=fe(e),o=e.endsWith("/")?e.length-1:e.length;let n=-1;for(let r=o-1;r>=0;--r)if(e.charCodeAt(r)===47){n=r;break}return n===-1?t?"/":".":t&&n===0?"/":e.slice(0,n)}i(c0,"_dirname");function d0(e,t=""){if(U(e),t!==void 0&&typeof t!="string")throw new TypeError("ext must be a string");let o=e.length;if(o===0)return"";for(;o>0&&e.charCodeAt(o-1)===47;)o--;if(o===0)return"/";let n=0;for(let a=o-1;a>=0;--a)if(e.charCodeAt(a)===47){n=a+1;break}let r=e.slice(n,o);return t&&r.endsWith(t)&&t!==""&&t!==r&&(r=r.slice(0,r.length-t.length)),r}i(d0,"_basename");function u0(e){U(e);let t=-1,o=0,n=-1,r=0;for(let a=e.length-1;a>=0;--a){const s=e.charCodeAt(a);if(s===47){if(n!==-1){o=a+1;break}continue}n===-1&&(n=a+1),s===46?t===-1?t=a:r!==1&&(r=1):t!==-1&&(r=-1)}return t===-1||n===-1||r===0||t===o?"":e.slice(t,n)}i(u0,"_extname");function I0(e){U(e);const t=fe(e)?"/":"",o=c0(e),n=d0(e),r=u0(n),a=r?n.slice(0,n.length-r.length):n;return{root:t,dir:o,base:n,ext:r,name:a}}i(I0,"_parse");function O0(e){const t=e.dir||e.root||"",o=e.base||(e.name||"")+(e.ext||"");return t?t.endsWith("/")?t+o:t+"/"+o:o||"."}i(O0,"_format");function R0(e){return e}i(R0,"_toNamespacedPath");const E={sep:s0,delimiter:C0,normalize:l0,join:D0,resolve:_e,isAbsolute:fe,relative:$0,dirname:c0,basename:d0,extname:u0,parse:I0,format:O0,toNamespacedPath:R0,posix:null,win32:null};E.posix=E;const ie={get sep(){return C?$().sep:E.sep},get delimiter(){return C?$().delimiter:E.delimiter},normalize:i((...e)=>C?$().normalize(...e):E.normalize(...e),"normalize"),join:i((...e)=>C?$().join(...e):E.join(...e),"join"),resolve:i((...e)=>C?$().resolve(...e):E.resolve(...e),"resolve"),isAbsolute:i((...e)=>C?$().isAbsolute(...e):E.isAbsolute(...e),"isAbsolute"),relative:i((...e)=>C?$().relative(...e):E.relative(...e),"relative"),dirname:i((...e)=>C?$().dirname(...e):E.dirname(...e),"dirname"),basename:i((...e)=>C?$().basename(...e):E.basename(...e),"basename"),extname:i((...e)=>C?$().extname(...e):E.extname(...e),"extname"),parse:i((...e)=>C?$().parse(...e):E.parse(...e),"parse"),format:i((...e)=>C?$().format(...e):E.format(...e),"format"),toNamespacedPath:i((...e)=>C?$().toNamespacedPath(...e):E.toNamespacedPath(...e),"toNamespacedPath"),posix:null,win32:null};ie.posix=ie;const B0=new Proxy({},{get(){throw new Error("POSIX-only path module: use the named export `posix` with your VFS.")}});ie.win32=B0;const O=ie;async function L0(e){const t=await e.newFeature("P.CU");return t.inputParams.sizeX=5,t.inputParams.sizeY=10,t.inputParams.sizeZ=15,e}i(L0,"test_primitiveCube");async function j0(e){const t=await e.newFeature("P.CU");return t.inputParams.sizeX=2,t.inputParams.sizeY=3,t.inputParams.sizeZ=4,e}i(j0,"test_solidMetrics");async function z0(e){try{const t=(e.scene?.children||[]).filter(x=>x&&x.type==="SOLID");if(!t.length){console.warn("[solidMetrics] No solids in scene.");return}const o=t[0],n=2,r=3,a=4,s=n*r*a,l=2*(n*r+r*a+a*n),d=typeof o.volume=="function"?o.volume():NaN,u=typeof o.surfaceArea=="function"?o.surfaceArea():NaN,p=i((x,y,A=1e-6)=>Math.abs(x-y)<=A*Math.max(1,Math.abs(y)),"approx"),c=i(x=>Number.isFinite(x)?x.toFixed(6):String(x),"fmt");console.log(`[solidMetrics] Solid volume: ${c(d)} (expected ${c(s)}) ${p(d,s)?"OK":"MISMATCH"}`),console.log(`[solidMetrics] Solid surface area: ${c(u)} (expected ${c(l)}) ${p(u,l)?"OK":"MISMATCH"}`);const f=o.children.filter(x=>x?.type==="FACE"),m=new Map([["_NX",r*a],["_PX",r*a],["_NY",n*a],["_PY",n*a],["_NZ",n*r],["_PZ",n*r]]);for(const x of f){const y=String(x?.name||""),A=Array.from(m.keys()).find(M=>y.endsWith(M));if(!A)continue;const P=typeof x.surfaceArea=="function"?x.surfaceArea():NaN,N=m.get(A);console.log(`[solidMetrics] Face ${y} area: ${c(P)} (expected ${c(N)}) ${p(P,N)?"OK":"MISMATCH"}`)}const v=o.children.filter(x=>x?.type==="EDGE").map(x=>typeof x.length=="function"?x.length():NaN),g=Array.from(new Set(v.map(x=>Number.isFinite(x)?x.toFixed(6):String(x))));console.log(`[solidMetrics] Distinct edge lengths: ${g.join(", ")} (expected ${[n,r,a].map(x=>x.toFixed(6)).join(", ")})`)}catch(t){console.warn("[solidMetrics] afterRun error:",t?.message||t)}}i(z0,"afterRun_solidMetrics");async function U0(e){const t=await e.newFeature("P.CY");return t.inputParams.radius=1,t.inputParams.height=5,t.inputParams.resolution=30,e}i(U0,"test_primitiveCylinder");async function Y0(e){return await e.newFeature("PLANE"),e}i(Y0,"test_plane");async function J0(e){const t=await e.newFeature("P.CO");return t.inputParams.radiusTop=3,t.inputParams.radiusBottom=.5,t.inputParams.height=5.2,t.inputParams.resolution=20,e}i(J0,"test_primitiveCone");async function W0(e){const t=await e.newFeature("P.T");t.inputParams.majorRadius=20,t.inputParams.tubeRadius=5,t.inputParams.resolution=10,t.inputParams.arc=300;const o=await e.newFeature("P.T");return o.inputParams.majorRadius=5,o.inputParams.tubeRadius=3,o.inputParams.resolution=30,o.inputParams.arc=360,e}i(W0,"test_primitiveTorus");async function X0(e){const t=await e.newFeature("P.CO");t.inputParams.radiusTop=3,t.inputParams.radiusBottom=.5,t.inputParams.height=5.2,t.inputParams.resolution=20;const o=await e.newFeature("P.CU");o.inputParams.sizeX=2,o.inputParams.sizeY=2,o.inputParams.sizeZ=20;const n=await e.newFeature("B");return n.inputParams.targetSolid=o.inputParams.featureID,n.inputParams.boolean={targets:[t.inputParams.featureID],operation:"SUBTRACT"},e}i(X0,"test_boolean_subtract");async function G0(e){const t=await e.newFeature("P.S");return t.inputParams.radius=5,t.inputParams.resolution=10,e}i(G0,"test_primitiveSphere");async function Z0(e){const t=await e.newFeature("P.PY");return t.inputParams.baseSideLength=5,t.inputParams.height=8,t.inputParams.sides=4,e}i(Z0,"test_primitivePyramid");async function q0(e){const t=await e.newFeature("IMPORT3D");return t.inputParams.fileToImport=K0,t.inputParams.deflectionAngle=15,e}i(q0,"test_stlLoader");const K0=`
|
|
2
2
|
solid Test_Cube
|
|
3
3
|
facet normal -4.258667930292975e-15 -9.729514454520843e-16 -1.0
|
|
4
4
|
outer loop
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
var Ut=Object.defineProperty;var l=(e,r)=>Ut(e,"name",{value:r,configurable:!0});import"./modulepreload-polyfill-BdX5DvLD.js";import{l as qt,S as zt,g as oe,i as at,p as Gt,a as dt,b as qe,c as ze,W as pt,r as pe,d as Re,e as V,s as fe,f as Vt,u as jt,h as it,j as Xt,k as Yt,w as Jt,m as Be}from"./WorkspaceFileBrowserWidget-BmFd0-0D.js";import{b as Zt,r as Qt}from"./brep-home-banner-Dg39_YS1.js";import"./preload-helper-ZNr0Qq7Q.js";const _e=".3mf",Ve="__BREP_WORKSPACE_MANUAL_REPOS__",ft="__BREP_UI_RECENT_EXPANDED__",ht="__BREP_UI_EXPLORER_VIEW_MODE__",er="__BREP_UI_EXPLORER_ICON_SIZE__",mt="__BREP_UI_EXPLORER_LOCATION__",gt="__BREP_HOME_SNAPSHOT__",bt="__BREP_HOME_INVERT_THEME__",tr=600*1e3,rr=72,or=192,yt=132,Ee="__BREP_TRASH__",nr="__BREP_TRASH_ROOT__",ar="https://api.github.com",ir="invert(1)",Ge=new Map,Te=new Map,t={root:document.getElementById("app"),records:[],allRecords:[],folderRecords:[],searchTerm:"",thumbCache:new Map,repoCache:[],manualRepoFulls:[],selectedRepoFulls:[],primaryRepoFull:"",mountedDirectories:[],explorerWorkspaceTop:!0,explorerRootSource:"local",explorerRootRepoFull:"",explorerPath:"",explorerViewMode:"list",explorerIconSize:yt,explorerSizePopoverOpen:!1,explorerSizePopoverClose:null,recentExpanded:!0,selectedEntryKeys:new Set,entryByKey:new Map,visibleExplorerEntryKeys:[],dragEntryKeys:[],filesListEl:null,filesStatusEl:null,storageBadgeEl:null,workspaceFoldersEl:null,workspaceFoldersMetaEl:null,workspaceModalEl:null,workspaceStatusEl:null,settingsPanelEl:null,settingsStatusEl:null,repoPickerEl:null,repoSummaryEl:null,mountPickerEl:null,mountSummaryEl:null,activeFileMenuClose:null,explorerWidget:null,loadingFiles:!1,pendingFilesReload:!1,workspaceReposLoading:!1,uiBusyDepth:0,busyMessage:"",busyDetail:"",busyOverlayEl:null,busyMessageEl:null,busyDetailEl:null,homeInvertTheme:!1};if(!t.root)throw new Error("Missing #app mount element");function D(){return Number(t.uiBusyDepth||0)>0}l(D,"isUiBusy");function Ie(){const e=D();if(t.root&&t.root.classList.toggle("hub-ui-busy",e),!!t.busyOverlayEl){if(t.busyOverlayEl.hidden=!e,t.busyOverlayEl.setAttribute("aria-hidden",e?"false":"true"),t.busyOverlayEl.setAttribute("aria-busy",e?"true":"false"),t.busyMessageEl&&(t.busyMessageEl.textContent=t.busyMessage||"Working..."),t.busyDetailEl){const r=String(t.busyDetail||"").trim();t.busyDetailEl.hidden=!r,t.busyDetailEl.textContent=r}e&&typeof t.busyOverlayEl.focus=="function"&&(t.busyOverlayEl.contains(document.activeElement)||t.busyOverlayEl.focus({preventScroll:!0}))}}l(Ie,"syncBusyOverlay");function sr(e="Working...",r=""){t.uiBusyDepth=Number(t.uiBusyDepth||0)+1,t.busyMessage=String(e||"Working..."),t.busyDetail=String(r||""),rt(),Ie()}l(sr,"beginBusyUi");function je(e,r=""){D()&&(typeof e=="string"&&e.trim()&&(t.busyMessage=e.trim()),t.busyDetail=String(r||""),Ie())}l(je,"setBusyUiProgress");function lr(){t.uiBusyDepth>0&&(t.uiBusyDepth-=1),t.uiBusyDepth||(t.busyMessage="",t.busyDetail=""),Ie()}l(lr,"endBusyUi");async function se(e,r,o={}){sr(e,o?.detail||"");try{return typeof r!="function"?void 0:await r({setMessage(n,a=""){je(n||e,a)}})}finally{lr()}}l(se,"runBusyUiTask");async function U({timeoutMs:e=12e4}={}){const r=Date.now();for(;(t.loadingFiles||t.pendingFilesReload)&&!(Date.now()-r>e);)await new Promise(o=>window.setTimeout(o,40))}l(U,"waitForFilesIdle");cr();async function cr(){try{await qt.ready()}catch{}br(),wt(t.homeInvertTheme),window.addEventListener(zt,()=>{Fe(),B()}),await Er()}l(cr,"boot");function wt(e){document?.documentElement&&(e?document.documentElement.style.filter=ir:document.documentElement.style.removeProperty("filter"))}l(wt,"applyHomeThemeFilter");function St(e){if(!e)return;const r=!!t.homeInvertTheme;e.textContent=r?"🌙":"🔆",e.setAttribute("aria-pressed",r?"true":"false"),e.setAttribute("aria-label",r?"Switch to dark mode":"Switch to light mode"),e.title=r?"Switch to dark mode":"Switch to light mode"}l(St,"syncHomeThemeToggleButton");function ur(e,{persist:r=!0,toggleButton:o=null}={}){t.homeInvertTheme=!!e,wt(t.homeInvertTheme),St(o),r&&$e(bt,t.homeInvertTheme?"1":"0")}l(ur,"setHomeThemeInverted");function dr(e={}){const r=new URL("cad.html",window.location.href),o=F(e?.source),n=E(e?.path||"");if(n)if(o==="github"){const i=Ye(e?.repoFull||""),s=Xe(n),c=i?`github/${i}/${s}`:`github/${s}`;r.searchParams.set("path",c)}else if(o==="mounted"){const i=Ye(e?.repoFull||e?.mountId||""),s=Xe(n),c=i?`mounted/${i}/${s}`:`mounted/${s}`;r.searchParams.set("path",c)}else r.searchParams.set("path",n);const a=e?.branch;return a&&r.searchParams.set("branch",String(a)),r.toString()}l(dr,"buildCadUrl");function We(e={}){window.location.href=dr(e)}l(We,"goCad");function Q(e){const r=Array.isArray(e)?e:String(e||"").split(/[\n,;]/g),o=[],n=new Set;for(const a of r){const i=String(a||"").trim();!i||n.has(i)||(n.add(i),o.push(i))}return o}l(Q,"normalizeRepoFullList");function pr(){try{const e=String(Xt(Ve,{fallback:""})||"").trim();if(!e)return[];const r=JSON.parse(e);return Q(r)}catch{return[]}}l(pr,"loadManualWorkspaceRepos");function fr(e){const r=Q(e);try{if(!r.length){Yt(Ve);return}Jt(Ve,JSON.stringify(r))}catch{}}l(fr,"saveManualWorkspaceRepos");function vt(){try{if(typeof window<"u"&&window.localStorage)return window.localStorage}catch{}return null}l(vt,"getBrowserLocalStorage");function ve(e,r=""){const o=vt();if(!o)return r;try{const n=o.getItem(String(e||""));return n==null?r:String(n)}catch{return r}}l(ve,"loadUiPreference");function $e(e,r){const o=vt();if(o)try{o.setItem(String(e||""),String(r??""))}catch{}}l($e,"saveUiPreference");function Et(e){if(!e||typeof e!="object")return null;const r=F(e?.source),o=String(e?.name||"").trim(),n=E(e?.path||o),a=E(e?.browserPath||n||o);return!o&&!n&&!a?null:{source:r,name:o||n||a,path:n||o||a,browserPath:a||n||o,folder:String(e?.folder||"").trim(),displayName:String(e?.displayName||"").trim(),repoFull:String(e?.repoFull||"").trim(),branch:String(e?.branch||"").trim(),savedAt:e?.savedAt||null,has3mf:!!e?.has3mf,record:{savedAt:e?.record?.savedAt||e?.savedAt||null,thumbnailPath:String(e?.record?.thumbnailPath||"").trim()||null}}}l(Et,"createHomeSnapshotRecord");function Ft(e){if(!e||typeof e!="object")return null;const r=F(e?.source),o=E(e?.path||"");return o?{source:r,repoFull:String(e?.repoFull||"").trim(),path:o,savedAt:e?.savedAt||null}:null}l(Ft,"createHomeSnapshotFolder");function hr(){const e={version:1,savedAt:Date.now(),records:t.allRecords.map(r=>Et(r)).filter(Boolean),folders:t.folderRecords.map(r=>Ft(r)).filter(Boolean)};$e(gt,JSON.stringify(e))}l(hr,"saveHomeSnapshot");function mr(){const e=String(ve(gt,"")||"").trim();if(!e)return null;try{const r=JSON.parse(e);if(!r||typeof r!="object")return null;const o=Number(r?.savedAt||0);if(!Number.isFinite(o)||o<=0||Date.now()-o>tr)return null;const n=Array.isArray(r?.records)?r.records:[],a=Array.isArray(r?.folders)?r.folders:[];return{records:n,folders:a}}catch{return null}}l(mr,"loadHomeSnapshot");function gr(){const e=mr();if(!e)return!1;const r=Array.isArray(e.records)?e.records:[],o=Array.isArray(e.folders)?e.folders:[];if(!r.length&&!o.length)return!1;const n=new Map;for(const i of r){const s=Et(i);if(!s)continue;const c=`${s.source}:${s.repoFull}:${s.name}`;n.has(c)||n.set(c,s)}const a=new Map;for(const i of o){const s=Ft(i);if(!s)continue;const c=`${s.source}:${s.repoFull}:${s.path}`;a.has(c)||a.set(c,s)}return t.allRecords=Array.from(n.values()),t.allRecords.sort((i,s)=>{const c=Date.parse(i?.savedAt||"")||0;return(Date.parse(s?.savedAt||"")||0)-c}),t.folderRecords=Array.from(a.values()),t.records=t.allRecords.slice(0,10),Qe(),!0}l(gr,"hydrateHomeSnapshotIntoState");function br(){const e=ve(bt,"").trim().toLowerCase();e==="1"||e==="true"?t.homeInvertTheme=!0:(e==="0"||e==="false")&&(t.homeInvertTheme=!1);const r=ve(ft,"");r==="0"||r==="false"?t.recentExpanded=!1:(r==="1"||r==="true")&&(t.recentExpanded=!0);const o=ve(ht,"").trim().toLowerCase();(o==="icons"||o==="list")&&(t.explorerViewMode=o);const n=ve(er,"");n&&(t.explorerIconSize=Sr(n)),yr()}l(br,"loadUiPreferences");function yr(){const e=String(ve(mt,"")||"").trim();if(e)try{const r=JSON.parse(e);if(!r||typeof r!="object")return;(r.workspaceTop===!0||r.workspaceTop===!1)&&(t.explorerWorkspaceTop=r.workspaceTop),t.explorerRootSource=F(r.rootSource||r.source||t.explorerRootSource),t.explorerRootRepoFull=String(r.rootRepoFull||r.repoFull||t.explorerRootRepoFull||"").trim(),t.explorerPath=E(r.path||t.explorerPath||""),t.explorerWorkspaceTop&&(t.explorerPath="")}catch{}}l(yr,"loadExplorerLocationPreference");function ge(){const e={workspaceTop:!!t.explorerWorkspaceTop,rootSource:F(t.explorerRootSource),rootRepoFull:String(t.explorerRootRepoFull||"").trim(),path:E(t.explorerPath||"")};e.workspaceTop&&(e.path=""),$e(mt,JSON.stringify(e))}l(ge,"saveExplorerLocationPreference");function F(e){const r=String(e||"").trim().toLowerCase();return r==="mounted"?"mounted":r==="github"?"github":"local"}l(F,"normalizeStorageSource");function wr(e=""){const r=String(e||"").trim();if(!r)return"";for(const o of Array.isArray(t.mountedDirectories)?t.mountedDirectories:[]){if(String(o?.id||"").trim()!==r)continue;const n=String(o?.name||"").trim();if(n)return n}return r}l(wr,"getMountedDirectoryName");function me(e,r=""){const o=F(e),n=String(r||"").trim();return o==="local"?"Local Browser":o==="mounted"?wr(n)||"Mounted Folder":n||"GitHub"}l(me,"getStorageRootLabel");function E(e){const r=String(e||"").replace(/\\/g,"/"),o=[];for(const n of r.split("/")){const a=String(n||"").trim();!a||a==="."||a===".."||o.push(a)}return o.join("/")}l(E,"normalizePath");function X(e){const r=E(e||"");return r?r===Ee||r.startsWith(`${Ee}/`):!1}l(X,"isTrashPath");function ke(e,r=""){return F(e)==="local"&&String(r||"").trim()===nr}l(ke,"isTrashRoot");function Sr(e){const r=Number(e);return Number.isFinite(r)?Math.max(rr,Math.min(or,Math.round(r))):yt}l(Sr,"clampExplorerIconSize");function st(e,r=""){const o=F(e),n=String(r||"").trim();return`${o}:${n}`}l(st,"makeRootKey");function De(){const e=oe(),r=Q(t.selectedRepoFulls?.length?t.selectedRepoFulls:e?.repoFulls||e?.repoFull||""),o=new Set,n=[],a=l(d=>{const p=String(d||"").trim();!p||o.has(p)||(o.add(p),n.push(p))},"addRepo");for(const d of r)a(d);for(const d of t.allRecords)F(d?.source)==="github"&&a(String(d?.repoFull||"").trim());n.sort((d,p)=>d.localeCompare(p));const i=new Map,s=l((d,p="")=>{const m=String(d||"").trim();if(!m)return;const b=i.get(m);if(b){!b.name&&p&&(b.name=String(p||"").trim());return}i.set(m,{id:m,name:String(p||"").trim()})},"addMounted");for(const d of Array.isArray(t.mountedDirectories)?t.mountedDirectories:[])s(d?.id,d?.name);for(const d of t.allRecords)F(d?.source)==="mounted"&&s(d?.repoFull,d?.repoLabel);for(const d of t.folderRecords)F(d?.source)==="mounted"&&s(d?.repoFull,d?.repoLabel);const c=Array.from(i.values()).sort((d,p)=>{const m=me("mounted",d.id),b=me("mounted",p.id);return m.localeCompare(b,void 0,{numeric:!0,sensitivity:"base"})}).map(d=>({source:"mounted",repoFull:d.id,label:me("mounted",d.id),isPrimary:!1})),u=String(t.primaryRepoFull||e?.repoFull||"").trim(),y=[{source:"local",repoFull:"",label:"Local Browser",isPrimary:!1}];y.push(...c);for(const d of n)y.push({source:"github",repoFull:d,label:d,isPrimary:!!u&&d===u});return y}l(De,"makeWorkspaceRoots");function vr(){t.explorerWorkspaceTop=!0,t.explorerPath="",ge(),ue()}l(vr,"setExplorerWorkspaceTop");function kt(e,r=""){t.explorerWorkspaceTop=!1,t.explorerRootSource=F(e),t.explorerRootRepoFull=String(r||"").trim(),t.explorerPath="",ge(),ue()}l(kt,"setExplorerRoot");function Rt(e){t.explorerPath=E(e),ge(),ue()}l(Rt,"setExplorerPath");async function Er(){t.root.innerHTML=`
|
|
2
|
+
<div class="hub-page">
|
|
3
|
+
<div class="hub-bg hub-bg-one"></div>
|
|
4
|
+
<div class="hub-bg hub-bg-two"></div>
|
|
5
|
+
<header class="hub-header">
|
|
6
|
+
<div class="hub-brand-wrap">
|
|
7
|
+
<div class="hub-brand-banner" aria-label="BREP.io logo">${Zt}</div>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="hub-header-actions">
|
|
10
|
+
<a class="hub-link-btn" href="./help/developer-index.html" target="_blank" rel="noreferrer">Docs</a>
|
|
11
|
+
<button type="button" class="hub-ghost-btn" data-action="toggle-theme" aria-pressed="false" aria-label="Switch to light mode" title="Switch to light mode">🔆</button>
|
|
12
|
+
<button type="button" class="hub-icon-btn" data-action="toggle-settings" title="Settings" aria-label="Settings">⚙</button>
|
|
13
|
+
<button type="button" class="hub-primary-btn" data-action="new">New Model</button>
|
|
14
|
+
</div>
|
|
15
|
+
</header>
|
|
16
|
+
|
|
17
|
+
<main class="hub-main">
|
|
18
|
+
<section class="hub-panel hub-files-panel">
|
|
19
|
+
<div class="hub-panel-head">
|
|
20
|
+
<h2 class="hub-panel-title">Your Files</h2>
|
|
21
|
+
<div class="hub-storage-badge" data-role="storage-badge">Storage: Local</div>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="hub-files-toolbar">
|
|
25
|
+
<input type="search" class="hub-input hub-search" placeholder="Search files... (repo:, source:, ext:, folder:)" data-role="search" />
|
|
26
|
+
<button type="button" class="hub-ghost-btn" data-action="refresh">Refresh</button>
|
|
27
|
+
<button type="button" class="hub-ghost-btn" data-action="toggle-workspace">Workspace</button>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="hub-status" data-role="files-status" hidden></div>
|
|
31
|
+
<div class="hub-files-list" data-role="files-list"></div>
|
|
32
|
+
</section>
|
|
33
|
+
</main>
|
|
34
|
+
|
|
35
|
+
<div class="hub-modal-overlay" data-role="workspace-modal" hidden>
|
|
36
|
+
<section class="hub-panel hub-modal-panel hub-workspace-panel">
|
|
37
|
+
<div class="hub-panel-head">
|
|
38
|
+
<h2 class="hub-panel-title">Workspace</h2>
|
|
39
|
+
<button type="button" class="hub-ghost-btn" data-action="close-workspace">Close</button>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="hub-settings-grid">
|
|
42
|
+
<div class="hub-field hub-field-inline">
|
|
43
|
+
<span class="hub-field-label">Add Repository</span>
|
|
44
|
+
<div class="hub-row-inline">
|
|
45
|
+
<input type="text" class="hub-input" data-role="workspace-repo" list="brep-repo-options" placeholder="owner/repo" />
|
|
46
|
+
<button type="button" class="hub-ghost-btn" data-action="add-repo">Add Repo</button>
|
|
47
|
+
<button type="button" class="hub-ghost-btn" data-action="repos">Load Repos</button>
|
|
48
|
+
</div>
|
|
49
|
+
<datalist id="brep-repo-options"></datalist>
|
|
50
|
+
<div class="hub-repo-picker" data-role="repo-picker"></div>
|
|
51
|
+
<div class="hub-repo-summary" data-role="repo-summary"></div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="hub-field hub-field-inline">
|
|
54
|
+
<span class="hub-field-label">Mounted Folders</span>
|
|
55
|
+
<div class="hub-row-inline">
|
|
56
|
+
<button type="button" class="hub-ghost-btn" data-action="mount-folder">Mount Folder</button>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="hub-repo-picker" data-role="mount-picker"></div>
|
|
59
|
+
<div class="hub-repo-summary" data-role="mount-summary"></div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="hub-status" data-role="workspace-status" hidden></div>
|
|
63
|
+
</section>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<div class="hub-modal-overlay" data-role="settings-modal" hidden>
|
|
67
|
+
<section class="hub-panel hub-modal-panel hub-settings-panel">
|
|
68
|
+
<div class="hub-panel-head">
|
|
69
|
+
<h2 class="hub-panel-title">Settings</h2>
|
|
70
|
+
<button type="button" class="hub-ghost-btn" data-action="close-settings">Close</button>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="hub-settings-grid">
|
|
74
|
+
<label class="hub-field">
|
|
75
|
+
<span class="hub-field-label">GitHub Token</span>
|
|
76
|
+
<input type="password" class="hub-input" data-role="token" placeholder="ghp_..." autocomplete="off" />
|
|
77
|
+
</label>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<section class="hub-settings-instructions" aria-label="GitHub token setup instructions">
|
|
81
|
+
<p class="hub-help-text">Create a GitHub personal access token, then paste it above.</p>
|
|
82
|
+
<ol class="hub-help-list">
|
|
83
|
+
<li>Open GitHub token settings.</li>
|
|
84
|
+
<li>Create a token with repository <code>Contents</code> read/write access.</li>
|
|
85
|
+
<li>Copy the token value and click <strong>Save Token</strong>.</li>
|
|
86
|
+
</ol>
|
|
87
|
+
<div class="hub-help-links">
|
|
88
|
+
<a
|
|
89
|
+
class="hub-link-btn"
|
|
90
|
+
href="https://github.com/settings/personal-access-tokens/new"
|
|
91
|
+
target="_blank"
|
|
92
|
+
rel="noopener noreferrer"
|
|
93
|
+
>
|
|
94
|
+
Open Fine-grained Token Setup
|
|
95
|
+
</a>
|
|
96
|
+
<a
|
|
97
|
+
class="hub-link-btn"
|
|
98
|
+
href="https://github.com/settings/tokens/new"
|
|
99
|
+
target="_blank"
|
|
100
|
+
rel="noopener noreferrer"
|
|
101
|
+
>
|
|
102
|
+
Open Classic Token Setup
|
|
103
|
+
</a>
|
|
104
|
+
</div>
|
|
105
|
+
</section>
|
|
106
|
+
|
|
107
|
+
<div class="hub-actions-row">
|
|
108
|
+
<button type="button" class="hub-primary-btn" data-action="save-settings">Save Token</button>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="hub-status" data-role="settings-status" hidden></div>
|
|
112
|
+
<p class="hub-help">Token needs repository Contents read/write permission.</p>
|
|
113
|
+
</section>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<div
|
|
117
|
+
class="hub-busy-overlay"
|
|
118
|
+
data-role="busy-overlay"
|
|
119
|
+
hidden
|
|
120
|
+
aria-hidden="true"
|
|
121
|
+
aria-busy="false"
|
|
122
|
+
aria-live="polite"
|
|
123
|
+
tabindex="-1"
|
|
124
|
+
>
|
|
125
|
+
<div class="hub-busy-panel" role="status" aria-live="polite">
|
|
126
|
+
<span class="hub-busy-spinner" aria-hidden="true"></span>
|
|
127
|
+
<div class="hub-busy-copy">
|
|
128
|
+
<h3 class="hub-busy-title" data-role="busy-message">Working...</h3>
|
|
129
|
+
<p class="hub-busy-detail" data-role="busy-detail" hidden></p>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
`,t.filesListEl=t.root.querySelector('[data-role="files-list"]'),t.filesStatusEl=t.root.querySelector('[data-role="files-status"]'),t.storageBadgeEl=t.root.querySelector('[data-role="storage-badge"]'),t.workspaceFoldersEl=t.root.querySelector('[data-role="workspace-folders"]'),t.workspaceFoldersMetaEl=t.root.querySelector('[data-role="workspace-folders-meta"]'),t.workspaceModalEl=t.root.querySelector('[data-role="workspace-modal"]'),t.workspaceStatusEl=t.root.querySelector('[data-role="workspace-status"]'),t.settingsPanelEl=t.root.querySelector('[data-role="settings-modal"]'),t.settingsStatusEl=t.root.querySelector('[data-role="settings-status"]'),t.mountPickerEl=t.root.querySelector('[data-role="mount-picker"]'),t.mountSummaryEl=t.root.querySelector('[data-role="mount-summary"]'),t.busyOverlayEl=t.root.querySelector('[data-role="busy-overlay"]'),t.busyMessageEl=t.root.querySelector('[data-role="busy-message"]'),t.busyDetailEl=t.root.querySelector('[data-role="busy-detail"]'),Ie();const e=t.root.querySelector('[data-role="search"]'),r=t.root.querySelector('[data-role="token"]'),o=t.root.querySelector('[data-role="workspace-repo"]'),n=t.root.querySelector("#brep-repo-options"),a=t.root.querySelector('[data-role="repo-picker"]'),i=t.root.querySelector('[data-role="repo-summary"]'),s=t.root.querySelector('[data-role="mount-picker"]'),c=t.root.querySelector('[data-role="mount-summary"]'),u=t.root.querySelector('[data-action="toggle-theme"]'),y=t.root.querySelector('[data-action="toggle-settings"]'),d=t.root.querySelector('[data-action="toggle-workspace"]'),p=t.root.querySelector('[data-action="add-repo"]'),m=t.root.querySelector('[data-action="mount-folder"]'),b=t.root.querySelector('[data-action="close-workspace"]'),f=t.root.querySelector('[data-action="close-settings"]');t.repoPickerEl=a,t.repoSummaryEl=i,t.root.querySelector('[data-action="new"]')?.addEventListener("click",()=>{D()||We()}),t.root.querySelector('[data-action="refresh"]')?.addEventListener("click",()=>{D()||B()}),St(u),u?.addEventListener("click",()=>{ur(!t.homeInvertTheme,{toggleButton:u})}),e&&(e.value=t.searchTerm),e?.addEventListener("input",()=>{D()||(t.searchTerm=String(e.value||"").trim(),ue())});const g=oe();t.manualRepoFulls=Q(pr()),t.selectedRepoFulls=Q(g?.repoFulls||g?.repoFull||""),t.primaryRepoFull=String(g?.repoFull||t.selectedRepoFulls[0]||"").trim(),r&&(r.value=g?.token||""),o&&(o.value="");const v=l(()=>t.repoCache.filter(h=>h&&h.full_name).sort((h,S)=>String(h.full_name||"").localeCompare(String(S.full_name||""))),"getSelectableRepos"),R=l(()=>{if(!n)return;n.innerHTML="";const h=Q([...t.manualRepoFulls,...t.selectedRepoFulls,...t.repoCache.map(S=>String(S?.full_name||"").trim())]);for(const S of h){const $=document.createElement("option");$.value=S,n.appendChild($)}},"refreshWorkspaceRepoOptions"),C=l(()=>{const h=new Map;for(const S of v()){const $=String(S?.full_name||"").trim();$&&h.set($,{repoFull:$,fetched:!0,manual:!1,readOnly:!!S?.permissions&&S.permissions.push===!1})}for(const S of t.manualRepoFulls){const $=h.get(S);$?$.manual=!0:h.set(S,{repoFull:S,fetched:!1,manual:!0,readOnly:!1})}for(const S of t.selectedRepoFulls)h.has(S)||h.set(S,{repoFull:S,fetched:!1,manual:!1,readOnly:!1});return Array.from(h.values()).sort((S,$)=>String(S.repoFull||"").localeCompare(String($.repoFull||"")))},"buildWorkspaceRepoCandidates"),P=l(h=>{const S=!!h;t.settingsPanelEl&&(t.settingsPanelEl.hidden=!S),y?.classList.toggle("is-active",S)},"setSettingsOpen");let k=0;const A=l(async({silent:h=!1}={})=>{const S=String(r?.value||"").trim()||String(oe()?.token||"").trim();if(!S){t.repoCache=[],R(),M(),h||K("Set a GitHub token from Settings first.","warn");return}t.workspaceReposLoading=!0,M();const $=++k;h||K("Loading repositories...","info");try{const T=await Vt(S);if($!==k)return;t.repoCache=Array.isArray(T)?T:[],R(),M(),h||K(`Loaded ${t.repoCache.length} repositories.`,"ok")}catch(T){if($!==k)return;h||K(`Repo load failed: ${H(T)}`,"error"),M()}finally{if($!==k)return;t.workspaceReposLoading=!1,M()}},"loadWorkspaceRepos"),x=l(h=>{const S=!!h;t.workspaceModalEl&&(t.workspaceModalEl.hidden=!S),d?.classList.toggle("is-active",S),S&&(A({silent:!1}),I({silent:!0}))},"setWorkspaceOpen");y?.addEventListener("click",()=>{if(D())return;const h=t.settingsPanelEl?.hidden!==!1;h&&x(!1),P(h)}),d?.addEventListener("click",()=>{if(D())return;const h=t.workspaceModalEl?.hidden!==!1;h&&P(!1),x(h)}),b?.addEventListener("click",()=>{D()||x(!1)}),f?.addEventListener("click",()=>{D()||P(!1)}),t.workspaceModalEl?.addEventListener("click",h=>{h.target===t.workspaceModalEl&&x(!1)}),t.settingsPanelEl?.addEventListener("click",h=>{h.target===t.settingsPanelEl&&P(!1)}),t.busyOverlayEl?.addEventListener("pointerdown",h=>{h.preventDefault(),h.stopPropagation()},!0),t.busyOverlayEl?.addEventListener("click",h=>{h.preventDefault(),h.stopPropagation()},!0),t.busyOverlayEl?.addEventListener("keydown",h=>{h.preventDefault(),h.stopPropagation()},!0),window.addEventListener("keydown",h=>{if(h.defaultPrevented)return;if(D()){h.preventDefault(),h.stopPropagation();return}const S=document.activeElement,$=qr(S),T=t.settingsPanelEl?.hidden===!1,O=t.workspaceModalEl?.hidden===!1;if(h.key==="Escape"){T&&P(!1),O&&x(!1),!T&&!O&&t.selectedEntryKeys.size&&(h.preventDefault(),we());return}if(!(T||O||$)){if((h.ctrlKey||h.metaKey)&&h.key.toLowerCase()==="a"){if(!t.visibleExplorerEntryKeys.length)return;h.preventDefault(),Ur(!0);return}if(h.key==="Delete"&&t.selectedEntryKeys.size){h.preventDefault(),Ht(Hr(),{confirm:!0});return}if(h.key==="Backspace"){if(h.preventDefault(),t.explorerWorkspaceTop)return;const J=E(t.explorerPath||"");if(J){const ie=J.lastIndexOf("/");Rt(ie>=0?J.slice(0,ie):"");return}vr()}}});const _=l(()=>{t.selectedRepoFulls=Q(t.selectedRepoFulls);let h=String(t.primaryRepoFull||"").trim();h&&!t.selectedRepoFulls.includes(h)&&(h=""),!h&&t.selectedRepoFulls.length&&(h=t.selectedRepoFulls[0]),h&&(t.selectedRepoFulls=Q([h,...t.selectedRepoFulls])),t.primaryRepoFull=h},"ensurePrimaryRepo"),j=l(h=>{const S=String(h||"").trim();return S?/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(S)?(t.manualRepoFulls=Q([S,...t.manualRepoFulls]),fr(t.manualRepoFulls),t.selectedRepoFulls.includes(S)?(t.primaryRepoFull||(t.primaryRepoFull=S),{ok:!0,changed:!1}):(t.selectedRepoFulls=Q([...t.selectedRepoFulls,S]),t.primaryRepoFull||(t.primaryRepoFull=S),{ok:!0,changed:!0})):{ok:!1,reason:"invalid"}:{ok:!1,reason:"empty"}},"addRepoToWorkspace"),M=l(()=>{if(!a||!i)return;a.innerHTML="",_();const h=String(t.primaryRepoFull||"").trim(),S=new Set(t.selectedRepoFulls),$=C().slice().sort((ie,q)=>{const le=String(ie?.repoFull||"").trim(),ee=String(q?.repoFull||"").trim(),te=S.has(le)?1:0,Z=S.has(ee)?1:0;return te!==Z?Z-te:le.localeCompare(ee)});if(!$.length){i.textContent=t.workspaceReposLoading?"Loading repositories...":"No repositories available yet. Add a repository or load your repo list.";return}for(const ie of $){const q=String(ie?.repoFull||"").trim();if(!q)continue;const le=S.has(q),ee=document.createElement("div");ee.className=`hub-repo-option${le?" is-included":""}`;const te=document.createElement("label");te.className="hub-repo-check";const Z=document.createElement("input");Z.type="checkbox",Z.checked=le,Z.addEventListener("change",()=>{Z.checked?(t.selectedRepoFulls=Q([...t.selectedRepoFulls,q]),t.primaryRepoFull||(t.primaryRepoFull=q)):(t.selectedRepoFulls=t.selectedRepoFulls.filter(re=>re!==q),String(t.primaryRepoFull||"").trim()===q&&(t.primaryRepoFull=t.selectedRepoFulls[0]||"")),_(),M(),W({pendingMessage:"Updating workspace repositories...",successMessage:"Workspace repositories updated."})}),te.appendChild(Z);const Pe=document.createElement("span");Pe.className="hub-repo-option-name",Pe.textContent=q,te.appendChild(Pe),ee.appendChild(te);const he=document.createElement("div");if(he.className="hub-repo-option-badges",le&&q===h){const re=document.createElement("span");re.className="hub-repo-badge is-primary",re.textContent="Primary",he.appendChild(re)}if(ie?.readOnly){const re=document.createElement("span");re.className="hub-repo-badge",re.textContent="Read Only",he.appendChild(re)}if(ie?.manual){const re=document.createElement("span");re.className="hub-repo-badge",re.textContent="Manual",he.appendChild(re)}ee.appendChild(he);const Se=document.createElement("button");Se.type="button",Se.className="hub-ghost-btn hub-repo-primary-btn",Se.textContent=q===h?"Primary":"Set Primary",Se.disabled=!le||q===h,Se.addEventListener("click",()=>{t.primaryRepoFull=q,_(),M(),W({pendingMessage:"Applying primary repository...",successMessage:"Primary repository updated."})}),ee.appendChild(Se),a.appendChild(ee)}const T=t.selectedRepoFulls.length,O=$.length,J=t.workspaceReposLoading?" Loading…":"";i.textContent=`Included: ${T} of ${O} repositories.${J}`},"renderWorkspaceRepos"),ne=l(()=>{if(!s||!c)return;s.innerHTML="";const h=at();if(m&&(m.disabled=!h),!h){c.textContent="System Access API is not available in this browser/context.";return}const S=(Array.isArray(t.mountedDirectories)?t.mountedDirectories:[]).slice().sort(($,T)=>String($?.name||$?.id||"").localeCompare(String(T?.name||T?.id||""),void 0,{numeric:!0,sensitivity:"base"}));if(!S.length){c.textContent="No mounted folders yet.";return}for(const $ of S){const T=String($?.id||"").trim();if(!T)continue;const O=String($?.name||T).trim()||T,J=document.createElement("div");J.className="hub-repo-option is-included";const ie=document.createElement("div");ie.className="hub-repo-check";const q=document.createElement("span");q.className="hub-repo-option-name",q.textContent=O,ie.appendChild(q),J.appendChild(ie);const le=document.createElement("div");le.className="hub-repo-option-badges";const ee=document.createElement("span");ee.className="hub-repo-badge",ee.textContent=T,ee.title=T,le.appendChild(ee),J.appendChild(le);const te=document.createElement("button");te.type="button",te.className="hub-ghost-btn hub-repo-primary-btn",te.textContent="Browse",te.addEventListener("click",()=>{kt("mounted",T),x(!1)}),J.appendChild(te);const Z=document.createElement("button");Z.type="button",Z.className="hub-ghost-btn hub-repo-primary-btn",Z.textContent="Unmount",Z.addEventListener("click",async()=>{if(await confirm(`Unmount "${O}"?`)){K(`Unmounting "${O}"...`,"info");try{await jt(T),await B(),ne(),K(`Unmounted "${O}".`,"ok")}catch(he){K(`Unmount failed: ${H(he)}`,"error")}}}),J.appendChild(Z),s.appendChild(J)}c.textContent=`Mounted: ${S.length} folder${S.length===1?"":"s"}.`},"renderMountedFolders"),I=l(async({silent:h=!0}={})=>{try{t.mountedDirectories=await dt(),ne(),h||K(t.mountedDirectories.length?`Loaded ${t.mountedDirectories.length} mounted folder${t.mountedDirectories.length===1?"":"s"}.`:"No mounted folders found.","info")}catch(S){ne(),h||K(`Failed to load mounted folders: ${H(S)}`,"error")}},"refreshMountedFolders");let N=0;const W=l(async({pendingMessage:h="Saving workspace repositories...",successMessage:S="Workspace repositories saved."}={})=>{_();const $=String(t.primaryRepoFull||"").trim();t.selectedRepoFulls=Q(t.selectedRepoFulls);const T=++N;K(h,"info");try{const O=await it({repoFull:$,repoFulls:t.selectedRepoFulls,mode:"local"});if(T!==N)return;O?K(S,"ok"):K("Workspace update returned no result.","warn"),M(),Fe(),await B()}catch(O){if(T!==N)return;K(`Workspace update failed: ${H(O)}`,"error")}},"applyWorkspaceRepos");let ae=0;const L=l(async({pendingMessage:h="Saving GitHub token...",successMessage:S="GitHub token saved."}={})=>{const $=String(r?.value||"").trim(),T=++ae;Le(h,"info");try{const O=await it({token:$,mode:"local"});if(T!==ae)return;O?Le(S,"ok"):Le("Token update returned no result.","warn"),$||(t.repoCache=[],R()),Fe(),await B(),t.workspaceModalEl?.hidden===!1&&await A({silent:!0})}catch(O){if(T!==ae)return;Le(`Token update failed: ${H(O)}`,"error")}},"applyTokenSettings");t.root.querySelector('[data-action="repos"]')?.addEventListener("click",async()=>{await A({silent:!1})}),m?.addEventListener("click",async()=>{if(!D()){if(!at()){K("System Access API is not available in this browser/context.","warn");return}K("Choose a local folder to mount...","info");try{await Gt(),await B(),ne(),K("Folder mounted.","ok")}catch(h){if(String(h?.name||"").trim()==="AbortError"){K("Mount canceled.","warn");return}K(`Mount failed: ${H(h)}`,"error")}}}),p?.addEventListener("click",()=>{const h=j(String(o?.value||"").trim());if(!h.ok){h.reason==="invalid"?K("Repository must be in owner/repo format.","warn"):K("Enter a repository to add.","warn");return}o&&(o.value=""),R(),M(),W({pendingMessage:"Adding repository to workspace...",successMessage:h.changed?"Repository added to workspace.":"Repository already in workspace."})}),t.root.querySelector('[data-action="save-settings"]')?.addEventListener("click",async()=>{await L({pendingMessage:"Saving GitHub token...",successMessage:"GitHub token saved."})}),o?.addEventListener("keydown",h=>{h.key==="Enter"&&(h.preventDefault(),t.root.querySelector('[data-action="add-repo"]')?.dispatchEvent(new Event("click")))}),r?.addEventListener("keydown",h=>{h.key==="Enter"&&(h.preventDefault(),t.root.querySelector('[data-action="save-settings"]')?.dispatchEvent(new Event("click")))}),R(),x(!1),P(!1),M(),ne(),Fe(),gr()&&(ue(),w("Loaded cached file index. Refreshing…","info")),await B()}l(Er,"renderHome");async function B(){if(t.loadingFiles){t.pendingFilesReload=!0,await U();return}if(!t.selectedRepoFulls.length){const e=oe();t.selectedRepoFulls=Q(e?.repoFulls||e?.repoFull||""),t.primaryRepoFull||(t.primaryRepoFull=String(e?.repoFull||t.selectedRepoFulls[0]||"").trim())}t.loadingFiles=!0,t.pendingFilesReload=!1,w("Loading files...","info"),D()&&je("Refreshing file index...","Loading local and remote records...");try{let e=[];try{e=await dt()}catch{e=[]}t.mountedDirectories=Array.isArray(e)?e:[];const r=t.mountedDirectories.map(m=>String(m?.id||"").trim()).filter(Boolean),[o,n,a,i,s,c]=await Promise.all([qe({source:"local"}),qe({source:"github",repoFulls:t.selectedRepoFulls}),qe({source:"mounted",repoFulls:r}),ze({source:"local"}),ze({source:"github",repoFulls:t.selectedRepoFulls}),ze({source:"mounted",repoFulls:r})]),u=[...Array.isArray(o)?o:[],...Array.isArray(n)?n:[],...Array.isArray(a)?a:[]],y=new Map;for(const m of u){const b=String(m?.source||"").trim().toLowerCase(),f=String(m?.repoFull||"").trim(),g=String(m?.name||m?.path||"").trim();if(!g)continue;const v=`${b}:${f}:${g}`;y.has(v)||y.set(v,m)}t.allRecords=Array.from(y.values()),t.allRecords.sort((m,b)=>{const f=Date.parse(m?.savedAt||"")||0;return(Date.parse(b?.savedAt||"")||0)-f});const d=[...Array.isArray(i)?i:[],...Array.isArray(s)?s:[],...Array.isArray(c)?c:[]],p=new Map;for(const m of d){const b=F(m?.source||"local"),f=String(m?.repoFull||"").trim(),g=E(m?.path||"");if(!g)continue;const v=`${b}:${f}:${g}`;p.has(v)||p.set(v,{source:b,repoFull:f,path:g,savedAt:m?.savedAt||null})}t.folderRecords=Array.from(p.values()),t.records=t.allRecords.slice(0,10),Qe(),hr(),Fe(),D()&&je("Refreshing file index...","Rendering updated file explorer..."),ue(),w("","info",!0)}catch(e){t.records=[],t.allRecords=[],t.folderRecords=[],Qe(),ue(),w(`Failed to load files: ${H(e)}`,"error")}finally{t.loadingFiles=!1,t.pendingFilesReload&&(t.pendingFilesReload=!1,await B())}}l(B,"loadFiles");function ue(){if(!t.filesListEl)return;if(t.explorerWidget){try{t.explorerWidget.destroy()}catch{}t.explorerWidget=null}rt(),t.filesListEl.innerHTML="";const e=t.searchTerm,r=t.records.slice().sort((p,m)=>{const b=Date.parse(p?.savedAt||"")||0;return(Date.parse(m?.savedAt||"")||0)-b});if(!(t.allRecords.length>0||t.folderRecords.length>0)){const p=document.createElement("section");p.className="hub-empty-start";const m=document.createElement("h3");m.className="hub-empty-start-title",m.textContent="Get Started",p.appendChild(m);const b=document.createElement("p");b.className="hub-empty-start-body",b.textContent="Add workspace repositories, create a new model, and save anywhere in your folder tree.",p.appendChild(b);const f=document.createElement("ol");f.className="hub-empty-start-steps";for(const g of["Open Workspace and include local, mounted folders, and/or GitHub repositories.","Click New Model to start a part or assembly.","Save to any folder path in your workspace tree."]){const v=document.createElement("li");v.textContent=g,f.appendChild(v)}p.appendChild(f),t.filesListEl.appendChild(p)}const n=document.createElement("section");n.className="hub-recent-strip",t.recentExpanded||n.classList.add("is-collapsed");const a=document.createElement("button");a.type="button",a.className="hub-recent-head hub-recent-toggle",a.setAttribute("aria-expanded",t.recentExpanded?"true":"false"),a.title=t.recentExpanded?"Collapse recent files":"Expand recent files";const i=document.createElement("h3");i.className="hub-recent-title",i.textContent="Recent Files";const s=document.createElement("div");s.className="hub-recent-head-right";const c=document.createElement("div");c.className="hub-recent-meta",c.textContent=`${r.length} file${r.length===1?"":"s"}`,s.appendChild(c);const u=document.createElement("span");u.className="hub-recent-chevron",u.setAttribute("aria-hidden","true"),u.textContent=t.recentExpanded?"v":">",s.appendChild(u),a.appendChild(i),a.appendChild(s),a.addEventListener("click",()=>{t.recentExpanded=!t.recentExpanded,$e(ft,t.recentExpanded?"1":"0"),ue()}),n.appendChild(a);const y=document.createElement("div");if(y.className="hub-recent-gallery hub-browser-grid",y.hidden=!t.recentExpanded,r.length)for(const p of r){const m=Lr(p);m&&y.appendChild(m)}else{const p=document.createElement("div");p.className="hub-empty",p.textContent="No recent files yet. Open or save a model to populate this list.",y.appendChild(p)}n.appendChild(y),t.filesListEl.appendChild(n);const d=De();t.filesListEl.appendChild(Mr(d,e))}l(ue,"renderFilesList");function xe(e){const r=String(e||"").trim();return r?r.toLowerCase().endsWith(_e)?r:`${r}${_e}`:""}l(xe,"ensureModelExtension");function et(e){const r=String(e?.name||"").trim(),o=String(e?.displayName||"").trim()||(r.includes("/")?r.split("/").pop():r);return xe(o||r)}l(et,"getEntryModelDisplayName");function $t(e){const r=E(e?.path||e?.name||"");return xe(r)}l($t,"getEntryModelPathWithExtension");function ye(e){return E(e?.browserPath||e?.path||e?.name||"")}l(ye,"getEntryBrowserPath");function xt(e){return xe(ye(e))}l(xt,"getEntryBrowserPathWithExtension");function Fr(e){const r=E(e);return r?r.toLowerCase().endsWith(_e)?r.slice(0,-_e.length):r:""}l(Fr,"stripModelFileExtension");function tt(e){const r=E(e?.path||e?.name||""),o=ye(e);return Fr(r||o)}l(tt,"getEntryCadLaunchModelPath");function kr(e){const r=F(e?.source),o=String(e?.repoFull||"").trim(),n=xt(e)||$t(e)||xe(String(e?.name||"").trim()),a=[];return a.push(me(r,o)),n&&a.push(n),a.join(" / ")}l(kr,"getEntryFullPathTooltip");function Xe(e){return E(e).split("/").filter(Boolean).map(r=>encodeURIComponent(r)).join("/")}l(Xe,"encodePathForUrl");function Ye(e){return String(e||"").trim().split("/").filter(Boolean).map(r=>encodeURIComponent(r)).join("/")}l(Ye,"encodeRefForUrl");function Rr(e){const r=String(e||"").trim();return/^[0-9a-f]{7,40}$/i.test(r)}l(Rr,"isCommitShaLikeRef");function Je(e){const r=String(e||"").trim();return!r||Rr(r)?"":r}l(Je,"normalizeGithubBrowserBranchRef");function $r(e){const o=String(e||"").trim().split("/");if(o.length<2)return null;const n=String(o[0]||"").trim(),a=String(o.slice(1).join("/")||"").trim();return!n||!a?null:{owner:n,repo:a}}l($r,"parseGithubRepoFull");function xr(e=""){const r={Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28"},o=String(e||"").trim();return o&&(r.Authorization=`Bearer ${o}`),r}l(xr,"getGithubApiHeaders");async function Cr(e,r=""){const o=String(e||"").trim();if(!o)return"";if(Ge.has(o))return String(Ge.get(o)||"");if(Te.has(o))return await Te.get(o);const n=(async()=>{try{const a=$r(o);if(!a)return"";const i=`${ar}/repos/${encodeURIComponent(a.owner)}/${encodeURIComponent(a.repo)}`,s=await fetch(i,{headers:xr(r)});if(!s.ok)return"";const c=await s.json(),u=Je(c?.default_branch||"");return u&&Ge.set(o,u),u}catch{return""}finally{Te.delete(o)}})();return Te.set(o,n),await n}l(Cr,"fetchGithubDefaultBranch");async function Pr(e){const r=String(e?.repoFull||"").trim();if(!r)return"";const o=oe()||{},n=String(o?.token||"").trim(),a=Je(e?.branch||""),i=Je(o?.branch||""),s=a||i||"",c=s.toLowerCase();if(!s||c==="main"||c==="master"){const u=await Cr(r,n);if(u)return u}return s||"main"}l(Pr,"resolveGithubBrowserBranch");async function Tr(e){if(F(e?.source)!=="github")return"";const o=String(e?.repoFull||"").trim();if(!o)return"";const n=await Pr(e),a=Ye(n),i=Xe(xt(e));return i?`https://github.com/${o}/blob/${a}/${i}`:`https://github.com/${o}`}l(Tr,"buildGithubModelUrl");async function Ar(e){try{const o=await Tr(e);if(o){window.open(o,"_blank","noopener,noreferrer");return}}catch{}const r=String(e?.repoFull||"").trim();r&&window.open(`https://github.com/${r}`,"_blank","noopener,noreferrer")}l(Ar,"openEntryOnGithub");function Lr(e){const r=String(e?.name||"").trim();if(!r)return null;const o=F(e?.source),n=String(e?.repoFull||"").trim(),a=String(e?.branch||"").trim(),i=Ce(e),s=Me(e),c=et(e),u=kr(e)||$t(e)||xe(r),y=tt(e)||r,d=l(f=>{f?.preventDefault?.(),f?.stopPropagation?.(),We({source:o,repoFull:n,branch:a,path:y})},"openFile"),p=document.createElement("article");p.className=`hub-browser-tile is-file hub-browser-file-entry${s?" is-selected":""}`,p.title=u||r,p.tabIndex=0,i&&(p.dataset.entryKey=i),p.appendChild(Gr(e,{tile:!0})),p.appendChild(Mt(e,{extraClass:"hub-browser-tile-menu"}));const m=Dr(e,{previewClass:"hub-browser-tile-preview",iconClass:"hub-browser-tile-icon",thumbClass:"hub-browser-tile-thumb"});m.classList.add("hub-browser-open-target"),m.title=`Open ${c||r}`,m.addEventListener("click",d),p.appendChild(m);const b=document.createElement("div");return b.className="hub-browser-tile-name",b.textContent=c||r,b.title=u||r,b.classList.add("hub-browser-open-target"),b.addEventListener("click",d),p.appendChild(b),zr(p,e,d),It(p,e),p}l(Lr,"createBrowserFileTile");function Dr(e,{previewClass:r="hub-browser-preview",iconClass:o="hub-browser-icon",thumbClass:n="hub-browser-thumb",iconGlyph:a="📄"}={}){const i=String(e?.name||"").trim(),s=et(e)||i||"Model",c=document.createElement("span");c.className=r;const u=document.createElement("span");u.className=o,u.textContent=a,u.setAttribute("aria-hidden","true"),c.appendChild(u);const y=document.createElement("img");return y.className=n,y.alt=`${s} preview`,y.addEventListener("load",()=>c.classList.add("has-thumb")),y.addEventListener("error",()=>c.classList.remove("has-thumb")),c.appendChild(y),Qr(e,y),c}l(Dr,"createModelPreview");function Ct(e,r=""){const o=F(e),n=String(r||"").trim();return t.allRecords.filter(a=>F(a?.source)!==o?!1:o==="local"?!0:String(a?.repoFull||"").trim()===n)}l(Ct,"getRecordsForRoot");function Pt(e,r=""){const o=F(e),n=String(r||"").trim();return t.folderRecords.filter(a=>F(a?.source)!==o?!1:o==="local"?!0:String(a?.repoFull||"").trim()===n)}l(Pt,"getFoldersForRoot");function Mr(e,r=""){const o=Array.isArray(e)?e:[],n=String(r||"").trim(),a=document.createElement("section");a.className="hub-explorer hub-browser",t.visibleExplorerEntryKeys=[];let i=null;const s=document.createElement("div");return s.className="hub-explorer-list",s.style.minWidth="0",a.appendChild(s),i=new pt({container:s,onActivateFile:l(async c=>{const u=F(c?.source),y=String(c?.repoFull||"").trim(),d=String(c?.branch||"").trim(),p=tt(c)||String(c?.name||"").trim();We({source:u,repoFull:y,branch:d,path:p})},"onActivateFile"),onLocationChange:l(c=>{t.explorerWorkspaceTop=!!c?.workspaceTop,t.explorerRootSource=F(c?.source||"local"),t.explorerRootRepoFull=String(c?.repoFull||"").trim(),t.explorerPath=t.explorerWorkspaceTop?"":E(c?.path||""),ge(),lt(i?.getRoots?.()||o)},"onLocationChange"),onViewModeChange:l(c=>{t.explorerViewMode=c==="icons"?"icons":"list",$e(ht,t.explorerViewMode)},"onViewModeChange"),onCreateFolder:l(async({targetPath:c,source:u,repoFull:y})=>{const d=F(u||"local"),p=d==="local"?"":String(y||"").trim();if(!D()){if(d==="github"&&!String(oe()?.token||"").trim())throw new Error("Set a GitHub token in Settings before creating folders in repositories.");w(`Creating folder "${c}"...`,"info"),await se(`Creating folder "${c}"...`,async({setMessage:m})=>{m(`Creating folder "${c}"...`,"Writing folder metadata..."),await Be(c,{source:d,repoFull:p}),t.explorerWorkspaceTop=!1,t.explorerRootSource=d,t.explorerRootRepoFull=p,t.explorerPath=E(c),ge(),m("Refreshing file index...","Updating folder and file listing..."),await B(),await U()}),w(`Created folder "${c}".`,"ok")}},"onCreateFolder"),onDeleteFolder:l(async({path:c,source:u,repoFull:y})=>{await At(c,{source:F(u||"local"),repoFull:String(y||"").trim()})},"onDeleteFolder"),onEmptyTrash:l(async({files:c=[],folders:u=[]}={})=>{await Kt(c,{confirm:!1,folderEntries:u})},"onEmptyTrash"),createFileActionsMenu:l((c,{tile:u=!1}={})=>Mt(c,{extraClass:u?"hub-browser-tile-menu":""}),"createFileActionsMenu"),createFolderActionsMenu:l((c,{tile:u=!1,source:y,repoFull:d}={})=>Or(c,{source:F(y||"local"),repoFull:String(d||"").trim()},{extraClass:u?"hub-browser-tile-menu":""}),"createFolderActionsMenu"),bindFileDragSource:l((c,u)=>It(c,u),"bindFileDragSource"),bindDropTarget:l((c,u)=>Xr(c,Vr(u?.source,u?.repoFull,u?.path)),"bindDropTarget"),onDropFiles:l(async({files:c,target:u})=>{await Bt(c,u,{refresh:!0})},"onDropFiles"),showSearchInput:!1,showCreateFolderButton:!0,showDeleteFolderButton:!0,showEmptyTrashButton:!0,showUpButton:!0,showRefreshButton:!1,fileActionLabel:"Open",scrollBody:!1}),t.explorerWidget=i,i.setData({records:t.allRecords,folders:t.folderRecords,roots:o},{render:!1}),i.setSearchTerm(n,{render:!1,syncInput:!0}),i.setViewMode(t.explorerViewMode,{persist:!1}),i.setLocation({workspaceTop:!!t.explorerWorkspaceTop,source:t.explorerRootSource,repoFull:t.explorerRootRepoFull,path:t.explorerPath},{persist:!1}),lt(i.getRoots()),a}l(Mr,"createFolderExplorer");function lt(e){const r=t.workspaceFoldersEl;if(!r)return;r.innerHTML="";const o=Array.isArray(e)?e:[];if(t.workspaceFoldersMetaEl&&(t.workspaceFoldersMetaEl.textContent=`${o.length} folder${o.length===1?"":"s"}`),!o.length){const a=document.createElement("div");a.className="hub-empty",a.textContent="No workspace folders configured yet. Add a repo or mount a folder to start browsing.",r.appendChild(a);return}const n=t.explorerWorkspaceTop?"":st(t.explorerRootSource,t.explorerRootRepoFull);for(const a of o)r.appendChild(_r(a,{isSelected:!!n&&st(a.source,a.repoFull)===n,onOpen:l(()=>kt(a.source,a.repoFull),"onOpen")}))}l(lt,"renderWorkspaceFoldersList");function _r(e,{isSelected:r=!1,onOpen:o=null}={}){const n=F(e?.source),a=String(e?.repoFull||"").trim(),i=ke(n,a)||!!e?.isTrash,s=String(e?.label||me(n,a)).trim()||"Workspace",c=!!e?.isPrimary&&n==="github",u=n==="local"&&!i,y=n==="mounted"&&!i,d=document.createElement("button");d.type="button",d.className=`hub-folder-card${c?" is-primary":""}${r?" is-selected":""}`,typeof o=="function"&&d.addEventListener("click",o);const p=document.createElement("div");p.className="hub-folder-card-icon",p.textContent=i?"🗑️":"📁",d.appendChild(p);const m=document.createElement("div");m.className="hub-folder-card-body";const b=document.createElement("div");b.className="hub-folder-card-name",b.textContent=s,b.title=s,m.appendChild(b);const f=document.createElement("div");return f.className="hub-folder-card-meta",i?f.textContent=r?"Internal trash · browsing":"Internal trash":u?f.textContent=r?"Local workspace · browsing":"Local workspace":y?f.textContent=r?"Mounted folder · browsing":"Mounted folder":c?f.textContent=r?"Primary workspace repo · browsing":"Primary workspace repo":f.textContent=r?"Workspace repo · browsing":"Workspace repo",m.appendChild(f),d.appendChild(m),d}l(_r,"createFolderCard");function rt(){if(typeof t.activeFileMenuClose!="function")return;const e=t.activeFileMenuClose;t.activeFileMenuClose=null;try{e()}catch{}}l(rt,"closeActiveFileMenu");function Tt(e=[],r={}){const o=String(r?.extraClass||"").trim(),n=String(r?.triggerTitle||"Actions").trim()||"Actions",a=document.createElement("div");a.className=o?`hub-file-menu ${o}`:"hub-file-menu";const i=document.createElement("button");i.type="button",i.className="hub-icon-btn hub-file-menu-trigger",i.textContent="...",i.title=n,i.setAttribute("aria-label",n),i.setAttribute("aria-haspopup","menu"),i.setAttribute("aria-expanded","false"),a.appendChild(i);const s=document.createElement("div");s.className="hub-file-menu-list",s.setAttribute("role","menu"),a.appendChild(s);let c=!1,u=null;const y=l(()=>{s.parentNode!==document.body&&document.body.appendChild(s)},"attachMenuToBody"),d=l(()=>{s.parentNode!==a&&a.appendChild(s)},"attachMenuToWrapper"),p=l(()=>{if(!c)return;const f=8;y(),s.classList.add("is-open"),s.classList.add("is-floating"),s.style.maxHeight=`${Math.max(140,window.innerHeight-f*2)}px`,s.style.overflowY="auto";const g=i.getBoundingClientRect(),v=s.getBoundingClientRect(),R=Math.max(136,Math.ceil(v.width||s.offsetWidth||136)),C=Math.ceil(v.height||s.offsetHeight||0);let P=g.right-R;P<f&&(P=f),P+R>window.innerWidth-f&&(P=Math.max(f,window.innerWidth-f-R));let k=g.bottom+6;if(k+C>window.innerHeight-f){const A=g.top-6-C;A>=f?k=A:k=Math.max(f,window.innerHeight-f-C)}s.style.left=`${Math.round(P)}px`,s.style.top=`${Math.round(k)}px`,s.style.right="auto"},"positionMenu"),m=l(()=>{c&&(c=!1,a.classList.remove("is-open"),i.setAttribute("aria-expanded","false"),s.classList.remove("is-open"),s.classList.remove("is-floating"),s.style.left="",s.style.top="",s.style.right="",s.style.maxHeight="",s.style.overflowY="",d(),typeof u=="function"&&(u(),u=null),t.activeFileMenuClose===m&&(t.activeFileMenuClose=null))},"closeMenu"),b=l(()=>{if(c)return;rt(),c=!0,a.classList.add("is-open"),i.setAttribute("aria-expanded","true"),t.activeFileMenuClose=m,p();const f=l(R=>{a.contains(R?.target)||s.contains(R?.target)||m()},"onPointerDown"),g=l(R=>{R?.key==="Escape"&&(R.preventDefault(),m())},"onKeyDown"),v=l(()=>{c&&p()},"onViewportChange");window.addEventListener("pointerdown",f,!0),window.addEventListener("keydown",g,!0),window.addEventListener("resize",v,!0),window.addEventListener("scroll",v,!0),u=l(()=>{window.removeEventListener("pointerdown",f,!0),window.removeEventListener("keydown",g,!0),window.removeEventListener("resize",v,!0),window.removeEventListener("scroll",v,!0)},"removeOutsideHandlers")},"openMenu");i.addEventListener("click",f=>{if(D()){f.preventDefault(),f.stopPropagation();return}f.preventDefault(),f.stopPropagation(),c?m():b()});for(const f of Array.isArray(e)?e:[]){if(!f||typeof f!="object")continue;const g=document.createElement("button");g.type="button",g.className=String(f.className||"hub-file-menu-item"),g.textContent=String(f.label||"").trim()||"Action",g.setAttribute("role","menuitem"),f.disabled&&(g.disabled=!0,g.title=String(f.disabledTitle||"Unavailable")),g.addEventListener("click",v=>{if(D()){v.preventDefault(),v.stopPropagation();return}f.disabled||(v.preventDefault(),v.stopPropagation(),m(),typeof f.run=="function"&&f.run())}),s.appendChild(g)}return a}l(Tt,"createFloatingActionsMenu");function be(e,r=""){const o=F(e),n=String(r||"").trim(),a={source:o,repoFull:n};if(o==="github"){const i=String(oe()?.branch||"").trim();i&&(a.branch=i)}return a}l(be,"getFolderScopeOptions");function Nr(e,r=""){return`${F(e)}::${String(r||"").trim()}`}l(Nr,"makeStorageScopeKey");function Oe(e=[],r=[]){const o=new Map,n=l((a,i)=>{const s=F(a||"local"),c=String(i||"").trim(),u=Nr(s,c);o.has(u)||o.set(u,{source:s,repoFull:c})},"addScope");for(const a of Array.isArray(e)?e:[]){const i=G(a);X(i)&&n(a?.source,a?.repoFull)}for(const a of Array.isArray(r)?r:[]){const i=E(a?.path||"");X(i)&&n(a?.source,a?.repoFull)}return Array.from(o.values())}l(Oe,"collectTrashScopes");function Br(e,r=""){const o=F(e||"local"),n=String(r||"").trim();return t.allRecords.some(a=>{const i=F(a?.source||"local");if(i!==o||i!=="local"&&String(a?.repoFull||"").trim()!==n)return!1;const s=ye(a);return X(s)})}l(Br,"hasTrashFilesInScope");function Ir(e,r=""){const o=F(e||"local"),n=String(r||"").trim(),a=t.folderRecords.filter(i=>{const s=F(i?.source||"local");return s!==o||s!=="local"&&String(i?.repoFull||"").trim()!==n?!1:X(i?.path||"")}).map(i=>E(i?.path||"")).filter(Boolean);return a.includes(Ee)||a.push(Ee),Array.from(new Set(a)).sort((i,s)=>s.length-i.length)}l(Ir,"getTrashFolderPathsInScope");async function Ke(e=[],{setMessage:r=null}={}){const o=Array.isArray(e)?e:[];if(!o.length)return 0;let n=0;for(const a of o){const i=F(a?.source||"local"),s=String(a?.repoFull||"").trim();if(i==="github"&&z(s)||Br(i,s))continue;const c=Ir(i,s);if(c.length)for(let u=0;u<c.length;u+=1){const y=c[u];typeof r=="function"&&r("Cleaning empty Trash...",`Removing marker ${u+1}/${c.length}: ${y}`);try{await Re(y,be(i,s)),n+=1}catch{}}}return n}l(Ke,"cleanupEmptyTrashFolders");function ot(e,r="",o=""){const n=F(e),a=String(r||"").trim(),i=E(o),s=i?`${i}/`:"",c=Ct(n,a),u=Pt(n,a),y=c.filter(p=>{const m=ye(p);return m===i||m.startsWith(s)}),d=u.map(p=>E(p?.path||"")).filter(p=>p&&(p===i||p.startsWith(s)));return i&&!d.includes(i)&&d.push(i),{records:y,folderPaths:Array.from(new Set(d))}}l(ot,"collectFolderSubtree");async function At(e,r={}){if(D())return;const o=E(e);if(!o)return;const n=F(r?.source||t.explorerRootSource),a=String(r?.repoFull||t.explorerRootRepoFull||"").trim();if(n==="github"&&z(a)){w(`Repository "${a}" is read-only.`,"warn");return}const{records:i,folderPaths:s}=ot(n,a,o),c=i.length,u=s.length;if(!c&&!u){w(`Folder "${o}" has no managed files to delete.`,"warn");return}if(!await confirm(`Delete folder "${o}"?
|
|
135
|
+
|
|
136
|
+
This will remove ${c} file${c===1?"":"s"} and ${u} managed folder marker${u===1?"":"s"}.`))return;const d=be(n,a);let p=0,m=0;try{w(`Deleting folder "${o}"...`,"info"),await se(`Deleting folder "${o}"...`,async({setMessage:b})=>{for(let f=0;f<i.length;f+=1){const g=i[f],v=E(g?.path||g?.name||"");b(`Deleting folder "${o}"...`,`Removing file ${f+1}/${i.length}: ${v||"Unknown file"}`);try{await pe(g.path||g.name,ce(g)),t.thumbCache.delete(Y(g))}catch{p+=1}}s.sort((f,g)=>g.length-f.length);for(let f=0;f<s.length;f+=1){const g=s[f];b(`Deleting folder "${o}"...`,`Removing folder marker ${f+1}/${s.length}: ${g}`);try{await Re(g,d),m+=1}catch{}}if(!t.explorerWorkspaceTop&&F(t.explorerRootSource)===n&&String(t.explorerRootRepoFull||"").trim()===a){const f=E(t.explorerPath||""),g=`${o}/`;if(f===o||f.startsWith(g)){const v=o.lastIndexOf("/");t.explorerPath=v>=0?o.slice(0,v):"",ge()}}b("Refreshing file index...","Updating folder and file listing..."),await B(),await U()}),p?w(`Deleted folder "${o}" with ${p} file deletion failure${p===1?"":"s"}.`,"warn"):w(`Deleted folder "${o}". Removed ${c} file${c===1?"":"s"} and ${m} folder marker${m===1?"":"s"}.`,"ok")}catch(b){w(`Delete folder failed: ${H(b)}`,"error")}}l(At,"deleteFolderPath");async function Wr(e,r={}){if(D())return;const o=E(e);if(!o)return;const n=F(r?.source||t.explorerRootSource),a=String(r?.repoFull||t.explorerRootRepoFull||"").trim();if(n==="github"&&z(a)){w(`Repository "${a}" is read-only.`,"warn");return}const i=await prompt("Rename folder path:",o);if(i==null)return;const s=E(String(i||"").trim());if(!s||s===o)return;if(s.startsWith(`${o}/`)){w("Cannot move a folder inside itself.","warn");return}const c=Ct(n,a),u=Pt(n,a),y=`${s}/`;if(c.some(R=>{const C=E(ye(R));return C===s||C.startsWith(y)})||u.some(R=>{const C=E(R?.path||"");return C===s||C.startsWith(y)})){w(`Target folder "${s}" already exists.`,"warn");return}const{records:p,folderPaths:m}=ot(n,a,o),b=`${o}/`,f=be(n,a);let g=0,v=0;try{w(`Renaming folder "${o}" to "${s}"...`,"info"),await se(`Renaming folder "${o}"...`,async({setMessage:R})=>{const C=m.slice().sort((k,A)=>k.length-A.length);for(let k=0;k<C.length;k+=1){const A=C[k],x=A===o?"":A.slice(b.length),_=E(x?`${s}/${x}`:s);if(_){R(`Renaming folder "${o}"...`,`Preparing folder marker ${k+1}/${C.length}: ${_}`);try{await Be(_,f)}catch{}}}for(let k=0;k<p.length;k+=1){const A=p[k],x=G(A)||E(de(A));if(!x){v+=1;continue}const _=x===o?"":x.slice(b.length),j=E(_?`${s}/${_}`:s);if(!j){v+=1;continue}R(`Renaming folder "${o}"...`,`Moving file ${k+1}/${p.length}: ${x}`);try{const M=await V(x,ce(A));if(!M||!M.data3mf){v+=1;continue}await fe(j,{savedAt:new Date().toISOString(),data3mf:M.data3mf,data:M.data,thumbnail:M.thumbnail||null},{...ce(A),source:n,repoFull:a,path:j}),await pe(x,ce(A));const ne=Y({source:n,repoFull:a,name:x}),I=Y({source:n,repoFull:a,name:j}),N=t.thumbCache.get(ne);N&&(t.thumbCache.set(I,N),t.thumbCache.delete(ne)),g+=1}catch{v+=1}}const P=m.slice().sort((k,A)=>A.length-k.length);for(let k=0;k<P.length;k+=1){const A=P[k];R(`Renaming folder "${o}"...`,`Cleaning old marker ${k+1}/${P.length}: ${A}`);try{await Re(A,f)}catch{}}if(!t.explorerWorkspaceTop&&F(t.explorerRootSource)===n&&String(t.explorerRootRepoFull||"").trim()===a){const k=E(t.explorerPath||"");if(k===o||k.startsWith(b)){const A=k===o?"":k.slice(b.length);t.explorerPath=E(A?`${s}/${A}`:s),ge()}}R("Refreshing file index...","Updating folder and file listing..."),await B(),await U()}),v?w(`Folder rename completed with ${v} failure${v===1?"":"s"}.`,"warn"):w(`Renamed folder to "${s}". Moved ${g} file${g===1?"":"s"}.`,"ok")}catch(R){w(`Rename folder failed: ${H(R)}`,"error")}}l(Wr,"renameFolderPath");function Lt(e=""){const r=E(e);if(!r)return"";const o=r.lastIndexOf("/");return o>=0?r.slice(0,o):""}l(Lt,"getParentPath");function Ze(e=""){const r=E(e);if(!r)return"";const o=r.lastIndexOf("/");return o>=0?r.slice(o+1):r}l(Ze,"getBaseName");function Ne(e,r="",o=""){const n=be(e,r),a=E(o);return a&&(n.path=a),n}l(Ne,"getFileScopeOptions");function nt(e=""){const r=String(e||"").trim();return!r||r.includes("/")||r.includes("\\")?"":E(r)}l(nt,"normalizeTargetName");async function Dt({title:e="Transfer",actionLabel:r="Apply",nameLabel:o="Name",initialName:n="",initialLocation:a={},description:i=""}={}){return await new Promise(s=>{const c=document.createElement("div");c.className="hub-modal-overlay",c.hidden=!1;const u=document.createElement("section");u.className="hub-panel hub-modal-panel hub-workspace-panel",u.style.width="min(1180px, calc(100vw - 48px))",u.style.maxHeight="calc(100vh - 40px)",u.style.display="flex",u.style.flexDirection="column",u.style.gap="10px",u.style.overflow="hidden",c.appendChild(u);const y=document.createElement("div");y.className="hub-panel-head";const d=document.createElement("h2");d.className="hub-panel-title",d.textContent=e,y.appendChild(d);const p=document.createElement("button");if(p.type="button",p.className="hub-ghost-btn",p.textContent="Cancel",y.appendChild(p),u.appendChild(y),i){const L=document.createElement("p");L.className="hub-help",L.textContent=i,u.appendChild(L)}const m=document.createElement("label");m.className="hub-field";const b=document.createElement("span");b.className="hub-field-label",b.textContent=o,m.appendChild(b);const f=document.createElement("input");f.type="text",f.className="hub-input",f.value=String(n||"").trim(),f.placeholder=o,m.appendChild(f),u.appendChild(m);const g=document.createElement("div");g.className="hub-help",u.appendChild(g);const v=document.createElement("div");v.className="hub-status",v.hidden=!0,u.appendChild(v);const R=document.createElement("div");R.style.minHeight="320px",R.style.height="min(56vh, 520px)",R.style.maxHeight="56vh",R.style.overflow="hidden",u.appendChild(R);const C=document.createElement("div");C.className="hub-actions-row";const P=document.createElement("button");P.type="button",P.className="hub-primary-btn",P.textContent=r;const k=document.createElement("button");k.type="button",k.className="hub-ghost-btn",k.textContent="Cancel",C.appendChild(P),C.appendChild(k),u.appendChild(C),document.body.appendChild(c);let A=!1,x=null;const _=l((L="",h="warn")=>{const S=String(L||"").trim();if(!S){v.hidden=!0,v.textContent="",v.dataset.tone="";return}v.hidden=!1,v.textContent=S,v.dataset.tone=h},"setDialogStatus"),j=l(()=>{if(!x)return;const L=x.getLocation(),h=F(L?.source||"local"),S=h==="local"?"":String(L?.repoFull||"").trim(),$=E(L?.path||""),T=!!L?.workspaceTop,O=[me(h,S),$||"(root)"].join(" / ");g.textContent=T?"Destination: select a workspace root or folder.":`Destination: ${O}`;const J=T||ke(h,S)||X($);P.disabled=J},"updateDestinationMeta"),M=l((L=null)=>{if(!A){A=!0;try{window.removeEventListener("keydown",ne,!0)}catch{}try{x?.destroy?.()}catch{}try{c.remove()}catch{}s(L)}},"close"),ne=l(L=>{L.key==="Escape"&&(L.preventDefault(),L.stopPropagation(),M(null))},"onKeyDown");window.addEventListener("keydown",ne,!0),c.addEventListener("click",L=>{L.target===c&&M(null)}),p.addEventListener("click",()=>M(null)),k.addEventListener("click",()=>M(null)),P.addEventListener("click",()=>{if(!x)return;const L=x.getLocation(),h=F(L?.source||"local"),S=h==="local"?"":String(L?.repoFull||"").trim(),$=E(L?.path||""),T=nt(f.value||"");if(!T){_(`${o} is required and cannot include path separators.`,"warn");return}if(L?.workspaceTop){_("Select a destination root or folder.","warn");return}if(ke(h,S)||X($)){_("Moving/copying into Trash is not allowed in this dialog.","warn");return}if(h!=="local"&&!S){_("Select a valid destination root.","warn");return}M({source:h,repoFull:S,path:$,name:T})}),x=new pt({container:R,onLocationChange:l(()=>{_("","warn"),j()},"onLocationChange"),onCreateFolder:l(async({targetPath:L,source:h,repoFull:S})=>{const $=F(h||"local"),T=$==="local"?"":String(S||"").trim();if($==="github"&&!String(oe()?.token||"").trim())throw new Error("Set a GitHub token in Settings before creating folders in repositories.");if($==="github"&&z(T))throw new Error(`Repository "${T}" is read-only.`);await Be(L,{source:$,repoFull:T}),await B(),await U(),x.setData({records:t.allRecords,folders:t.folderRecords,roots:De()},{render:!1}),x.setLocation({workspaceTop:!1,source:$,repoFull:T,path:E(L)},{persist:!1})},"onCreateFolder"),onDropFiles:l(async({files:L,target:h})=>{_("","warn"),await Bt(L,h,{refresh:!0});const S=x?.getLocation?.()||{workspaceTop:!1,source:F(h?.source||"local"),repoFull:String(h?.repoFull||"").trim(),path:E(h?.path||"")},$=S.workspaceTop?{workspaceTop:!1,source:F(h?.source||"local"),repoFull:String(h?.repoFull||"").trim(),path:E(h?.path||"")}:S;x.setData({records:t.allRecords,folders:t.folderRecords,roots:De()},{render:!1}),x.setLocation({workspaceTop:!!$.workspaceTop,source:F($.source||"local"),repoFull:String($.repoFull||"").trim(),path:E($.path||"")},{persist:!1}),j()},"onDropFiles"),showSearchInput:!0,showViewToggle:!0,showCreateFolderButton:!0,showDeleteFolderButton:!1,showEmptyTrashButton:!1,showUpButton:!0,showRefreshButton:!0,fileActionLabel:"Open",scrollBody:!0});try{x._saveLocationPreference=()=>{}}catch{}const I=De();x.setData({records:t.allRecords,folders:t.folderRecords,roots:I},{render:!1});const N=F(a?.source||"local"),W=N==="local"?"":String(a?.repoFull||"").trim(),ae=E(a?.path||"");x.setLocation({workspaceTop:!1,source:N,repoFull:W,path:ae},{persist:!1}),j(),setTimeout(()=>{try{f.focus({preventScroll:!0})}catch{}try{f.select()}catch{}},0)})}l(Dt,"openTransferBrowserDialog");async function ct(e,{copy:r=!0}={}){if(D())return;const o=G(e);if(!o){w("File path is missing.","warn");return}const n=F(e?.source),a=String(e?.repoFull||"").trim();if(!r&&n==="github"&&z(a)){w(`Cannot move from read-only repository "${a}".`,"warn");return}const i=await Dt({title:r?"Copy File To...":"Move File To...",actionLabel:r?"Copy File":"Move File",nameLabel:"File Name",initialName:Ze(o)||et(e),initialLocation:{source:n,repoFull:a,path:Lt(o)},description:"Choose a destination folder, then set the file name."});if(!i)return;const s=F(i.source||"local"),c=s==="local"?"":String(i.repoFull||"").trim(),u=E(i.path||""),y=nt(i.name||""),d=E(u?`${u}/${y}`:y);if(!d){w("Destination file path is invalid.","warn");return}if(s!=="local"&&!c){w("Destination root is missing.","warn");return}if(s==="github"&&!String(oe()?.token||"").trim()){w("Set a GitHub token in Settings before writing to repositories.","warn");return}if(s==="github"&&z(c)){w(`Repository "${c}" is read-only.`,"warn");return}if(n===s&&a===c&&o===d){w("Source and destination are the same.","warn");return}const m=r?"Copy":"Move";let b=!1;const f=Oe([e],[]);try{await se(`${m} file...`,async({setMessage:g})=>{const v=Ne(n,a,o),R=Ne(s,c,d);g(`${m} file...`,`Reading: ${o}`);const C=await V(o,v);if(!C||!C.data3mf)throw new Error(`File not found: ${o}`);if(g(`${m} file...`,`Checking destination: ${d}`),await V(d,R)&&!await confirm(`"${d}" already exists. Overwrite it?`)){b=!0;return}g(`${m} file...`,`Writing: ${d}`),await fe(d,{savedAt:new Date().toISOString(),data3mf:C.data3mf,data:C.data,thumbnail:C.thumbnail||null},R),r||(g(`${m} file...`,`Removing source: ${o}`),await pe(o,v),t.thumbCache.delete(Y(e))),we({rerender:!1}),g("Refreshing file index...","Updating folder and file listing..."),await B(),await U(),await Ke(f,{setMessage:g})>0&&(g("Refreshing file index...","Finalizing Trash folder cleanup..."),await B(),await U())},{detail:`${o} -> ${d}`})}catch(g){w(`${m} failed: ${H(g)}`,"error");return}if(b){w(`${m} cancelled.`,"warn");return}w(`${m} complete: "${d}".`,"ok")}l(ct,"runFileTransferAction");async function ut(e,r={}){if(D())return;const o=E(e?.path||"");if(!o){w("Folder path is missing.","warn");return}const n=F(r?.source||t.explorerRootSource||"local"),a=String(r?.repoFull||t.explorerRootRepoFull||"").trim(),i=r?.copy!==!1;if(!i&&n==="github"&&z(a)){w(`Cannot move from read-only repository "${a}".`,"warn");return}const s=await Dt({title:i?"Copy Folder To...":"Move Folder To...",actionLabel:i?"Copy Folder":"Move Folder",nameLabel:"Folder Name",initialName:Ze(o),initialLocation:{source:n,repoFull:a,path:Lt(o)},description:"Choose a destination folder, then set the folder name."});if(!s)return;const c=F(s.source||"local"),u=c==="local"?"":String(s.repoFull||"").trim(),y=E(s.path||""),d=nt(s.name||""),p=E(y?`${y}/${d}`:d);if(!p){w("Destination folder path is invalid.","warn");return}if(c!=="local"&&!u){w("Destination root is missing.","warn");return}if(c==="github"&&!String(oe()?.token||"").trim()){w("Set a GitHub token in Settings before writing to repositories.","warn");return}if(c==="github"&&z(u)){w(`Repository "${u}" is read-only.`,"warn");return}if(n===c&&a===u&&o===p){w("Source and destination are the same.","warn");return}if(!i&&n===c&&a===u&&p.startsWith(`${o}/`)){w("Cannot move a folder inside itself.","warn");return}const{records:b,folderPaths:f}=ot(n,a,o);if(!b.length&&!f.length){w(`Folder "${o}" has no managed content to transfer.`,"warn");return}const g=i?"Copy":"Move";let v=0,R=0,C=0,P=0;const k=Oe(b,[{source:n,repoFull:a,path:o}]);try{await se(`${g} folder...`,async({setMessage:x})=>{const _=`${o}/`,j=f.slice().sort((I,N)=>I.length-N.length);for(let I=0;I<j.length;I+=1){const N=j[I],W=N===o?"":N.slice(_.length),ae=E(W?`${p}/${W}`:p);if(ae){x(`${g} folder...`,`Preparing destination folder ${I+1}/${j.length}: ${ae}`);try{await Be(ae,be(c,u))}catch{}}}const M=b.slice().sort((I,N)=>String(G(I)||"").localeCompare(String(G(N)||"")));for(let I=0;I<M.length;I+=1){const N=M[I],W=G(N);if(!W){C+=1;continue}const ae=W.startsWith(_)?W.slice(_.length):Ze(W),L=E(ae?`${p}/${ae}`:p);if(!L){C+=1;continue}x(`${g} folder...`,`Processing file ${I+1}/${M.length}: ${W}`);try{const h=Ne(n,a,W),S=Ne(c,u,L),$=await V(W,h);if(!$||!$.data3mf){P+=1;continue}if(await V(L,S)&&!await confirm(`"${L}" already exists. Overwrite it?`)){C+=1;continue}await fe(L,{savedAt:new Date().toISOString(),data3mf:$.data3mf,data:$.data,thumbnail:$.thumbnail||null},S),i?v+=1:(await pe(W,h),t.thumbCache.delete(Y({source:n,repoFull:a,name:W})),R+=1)}catch{P+=1}}if(!i){const I=f.slice().sort((N,W)=>W.length-N.length);for(let N=0;N<I.length;N+=1){const W=I[N];x(`${g} folder...`,`Cleaning source folder marker ${N+1}/${I.length}: ${W}`);try{await Re(W,be(n,a))}catch{}}}we({rerender:!1}),x("Refreshing file index...","Updating folder and file listing..."),await B(),await U(),await Ke(k,{setMessage:x})>0&&(x("Refreshing file index...","Finalizing Trash folder cleanup..."),await B(),await U())},{detail:`${o} -> ${p}`})}catch(x){w(`${g} folder failed: ${H(x)}`,"error");return}const A=i?v:R;P?w(`${g} folder complete: ${A} succeeded, ${P} failed, ${C} skipped.`,"warn"):w(`${g} folder complete: ${A} succeeded, ${C} skipped.`,"ok")}l(ut,"runFolderTransferAction");function Or(e,r={},o={}){const n=E(e?.path||"");if(!n)return null;const a=F(r?.source||t.explorerRootSource),i=String(r?.repoFull||t.explorerRootRepoFull||"").trim();if(ke(a,i)||X(n))return null;const s=a==="github"&&z(i),c=String(o?.extraClass||"").trim();return Tt([{label:"Open",className:"hub-file-menu-item",run:l(()=>Rt(n),"run")},{label:"Rename Folder",className:"hub-file-menu-item",disabled:s,disabledTitle:"Read-only repository",run:l(()=>{Wr(n,{source:a,repoFull:i})},"run")},{label:"Copy Folder...",className:"hub-file-menu-item",run:l(()=>{ut(e,{source:a,repoFull:i,copy:!0})},"run")},{label:"Move Folder...",className:"hub-file-menu-item",disabled:s,disabledTitle:"Read-only repository",run:l(()=>{ut(e,{source:a,repoFull:i,copy:!1})},"run")},{label:"Delete Folder",className:"hub-file-menu-item is-danger",disabled:s,disabledTitle:"Read-only repository",run:l(()=>{At(n,{source:a,repoFull:i})},"run")}],{extraClass:c,triggerTitle:"Folder actions"})}l(Or,"createFolderActionsMenu");function Mt(e,r={}){const o=String(e?.name||"").trim(),n=F(e?.source),a=String(e?.repoFull||"").trim(),i=String(e?.branch||"").trim(),s=X(ye(e)),c=s?Wt(G(e)):"",u=n==="github"&&z(a),y=n==="github"&&!!a,d=tt(e)||o,p=String(r?.extraClass||"").trim(),m=[{label:"Open",className:"hub-file-menu-item",run:l(()=>We({source:n,repoFull:a,branch:i,path:d}),"run")},...y?[{label:"Open on GitHub",className:"hub-file-menu-item",run:l(()=>{Ar(e)},"run")}]:[],{label:"Rename",className:"hub-file-menu-item",disabled:u,run:l(()=>{eo(e)},"run")},{label:"Duplicate",className:"hub-file-menu-item",disabled:u,run:l(()=>{to(e)},"run")},{label:"Copy To...",className:"hub-file-menu-item",run:l(()=>{ct(e,{copy:!0})},"run")},{label:"Move To...",className:"hub-file-menu-item",disabled:u,disabledTitle:"Read-only repository",run:l(()=>{ct(e,{copy:!1})},"run")},...s?[{label:"Restore",className:"hub-file-menu-item",disabled:u||!c,disabledTitle:u?"Read-only repository":"Original path unavailable",run:l(()=>{Zr([e],{confirm:!0})},"run")},{label:"Delete Permanently",className:"hub-file-menu-item is-danger",disabled:u,disabledTitle:"Read-only repository",run:l(()=>{Kt([e],{confirm:!0})},"run")}]:[{label:"Move to Trash",className:"hub-file-menu-item is-danger",disabled:u,run:l(()=>{Ht([e],{confirm:!0})},"run")}]];return Tt(m,{extraClass:p,triggerTitle:"File actions"})}l(Mt,"createFileActionsMenu");function He(e){return!e||typeof e=="string"?"":String(e.repoFull||"").trim()}l(He,"getEntryRepoFull");function Ue(e){return!e||typeof e=="string"?"":String(e.source||"").trim().toLowerCase()}l(Ue,"getEntrySource");function Kr(e){return!e||typeof e=="string"?"":String(e.branch||"").trim()}l(Kr,"getEntryBranch");function ce(e){if(!e||typeof e=="string")return{};const r={},o=Ue(e),n=He(e),a=Kr(e),i=G(e)||de(e);return(o==="local"||o==="github"||o==="mounted")&&(r.source=o),n&&(r.repoFull=n),a&&(r.branch=a),i&&(r.path=i),r}l(ce,"buildEntryScope");function de(e){return e?typeof e=="string"?String(e).trim():String(e.name||"").trim():""}l(de,"getEntryName");function G(e){if(!e)return"";if(typeof e=="string")return E(String(e).trim());const r=String(e.path||e.name||"").trim();return E(r||ye(e))}l(G,"getEntryModelPath");function Y(e){const r=Ue(e),o=He(e),n=typeof e=="string"?de(e):G(e)||de(e),a=o?`${o}::${n}`:n;return r?`${r}::${a}`:a}l(Y,"getEntryCacheKey");function Ce(e){return Y(e)}l(Ce,"getEntrySelectionKey");function Qe(){const e=new Map;for(const o of Array.isArray(t.allRecords)?t.allRecords:[]){const n=Ce(o);n&&(e.has(n)||e.set(n,o))}t.entryByKey=e;const r=new Set;for(const o of t.selectedEntryKeys)e.has(o)&&r.add(o);t.selectedEntryKeys=r}l(Qe,"rebuildEntryLookup");function Hr(){const e=[];for(const r of t.selectedEntryKeys){const o=t.entryByKey.get(r);o&&e.push(o)}return e}l(Hr,"getSelectedEntries");function we({rerender:e=!0}={}){t.selectedEntryKeys.size&&(t.selectedEntryKeys=new Set,e&&ue())}l(we,"clearSelectedEntries");function _t(e,{rerender:r=!0}={}){const o=Ce(e);if(!o)return;t.selectedEntryKeys.has(o)?t.selectedEntryKeys.delete(o):t.selectedEntryKeys.add(o),r&&ue()}l(_t,"toggleEntrySelected");function Me(e){const r=Ce(e);return!!r&&t.selectedEntryKeys.has(r)}l(Me,"isEntrySelected");function Ur(e=!1){const r=Array.isArray(t.visibleExplorerEntryKeys)?t.visibleExplorerEntryKeys:[];if(!r.length)return;const o=e?new Set(t.selectedEntryKeys):new Set;for(const n of r)!n||!t.entryByKey.has(n)||o.add(n);t.selectedEntryKeys=o,ue()}l(Ur,"selectVisibleExplorerEntries");function qr(e){if(!e)return!1;const r=String(e.tagName||"").toLowerCase();return!!(r==="input"||r==="textarea"||r==="select"||e.isContentEditable)}l(qr,"isTextInputElement");function Ae(e,r){const o=Array.from(document.querySelectorAll(".hub-explorer .hub-browser-file-entry"));if(!o.length)return;const n=o.indexOf(e);if(n<0)return;const a=Math.max(0,Math.min(o.length-1,n+Number(r||0))),i=o[a];i&&typeof i.focus=="function"&&i.focus({preventScroll:!1})}l(Ae,"focusExplorerFileItemByDelta");function zr(e,r,o){!e||!r||typeof o!="function"||e.addEventListener("keydown",n=>{if(!n.defaultPrevented){if(n.key==="Enter"){n.preventDefault(),o(n);return}if(n.key===" "){n.preventDefault(),_t(r);return}if(n.key==="ArrowDown"){n.preventDefault(),Ae(e,1);return}if(n.key==="ArrowUp"){n.preventDefault(),Ae(e,-1);return}if(n.key==="ArrowRight"&&t.explorerViewMode==="icons"){n.preventDefault(),Ae(e,1);return}n.key==="ArrowLeft"&&t.explorerViewMode==="icons"&&(n.preventDefault(),Ae(e,-1))}})}l(zr,"bindExplorerFileKeyboard");function Gr(e,{tile:r=!1}={}){const o=document.createElement("button");return o.type="button",o.className=`hub-select-toggle${r?" is-tile":""}${Me(e)?" is-selected":""}`,o.setAttribute("aria-label",Me(e)?"Unselect file":"Select file"),o.textContent=Me(e)?"✓":"○",o.addEventListener("click",n=>{n.preventDefault(),n.stopPropagation(),_t(e)}),o}l(Gr,"createSelectionToggle");function z(e=""){const r=String(e||"").trim();if(!r)return!1;for(const o of Array.isArray(t.repoCache)?t.repoCache:[])if(String(o?.full_name||"").trim()===r)return!!(o?.permissions&&o.permissions.push===!1);return!1}l(z,"getRepoReadOnlyStatus");function Vr(e,r="",o=""){return{source:F(e),repoFull:String(r||"").trim(),path:E(o)}}l(Vr,"createEntryDropTarget");function Nt(e){const r=F(e?.source),o=String(e?.repoFull||"").trim(),n=E(e?.path||""),a=[me(r,o)];return n&&a.push(n),a.join(" / ")}l(Nt,"getDropTargetLabel");async function Bt(e,r,{refresh:o=!0}={}){if(D())return{imported:0,skipped:0,failed:0};const n=Array.isArray(e)?e.filter(Boolean):[];if(!n.length)return{imported:0,skipped:0,failed:0};const a=Ot(r,null),i=E(r?.path||""),s=Nt(r),c=F(a.source||"local"),u=String(a.repoFull||"").trim(),y=c==="local";if(ke(c,u)||X(i))return w("Cannot import files into Trash.","warn"),{imported:0,skipped:n.length,failed:0};if(c!=="local"&&!u)return w("Select a valid destination folder before dropping files.","warn"),{imported:0,skipped:n.length,failed:0};if(c==="github"&&!String(oe()?.token||"").trim())return w("Set a GitHub token in Settings before importing files into repositories.","warn"),{imported:0,skipped:n.length,failed:0};if(c==="github"&&z(u))return w(`Repository "${u}" is read-only.`,"warn"),{imported:0,skipped:n.length,failed:0};let d=0,p=0,m=0;w(`Importing ${n.length} file${n.length===1?"":"s"}...`,"info");try{await se("Importing desktop files...",async({setMessage:b})=>{for(let f=0;f<n.length;f+=1){const g=n[f],v=String(g?.name||"").trim()||`file-${f+1}`;b("Importing desktop files...",`${f+1}/${n.length} - ${v}`);try{const R=await Qt(g,{allowJson:y}),C=E(R?.baseName||"");if(!R?.record||!C){p+=1;continue}const P=E(i?`${i}/${C}`:C);if(!P){p+=1;continue}const k={...a,source:c,repoFull:u,path:P};if(await V(P,k)&&!await confirm(`"${P}" already exists in ${s}. Overwrite it?`)){p+=1;continue}await fe(P,R.record,k),d+=1}catch{m+=1}}o&&(b("Refreshing file index...","Updating folder and file listing..."),await B(),await U())},{detail:`Target: ${s}`})}catch(b){return w(`Desktop import failed: ${H(b)}`,"error"),{imported:d,skipped:p,failed:m+1}}return!d&&!m?(w(`No supported files were imported. Drop ${y?".3mf or .json":".3mf"} files.`,"warn"),{imported:d,skipped:p,failed:m}):(m?w(`Import complete: ${d} imported, ${m} failed, ${p} skipped.`,"warn"):w(`Imported ${d} file${d===1?"":"s"} to "${s}".${p?` (${p} skipped)`:""}`,"ok"),{imported:d,skipped:p,failed:m})}l(Bt,"importDesktopFilesToFolder");function jr(){const e=Array.isArray(t.dragEntryKeys)?t.dragEntryKeys:[],r=[],o=new Set;for(const n of e){if(!n||o.has(n))continue;o.add(n);const a=t.entryByKey.get(n);a&&r.push(a)}return r}l(jr,"getActiveDragEntries");function It(e,r){!e||!r||(e.draggable=!0,e.addEventListener("dragstart",o=>{if(D()){o.preventDefault();return}const n=Ce(r);if(!n){o.preventDefault();return}const i=(t.selectedEntryKeys.has(n)?Array.from(t.selectedEntryKeys):[n]).filter(s=>t.entryByKey.has(s));if(!i.length){o.preventDefault();return}t.dragEntryKeys=i,e.classList.add("is-dragging"),o.dataTransfer&&(o.dataTransfer.effectAllowed="copyMove",o.dataTransfer.setData("text/plain",i.join(`
|
|
137
|
+
`)))}),e.addEventListener("dragend",()=>{t.dragEntryKeys=[],e.classList.remove("is-dragging"),document.querySelectorAll(".hub-drop-target.is-drop-active").forEach(o=>{o.classList.remove("is-drop-active")})}))}l(It,"bindDragSource");function Xr(e,r){if(!e||!r)return;let o=0;e.classList.add("hub-drop-target");const n=l(()=>e.classList.add("is-drop-active"),"markActive"),a=l(()=>{o=0,e.classList.remove("is-drop-active")},"clearActive");e.addEventListener("dragenter",i=>{D()||t.dragEntryKeys.length&&(i.preventDefault(),o+=1,n())}),e.addEventListener("dragover",i=>{if(!D()&&t.dragEntryKeys.length){if(i.preventDefault(),i.dataTransfer){const s=!!(i.altKey||i.ctrlKey||i.metaKey);i.dataTransfer.dropEffect=s?"copy":"move"}n()}}),e.addEventListener("dragleave",()=>{D()||t.dragEntryKeys.length&&(o=Math.max(0,o-1),o||e.classList.remove("is-drop-active"))}),e.addEventListener("drop",i=>{if(D()){i.preventDefault(),i.stopPropagation();return}const s=jr();if(t.dragEntryKeys=[],a(),!s.length)return;i.preventDefault(),i.stopPropagation();const c=!!(i.altKey||i.ctrlKey||i.metaKey);Jr(s,r,{copy:c,confirm:!0})})}l(Xr,"bindDropTarget");function Yr(e){const r=G(e);if(!r)return"";const o=r.split("/").filter(Boolean);return o[o.length-1]||r}l(Yr,"getEntryPathBaseName");function Wt(e){const r=E(e||"");if(!X(r))return"";const o=r.split("/").filter(Boolean);if(!o.length||o[0]!==Ee)return"";const n=o.slice(1);return n.length?E(n.join("/")):""}l(Wt,"getRestorePathFromTrashPath");function Ot(e,r=null){const o=F(e?.source),n=String(e?.repoFull||"").trim(),a=String(oe()?.branch||"").trim(),i={source:o,repoFull:n};if(o==="github"){const s=String(r?.branch||"").trim();s?i.branch=s:a&&(i.branch=a)}return i}l(Ot,"getTargetScopeForWrite");async function Jr(e,r,{copy:o=!1,confirm:n=!0}={}){if(D())return;const a=Array.isArray(e)?e.filter(Boolean):[];if(!a.length)return;const i=Ot(r,a[0]),s=E(r?.path||""),c=Nt(r),u=o?"Copy":"Move";if(i.source==="github"&&z(i.repoFull)){w(`Cannot ${o?"copy into":"move into"} read-only repository "${i.repoFull}".`,"warn");return}if(n&&!await confirm(`${u} ${a.length} file${a.length===1?"":"s"} to "${c}"?`))return;let y=0,d=0,p=0;w(`${u} in progress...`,"info");try{await se(`${u} files...`,async({setMessage:m})=>{for(let b=0;b<a.length;b+=1){const f=a[b],g=G(f);if(m(`${u} files...`,`${b+1}/${a.length} - ${g||de(f)||"Unknown file"}`),!g){d+=1;continue}if(X(g)){d+=1;continue}const v={...ce(f),path:g},R=F(f?.source),C=String(f?.repoFull||"").trim(),P=Yr(f),k=E(s?`${s}/${P}`:P);if(!k){d+=1;continue}if(R===i.source&&C===String(i.repoFull||"").trim()&&g===k){d+=1;continue}if(!o&&R==="github"&&z(C)){d+=1;continue}try{const x=await V(g,v);if(!x||!x.data3mf){p+=1;continue}const _={...i,path:k};if(await V(k,_)&&!await confirm(`"${k}" already exists in ${c}. Overwrite it?`)){d+=1;continue}await fe(k,{savedAt:new Date().toISOString(),data3mf:x.data3mf,data:x.data,thumbnail:x.thumbnail||null},_),o||(await pe(g,v),t.thumbCache.delete(Y(f))),y+=1}catch{p+=1}}we({rerender:!1}),m("Refreshing file index...","Updating folder and file listing..."),await B(),await U()},{detail:`Target: ${c}`})}catch(m){w(`${u} failed: ${H(m)}`,"error");return}p?w(`${u} complete: ${y} succeeded, ${p} failed, ${d} skipped.`,"warn"):w(`${u} complete: ${y} succeeded, ${d} skipped.`,"ok")}l(Jr,"relocateEntries");async function Kt(e,{confirm:r=!0,folderEntries:o=[]}={}){if(D())return;const n=Array.isArray(e)?e.filter(Boolean):[],a=Array.isArray(o)?o.filter(Boolean):[];if(!n.length&&!a.length)return;const i=n.length===1?"Delete file permanently":n.length?`Delete ${n.length} files permanently`:"Empty Trash permanently";if(r&&!await confirm(`${i}?
|
|
138
|
+
|
|
139
|
+
This cannot be undone.`))return;let s=0,c=0,u=0;const y=Oe(n,a);w("Deleting permanently...","info");try{await se("Deleting permanently...",async({setMessage:d})=>{for(let b=0;b<n.length;b+=1){const f=n[b],g=G(f);if(d("Deleting permanently...",`${b+1}/${n.length} - ${g||de(f)||"Unknown file"}`),!g||!X(g)){u+=1;continue}const v=F(f?.source),R=String(f?.repoFull||"").trim();if(v==="github"&&z(R)){u+=1;continue}const C={...ce(f),path:g};try{await pe(g,C),t.thumbCache.delete(Y(f)),s+=1}catch{c+=1}}const p=a.slice().sort((b,f)=>String(f?.path||"").length-String(b?.path||"").length);for(let b=0;b<p.length;b+=1){const f=p[b],g=E(f?.path||"");if(!g||!X(g))continue;const v=F(f?.source||"local"),R=String(f?.repoFull||"").trim();if(!(v==="github"&&z(R))){d("Deleting permanently...",`Cleaning folder marker ${b+1}/${p.length}: ${g}`);try{await Re(g,be(v,R))}catch{}}}we({rerender:!1}),d("Refreshing file index...","Updating folder and file listing..."),await B(),await U(),await Ke(y,{setMessage:d})>0&&(d("Refreshing file index...","Finalizing Trash folder cleanup..."),await B(),await U())},{detail:`Items: ${n.length}`})}catch(d){w(`Permanent delete failed: ${H(d)}`,"error");return}c?w(`Permanent delete complete: ${s} succeeded, ${c} failed, ${u} skipped.`,"warn"):w(`Deleted ${s} file${s===1?"":"s"} permanently.`,"ok")}l(Kt,"permanentlyDeleteEntries");async function Zr(e,{confirm:r=!0}={}){if(D())return;const o=Array.isArray(e)?e.filter(Boolean):[];if(!o.length)return;const n=o.length===1?"Restore file":`Restore ${o.length} files`;if(r&&!await confirm(`${n} from Trash?`))return;let a=0,i=0,s=0;const c=Oe(o,[]);w("Restoring files from Trash...","info");try{await se("Restoring files from Trash...",async({setMessage:u})=>{for(let d=0;d<o.length;d+=1){const p=o[d],m=G(p);if(u("Restoring files from Trash...",`${d+1}/${o.length} - ${m||de(p)||"Unknown file"}`),!m||!X(m)){s+=1;continue}const b=Wt(m);if(!b){s+=1;continue}const f=F(p?.source),g=String(p?.repoFull||"").trim();if(f==="github"&&z(g)){s+=1;continue}const v={...ce(p),path:m},R={...ce(p),path:b};try{const C=await V(m,v);if(!C||!C.data3mf){i+=1;continue}if(await V(b,R)&&!await confirm(`"${b}" already exists. Overwrite it?`)){s+=1;continue}await fe(b,{savedAt:new Date().toISOString(),data3mf:C.data3mf,data:C.data,thumbnail:C.thumbnail||null},R),await pe(m,v);const k=Y(p),A=Y({source:f,repoFull:g,name:b}),x=t.thumbCache.get(k);x&&t.thumbCache.set(A,x),t.thumbCache.delete(k),a+=1}catch{i+=1}}we({rerender:!1}),u("Refreshing file index...","Updating folder and file listing..."),await B(),await U(),await Ke(c,{setMessage:u})>0&&(u("Refreshing file index...","Finalizing Trash folder cleanup..."),await B(),await U())},{detail:`Items: ${o.length}`})}catch(u){w(`Restore failed: ${H(u)}`,"error");return}i?w(`Restore complete: ${a} succeeded, ${i} failed, ${s} skipped.`,"warn"):w(`Restored ${a} file${a===1?"":"s"} from Trash.`,"ok")}l(Zr,"restoreEntries");async function Ht(e,{confirm:r=!0}={}){if(D())return;const o=Array.isArray(e)?e.filter(Boolean):[];if(!o.length)return;const n=o.length===1?"Move file to Trash":`Move ${o.length} files to Trash`;if(r&&!await confirm(`${n}?`))return;let a=0,i=0,s=0;w("Moving files to Trash...","info");try{await se("Moving files to Trash...",async({setMessage:c})=>{for(let u=0;u<o.length;u+=1){const y=o[u],d=G(y);c("Moving files to Trash...",`${u+1}/${o.length} - ${d||de(y)||"Unknown file"}`);const p=F(y?.source),m=String(y?.repoFull||"").trim();if(p==="github"&&z(m)){s+=1;continue}if(!d){s+=1;continue}if(X(d)){s+=1;continue}const b={...ce(y),path:d},f=E(`${Ee}/${d}`);if(!f){s+=1;continue}const g={...b,path:f};try{const v=await V(d,b);if(!v||!v.data3mf){i+=1;continue}if(await V(f,g)&&!await confirm(`"${f}" already exists in Trash. Overwrite it?`)){s+=1;continue}await fe(f,{savedAt:new Date().toISOString(),data3mf:v.data3mf,data:v.data,thumbnail:v.thumbnail||null},g),await pe(d,b),t.thumbCache.delete(Y(y)),a+=1}catch{i+=1}}we({rerender:!1}),c("Refreshing file index...","Updating folder and file listing..."),await B(),await U()},{detail:`Items: ${o.length}`})}catch(c){w(`Trash move failed: ${H(c)}`,"error");return}i?w(`Trash move complete: ${a} succeeded, ${i} failed, ${s} skipped.`,"warn"):w(`Moved ${a} file${a===1?"":"s"} to Trash.`,"ok")}l(Ht,"moveEntriesToTrash");async function Qr(e,r){if(!r||!e)return;const o=Y(e);if(e?.record?.thumbnail){r.src=e.record.thumbnail,t.thumbCache.set(o,e.record.thumbnail);return}if(t.thumbCache.has(o)){const n=t.thumbCache.get(o);if(n){r.src=n;return}}}l(Qr,"hydrateThumbnail");async function eo(e){if(D())return;const r=G(e)||de(e),o=Ue(e),n=He(e),a=ce(e),i=await V(r,a);if(!i){w(`File not found: ${r}`,"warn");return}let s=await prompt("Rename file",r)||"";if(s=s.trim(),!(!s||s===r||await V(s,{...a,path:s})&&!await confirm(`"${s}" already exists. Overwrite it?`)))try{await se(`Renaming "${r}"...`,async({setMessage:u})=>{u(`Renaming "${r}"...`,`Writing ${s}`),await fe(s,{savedAt:i.savedAt||new Date().toISOString(),data3mf:i.data3mf,data:i.data,thumbnail:i.thumbnail||null},{...a,path:s}),await pe(r,a);const y=Y({source:o,name:r,repoFull:n}),d=Y({source:o,name:s,repoFull:n}),p=t.thumbCache.get(y);p&&(t.thumbCache.set(d,p),t.thumbCache.delete(y)),u("Refreshing file index...","Updating folder and file listing..."),await B(),await U()}),w(`Renamed "${r}" to "${s}".`,"ok")}catch(u){w(`Rename failed: ${H(u)}`,"error")}}l(eo,"renameFile");async function to(e){if(D())return;const r=G(e)||de(e),o=Ue(e),n=He(e),a=ce(e),i=await V(r,a);if(!i){w(`File not found: ${r}`,"warn");return}let s=await prompt("Duplicate as",`${r} copy`)||"";if(s=s.trim(),!(!s||await V(s,{...a,path:s})&&!await confirm(`"${s}" already exists. Overwrite it?`)))try{await se(`Duplicating "${r}"...`,async({setMessage:u})=>{u(`Duplicating "${r}"...`,`Writing ${s}`),await fe(s,{savedAt:new Date().toISOString(),data3mf:i.data3mf,data:i.data,thumbnail:i.thumbnail||t.thumbCache.get(Y({source:o,name:r,repoFull:n}))||null},{...a,path:s}),u("Refreshing file index...","Updating folder and file listing..."),await B(),await U()}),w(`Duplicated "${r}" to "${s}".`,"ok")}catch(u){w(`Duplicate failed: ${H(u)}`,"error")}}l(to,"duplicateFile");function Fe(){if(!t.storageBadgeEl)return;const e=oe(),r=Q(t.selectedRepoFulls?.length?t.selectedRepoFulls:e?.repoFulls||e?.repoFull||""),o=!!String(e?.token||"").trim()&&r.length>0,n=(Array.isArray(t.mountedDirectories)?t.mountedDirectories:[]).length,a=["Local Browser"];n>0&&a.push(`Mounted ${n}`),o&&a.push(`GitHub ${r.length}`),t.storageBadgeEl.textContent=`Storage: Per-file (${a.join(" + ")})`}l(Fe,"refreshStorageBadge");function w(e,r="info",o=!1){if(t.filesStatusEl){if(o||!e){t.filesStatusEl.hidden=!0,t.filesStatusEl.textContent="",t.filesStatusEl.dataset.tone="";return}t.filesStatusEl.hidden=!1,t.filesStatusEl.textContent=e,t.filesStatusEl.dataset.tone=r}}l(w,"setFilesStatus");function K(e,r="info",o=!1){if(t.workspaceStatusEl){if(o||!e){t.workspaceStatusEl.hidden=!0,t.workspaceStatusEl.textContent="",t.workspaceStatusEl.dataset.tone="";return}t.workspaceStatusEl.hidden=!1,t.workspaceStatusEl.textContent=e,t.workspaceStatusEl.dataset.tone=r}}l(K,"setWorkspaceStatus");function Le(e,r="info",o=!1){if(t.settingsStatusEl){if(o||!e){t.settingsStatusEl.hidden=!0,t.settingsStatusEl.textContent="",t.settingsStatusEl.dataset.tone="";return}t.settingsStatusEl.hidden=!1,t.settingsStatusEl.textContent=e,t.settingsStatusEl.dataset.tone=r}}l(Le,"setSettingsStatus");function H(e){return e?typeof e=="string"?e:typeof e.message=="string"&&e.message.trim()?e.message.trim():String(e):"Unknown error"}l(H,"errorMessage");
|