@hienlh/ppm 0.13.62 → 0.13.64
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/CHANGELOG.md +11 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +2 -1
- package/bun.lock +2170 -0
- package/bunfig.toml +2 -0
- package/dist/web/assets/audio-preview-Bog1sIoF.js +1 -0
- package/dist/web/assets/{chat-tab-nNh5rLB2.js → chat-tab-B-uVAh4d.js} +7 -7
- package/dist/web/assets/code-editor-cDv3opsJ.js +8 -0
- package/dist/web/assets/{conflict-editor-B4f2ilts.js → conflict-editor-D5sEfbcX.js} +3 -3
- package/dist/web/assets/database-viewer-BGBVsG5J.js +1 -0
- package/dist/web/assets/diff-viewer-B-O1mvHO.js +4 -0
- package/dist/web/assets/docx-preview-ByzSlSgn.js +12 -0
- package/dist/web/assets/{extension-webview-CUPyfczi.js → extension-webview-0qfU1r7z.js} +1 -1
- package/dist/web/assets/git-log-panel-C1T8bav0.js +1 -0
- package/dist/web/assets/{glide-data-grid-1rBqhi2J.js → glide-data-grid-DV8ht1BP.js} +3 -3
- package/dist/web/assets/image-preview-Dbo7SAVb.js +1 -0
- package/dist/web/assets/{index-DwvSM9vu.css → index-BuXdQZjD.css} +1 -1
- package/dist/web/assets/index-DU_JZ5MY.js +27 -0
- package/dist/web/assets/keybindings-store-0FUOwc9I.js +1 -0
- package/dist/web/assets/{markdown-renderer-BS-EgLZm.js → markdown-renderer-D-QbsfIC.js} +1 -1
- package/dist/web/assets/notification-store-bwd1UKbs.js +1 -0
- package/dist/web/assets/pdf-preview-DV96VPTb.js +1 -0
- package/dist/web/assets/port-forwarding-tab-C4OYC71C.js +1 -0
- package/dist/web/assets/{postgres-viewer-BZ7RHn6E.js → postgres-viewer-hb-_twEU.js} +2 -2
- package/dist/web/assets/{settings-tab-B3U6o2Cv.js → settings-tab-BUCIqVAl.js} +1 -1
- package/dist/web/assets/sql-query-editor-C7YgtDR3.js +3 -0
- package/dist/web/assets/sqlite-viewer-z3pGFSje.js +1 -0
- package/dist/web/assets/system-monitor-tab-Bj6pcRmV.js +1 -0
- package/dist/web/assets/{terminal-tab-BEGaXjCj.js → terminal-tab-DbxLHofN.js} +2 -2
- package/dist/web/assets/video-preview-DylSBAzo.js +1 -0
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/docs/codebase-summary.md +2 -1
- package/docs/project-changelog.md +10 -1
- package/package.json +2 -1
- package/src/index.ts +0 -0
- package/src/server/routes/files.ts +20 -0
- package/src/server/routes/fs-browse.ts +16 -0
- package/src/web/components/database/database-viewer.tsx +13 -2
- package/src/web/components/database/sql-query-editor.tsx +8 -10
- package/src/web/components/editor/code-editor.tsx +5 -2
- package/src/web/components/editor/docx-preview.tsx +92 -0
- package/src/web/components/layout/command-palette-filter-chips.tsx +61 -0
- package/src/web/components/layout/command-palette.tsx +54 -7
- package/dist/web/assets/audio-preview-B3rIhhbi.js +0 -1
- package/dist/web/assets/code-editor-CMSwWKuR.js +0 -8
- package/dist/web/assets/database-viewer-D-28-BdV.js +0 -1
- package/dist/web/assets/diff-viewer-Bv8DUUIR.js +0 -4
- package/dist/web/assets/git-log-panel-CFLQD23g.js +0 -1
- package/dist/web/assets/image-preview-DHrZPetH.js +0 -1
- package/dist/web/assets/index-CkQX29w3.js +0 -27
- package/dist/web/assets/keybindings-store-Bigfs0Ss.js +0 -1
- package/dist/web/assets/notification-store-NXr7Mag_.js +0 -1
- package/dist/web/assets/pdf-preview-CeN9W7kd.js +0 -1
- package/dist/web/assets/port-forwarding-tab-CYUcx2_j.js +0 -1
- package/dist/web/assets/sql-query-editor-CfDG3duv.js +0 -3
- package/dist/web/assets/sqlite-viewer-ofYBAsHX.js +0 -1
- package/dist/web/assets/system-monitor-tab-By-j_TO1.js +0 -1
- package/dist/web/assets/video-preview-CHOiQ3I9.js +0 -1
- /package/dist/web/assets/{vendor-xterm-t3d5xZdz.js → vendor-xterm-msgiskDb.js} +0 -0
package/dist/web/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
try{self[`workbox:core:7.3.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.3.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.3.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.3.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&!(t.origin!==location.origin&&n.index!==0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}function B(e){O().precache(e)}function V(e,t){B(e),z(t)}V([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"307b67ad2eab6a465427cd64440bbe8a","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/react-CfveccaI.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/api-settings-uQKmeGkl.js"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/project-store-BnvrVKBw.js"},{"revision":null,"url":"assets/table-2wDtM4_B.js"},{"revision":null,"url":"assets/sql-query-editor-CfDG3duv.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-Ar00Wbhd.js"},{"revision":null,"url":"assets/arrow-down-D825m4vm.js"},{"revision":null,"url":"assets/use-blob-url-DCUIEzjB.js"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/settings-tab-B3U6o2Cv.js"},{"revision":null,"url":"assets/notification-store-NXr7Mag_.js"},{"revision":null,"url":"assets/chevron-down-BMo4cBth.js"},{"revision":null,"url":"assets/dist-DeY41KFi.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-Q4ssDdib.js"},{"revision":null,"url":"assets/github.min-D2BCvnWf.css"},{"revision":null,"url":"assets/radar-KQ55EAFF-kq5v4OKX.js"},{"revision":null,"url":"assets/system-monitor-tab-By-j_TO1.js"},{"revision":null,"url":"assets/settings-store-CSDOihqv.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/info-3K5VOQVL-CWKw4e0V.js"},{"revision":null,"url":"assets/glide-data-grid-nthEL3fk.css"},{"revision":null,"url":"assets/esm-JPvheKDJ.js"},{"revision":null,"url":"assets/lib-DrypSCq8.js"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/panel-store-B1pOXkyS.js"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/wifi-LJEyIdXf.js"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/database-viewer-D-28-BdV.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/pdf-preview-CeN9W7kd.js"},{"revision":null,"url":"assets/chevron-right-CD8e6Aj4.js"},{"revision":null,"url":"assets/vendor-mermaid-DCie7hiR.js"},{"revision":null,"url":"assets/video-preview-CHOiQ3I9.js"},{"revision":null,"url":"assets/port-forwarding-tab-CYUcx2_j.js"},{"revision":null,"url":"assets/trash-2-DkIfBY8d.js"},{"revision":null,"url":"assets/text-wrap-AZErifCu.js"},{"revision":null,"url":"assets/conflict-editor-B4f2ilts.js"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/globe-CQ8NAYvi.js"},{"revision":null,"url":"assets/utils-E0yyGxXt.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/use-monaco-theme-qx6SfVRk.js"},{"revision":null,"url":"assets/input-B78ol0hV.js"},{"revision":null,"url":"assets/code-DiNmA3eR.js"},{"revision":null,"url":"assets/refresh-cw-CRD2qr4U.js"},{"revision":null,"url":"assets/postgres-viewer-BZ7RHn6E.js"},{"revision":null,"url":"assets/search-D90WJ5fo.js"},{"revision":null,"url":"assets/vendor-ui-UXCWAcmi.js"},{"revision":null,"url":"assets/terminal-tab-BEGaXjCj.js"},{"revision":null,"url":"assets/file-exclamation-point-B__2Hrd6.js"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/data-grid-types-C29KDkZJ.js"},{"revision":null,"url":"assets/katex-DUj5OG1J.js"},{"revision":null,"url":"assets/index-DwvSM9vu.css"},{"revision":null,"url":"assets/github-dark-dimmed.min-BrpRStFV.css"},{"revision":null,"url":"assets/number-overlay-editor-DS-qf63L.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2"},{"revision":null,"url":"assets/KaTeX_Script-Regular-D3wIWfF6.woff2"},{"revision":null,"url":"assets/arrow-up-Rcw6_KKu.js"},{"revision":null,"url":"assets/ai-settings-section-BH2UOQH-.js"},{"revision":null,"url":"assets/database-Dc8mr-dP.js"},{"revision":null,"url":"assets/eye-off-BacF7RVS.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/index-CkQX29w3.js"},{"revision":null,"url":"assets/keybindings-store-Bigfs0Ss.js"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/vendor-xterm-t3d5xZdz.js"},{"revision":null,"url":"assets/image-preview-DHrZPetH.js"},{"revision":null,"url":"assets/api-client-DiZgVOok.js"},{"revision":null,"url":"assets/chat-tab-nNh5rLB2.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/x-DfF6D5Js.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-DChODgHt.js"},{"revision":null,"url":"assets/diff-viewer-Bv8DUUIR.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/data-grid-overlay-editor-CmduzuPM.js"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-2a0r4GHr.js"},{"revision":null,"url":"assets/markdown-renderer-BS-EgLZm.js"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/code-editor-CMSwWKuR.js"},{"revision":null,"url":"assets/audio-preview-B3rIhhbi.js"},{"revision":null,"url":"assets/sparkles-KCOEy7QI.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-DLKD1Xjj.js"},{"revision":null,"url":"assets/csv-parser-D8VHWVA6.js"},{"revision":null,"url":"assets/csv-preview-DgArUJhd.js"},{"revision":null,"url":"assets/tab-store-DzftzxTL.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/git-log-panel-CFLQD23g.js"},{"revision":null,"url":"assets/extension-webview-CUPyfczi.js"},{"revision":null,"url":"assets/glide-data-grid-1rBqhi2J.js"},{"revision":null,"url":"assets/dist-PPUhQONj.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":null,"url":"assets/sqlite-viewer-ofYBAsHX.js"},{"revision":"d0f94ce046cf8cf09605ee7664dac557","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"a424156a79b9c1b907db93aa3180585a","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"b3a7f967560c9816492a1567b3f7f0dc","url":"monacoeditorwork/css.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"26dccd02a2ef7522892015154f5e3680","url":"manifest.webmanifest"}]),self.addEventListener(`push`,e=>{e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{if(t.some(e=>e.visibilityState===`visible`))return;let n=e.data?.json()??{title:`PPM`,body:`Chat completed`};return self.registration.showNotification(n.title,{body:n.body,icon:`/icon-192.svg`,badge:`/icon-192.svg`,tag:`ppm-chat-done`,silent:!1,data:{url:self.location.origin}})}))}),self.addEventListener(`notificationclick`,e=>{e.notification.close(),e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{for(let e of t)if(e.url.includes(self.location.origin)&&`focus`in e)return e.focus();return self.clients.openWindow(e.notification.data?.url||`/`)}))});
|
|
1
|
+
try{self[`workbox:core:7.3.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.3.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.3.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.3.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&!(t.origin!==location.origin&&n.index!==0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}function B(e){O().precache(e)}function V(e,t){B(e),z(t)}V([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"df3ac56b54813e3e0cd57f64f3c6ce7f","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/vendor-xterm-msgiskDb.js"},{"revision":null,"url":"assets/react-CfveccaI.js"},{"revision":null,"url":"assets/extension-webview-0qfU1r7z.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/api-settings-uQKmeGkl.js"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/project-store-BnvrVKBw.js"},{"revision":null,"url":"assets/sqlite-viewer-z3pGFSje.js"},{"revision":null,"url":"assets/keybindings-store-0FUOwc9I.js"},{"revision":null,"url":"assets/table-2wDtM4_B.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-Ar00Wbhd.js"},{"revision":null,"url":"assets/arrow-down-D825m4vm.js"},{"revision":null,"url":"assets/notification-store-bwd1UKbs.js"},{"revision":null,"url":"assets/markdown-renderer-D-QbsfIC.js"},{"revision":null,"url":"assets/use-blob-url-DCUIEzjB.js"},{"revision":null,"url":"assets/settings-tab-BUCIqVAl.js"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/conflict-editor-D5sEfbcX.js"},{"revision":null,"url":"assets/chevron-down-BMo4cBth.js"},{"revision":null,"url":"assets/dist-DeY41KFi.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-Q4ssDdib.js"},{"revision":null,"url":"assets/github.min-D2BCvnWf.css"},{"revision":null,"url":"assets/radar-KQ55EAFF-kq5v4OKX.js"},{"revision":null,"url":"assets/settings-store-CSDOihqv.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/info-3K5VOQVL-CWKw4e0V.js"},{"revision":null,"url":"assets/glide-data-grid-nthEL3fk.css"},{"revision":null,"url":"assets/esm-JPvheKDJ.js"},{"revision":null,"url":"assets/index-BuXdQZjD.css"},{"revision":null,"url":"assets/lib-DrypSCq8.js"},{"revision":null,"url":"assets/database-viewer-BGBVsG5J.js"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/panel-store-B1pOXkyS.js"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/wifi-LJEyIdXf.js"},{"revision":null,"url":"assets/sql-query-editor-C7YgtDR3.js"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/port-forwarding-tab-C4OYC71C.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/chevron-right-CD8e6Aj4.js"},{"revision":null,"url":"assets/vendor-mermaid-DCie7hiR.js"},{"revision":null,"url":"assets/trash-2-DkIfBY8d.js"},{"revision":null,"url":"assets/text-wrap-AZErifCu.js"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/system-monitor-tab-Bj6pcRmV.js"},{"revision":null,"url":"assets/globe-CQ8NAYvi.js"},{"revision":null,"url":"assets/glide-data-grid-DV8ht1BP.js"},{"revision":null,"url":"assets/utils-E0yyGxXt.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/use-monaco-theme-qx6SfVRk.js"},{"revision":null,"url":"assets/input-B78ol0hV.js"},{"revision":null,"url":"assets/code-DiNmA3eR.js"},{"revision":null,"url":"assets/refresh-cw-CRD2qr4U.js"},{"revision":null,"url":"assets/search-D90WJ5fo.js"},{"revision":null,"url":"assets/vendor-ui-UXCWAcmi.js"},{"revision":null,"url":"assets/file-exclamation-point-B__2Hrd6.js"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/data-grid-types-C29KDkZJ.js"},{"revision":null,"url":"assets/katex-DUj5OG1J.js"},{"revision":null,"url":"assets/diff-viewer-B-O1mvHO.js"},{"revision":null,"url":"assets/github-dark-dimmed.min-BrpRStFV.css"},{"revision":null,"url":"assets/image-preview-Dbo7SAVb.js"},{"revision":null,"url":"assets/number-overlay-editor-DS-qf63L.js"},{"revision":null,"url":"assets/video-preview-DylSBAzo.js"},{"revision":null,"url":"assets/audio-preview-Bog1sIoF.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2"},{"revision":null,"url":"assets/KaTeX_Script-Regular-D3wIWfF6.woff2"},{"revision":null,"url":"assets/arrow-up-Rcw6_KKu.js"},{"revision":null,"url":"assets/ai-settings-section-BH2UOQH-.js"},{"revision":null,"url":"assets/database-Dc8mr-dP.js"},{"revision":null,"url":"assets/eye-off-BacF7RVS.js"},{"revision":null,"url":"assets/git-log-panel-C1T8bav0.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/api-client-DiZgVOok.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/x-DfF6D5Js.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-DChODgHt.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/data-grid-overlay-editor-CmduzuPM.js"},{"revision":null,"url":"assets/index-DU_JZ5MY.js"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/docx-preview-ByzSlSgn.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-2a0r4GHr.js"},{"revision":null,"url":"assets/pdf-preview-DV96VPTb.js"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/terminal-tab-DbxLHofN.js"},{"revision":null,"url":"assets/sparkles-KCOEy7QI.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-DLKD1Xjj.js"},{"revision":null,"url":"assets/code-editor-cDv3opsJ.js"},{"revision":null,"url":"assets/postgres-viewer-hb-_twEU.js"},{"revision":null,"url":"assets/csv-parser-D8VHWVA6.js"},{"revision":null,"url":"assets/csv-preview-DgArUJhd.js"},{"revision":null,"url":"assets/tab-store-DzftzxTL.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/chat-tab-B-uVAh4d.js"},{"revision":null,"url":"assets/dist-PPUhQONj.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":"d0f94ce046cf8cf09605ee7664dac557","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"a424156a79b9c1b907db93aa3180585a","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"b3a7f967560c9816492a1567b3f7f0dc","url":"monacoeditorwork/css.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"26dccd02a2ef7522892015154f5e3680","url":"manifest.webmanifest"}]),self.addEventListener(`push`,e=>{e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{if(t.some(e=>e.visibilityState===`visible`))return;let n=e.data?.json()??{title:`PPM`,body:`Chat completed`};return self.registration.showNotification(n.title,{body:n.body,icon:`/icon-192.svg`,badge:`/icon-192.svg`,tag:`ppm-chat-done`,silent:!1,data:{url:self.location.origin}})}))}),self.addEventListener(`notificationclick`,e=>{e.notification.close(),e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{for(let e of t)if(e.url.includes(self.location.origin)&&`focus`in e)return e.focus();return self.clients.openWindow(e.notification.data?.url||`/`)}))});
|
package/docs/codebase-summary.md
CHANGED
|
@@ -210,7 +210,8 @@ src/
|
|
|
210
210
|
│ │ ├── draggable-tab.tsx # Draggable tab with context menu, rename, connection color
|
|
211
211
|
│ │ ├── tab-content.tsx # Router for tab content (v0.9.85+: fallback guards)
|
|
212
212
|
│ │ ├── split-drop-overlay.tsx # Drop zone for tab splitting
|
|
213
|
-
│ │ ├── command-palette.tsx # Global command palette (Shift+Shift, DB table search)
|
|
213
|
+
│ │ ├── command-palette.tsx # Global command palette (Shift+Shift, DB table search, filter chips for Actions/Files/DB/Filesystem)
|
|
214
|
+
│ │ ├── command-palette-filter-chips.tsx # Presentational filter chip bar — group toggle buttons with count badges (hidden when ≤1 group)
|
|
214
215
|
│ │ ├── add-project-form.tsx # Modal form to add projects
|
|
215
216
|
│ │ ├── mobile-nav.tsx # Bottom navigation for mobile (v0.9.85+: fallback guards)
|
|
216
217
|
│ │ └── mobile-drawer.tsx # Mobile overlay drawer
|
|
@@ -20,9 +20,18 @@ All notable changes to PPM are documented here. Format follows [Keep a Changelog
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
## [Unreleased] — Resource Monitor, Lazy-Load File Tree + Palette Index, Session Tagging, File Compare, Draft Messages, Jira Debug Session Redesign, Frontend Memory Optimization, Git-Graph Enhancements
|
|
23
|
+
## [Unreleased] — Resource Monitor, Lazy-Load File Tree + Palette Index, Session Tagging, File Compare, Draft Messages, Jira Debug Session Redesign, Frontend Memory Optimization, Git-Graph Enhancements, Command Palette Filter Chips
|
|
24
24
|
|
|
25
25
|
### Added
|
|
26
|
+
- **Command Palette Filter Chips** — Filter palette results by type with toggle chips
|
|
27
|
+
- Chips appear above results when 2+ groups are available (Actions, Files, Database, Filesystem)
|
|
28
|
+
- Each chip shows group label, icon, and live result count for the current query
|
|
29
|
+
- Toggling a chip includes/excludes that group; multiple chips can be active simultaneously
|
|
30
|
+
- Chips hidden when only one group has results (no filtering value)
|
|
31
|
+
- Mobile-friendly: 44px touch targets, horizontally scrollable chip row
|
|
32
|
+
- Files: `command-palette-filter-chips.tsx` (new presentational component), `command-palette.tsx` (filter state + `availableGroups` + `groupCounts` + `displayItems` logic)
|
|
33
|
+
|
|
34
|
+
|
|
26
35
|
- **System Resource Monitor** — Real-time process monitoring with SSE streaming, sidebar status bar, and dedicated System Monitor tab
|
|
27
36
|
- Backend: `ResourceMonitorService` polls `ps` command every 3s, builds process tree from PPM root PID, categorizes processes (server/terminal/ai-tool/build/unknown), maintains 30-min ring buffer (600 snapshots)
|
|
28
37
|
- Backend: SSE streaming route at `GET /api/system/resources/stream` with client count cap (max 5), manual reconnect with exponential backoff
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hienlh/ppm",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.64",
|
|
4
4
|
"description": "Personal Project Manager — mobile-first web IDE with AI assistance",
|
|
5
5
|
"author": "hienlh",
|
|
6
6
|
"license": "MIT",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"js-yaml": "^4.1.1",
|
|
68
68
|
"katex": "^0.16.45",
|
|
69
69
|
"lucide-react": "^0.577.0",
|
|
70
|
+
"mammoth": "^1.12.0",
|
|
70
71
|
"mermaid": "^11.13.0",
|
|
71
72
|
"monaco-editor": "0.55.1",
|
|
72
73
|
"next-themes": "^0.4.6",
|
package/src/index.ts
CHANGED
|
File without changes
|
|
@@ -5,6 +5,7 @@ import { fileService, SecurityError, NotFoundError, ValidationError } from "../.
|
|
|
5
5
|
import { readSystemFile } from "../../services/fs-browse.service.ts";
|
|
6
6
|
import { ok, err } from "../../types/api.ts";
|
|
7
7
|
import { errorStatus } from "../helpers/error-status.ts";
|
|
8
|
+
import mammoth from "mammoth";
|
|
8
9
|
|
|
9
10
|
type Env = { Variables: { projectPath: string; projectName: string } };
|
|
10
11
|
|
|
@@ -93,6 +94,25 @@ fileRoutes.get("/raw", (c) => {
|
|
|
93
94
|
}
|
|
94
95
|
});
|
|
95
96
|
|
|
97
|
+
/** GET /files/docx-html?path=... — convert project .docx to HTML via mammoth */
|
|
98
|
+
fileRoutes.get("/docx-html", async (c) => {
|
|
99
|
+
try {
|
|
100
|
+
const projectPath = c.get("projectPath");
|
|
101
|
+
const filePath = c.req.query("path");
|
|
102
|
+
if (!filePath) return c.json(err("Missing query parameter: path"), 400);
|
|
103
|
+
|
|
104
|
+
const absPath = resolve(projectPath, filePath);
|
|
105
|
+
if (!absPath.startsWith(projectPath)) return c.json(err("Access denied"), 403);
|
|
106
|
+
if (!existsSync(absPath)) return c.json(err("File not found"), 404);
|
|
107
|
+
|
|
108
|
+
const buffer = await Bun.file(absPath).arrayBuffer();
|
|
109
|
+
const result = await mammoth.convertToHtml({ arrayBuffer: buffer });
|
|
110
|
+
return c.json(ok({ html: result.value, warnings: result.messages }));
|
|
111
|
+
} catch (e) {
|
|
112
|
+
return c.json(err((e as Error).message), errorStatus(e));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
96
116
|
/** GET /files/read?path=... */
|
|
97
117
|
fileRoutes.get("/read", (c) => {
|
|
98
118
|
try {
|
|
@@ -2,6 +2,7 @@ import { Hono } from "hono";
|
|
|
2
2
|
import { existsSync, mkdirSync, rmSync, statSync } from "fs";
|
|
3
3
|
import { resolve } from "path";
|
|
4
4
|
import { $ } from "bun";
|
|
5
|
+
import mammoth from "mammoth";
|
|
5
6
|
import {
|
|
6
7
|
browse,
|
|
7
8
|
list,
|
|
@@ -75,6 +76,21 @@ fsBrowseRoutes.get("/raw", (c) => {
|
|
|
75
76
|
}
|
|
76
77
|
});
|
|
77
78
|
|
|
79
|
+
/** GET /api/fs/docx-html?path=/some/file.docx — convert .docx to HTML via mammoth */
|
|
80
|
+
fsBrowseRoutes.get("/docx-html", async (c) => {
|
|
81
|
+
try {
|
|
82
|
+
const filePath = c.req.query("path");
|
|
83
|
+
if (!filePath) return c.json(err("path is required"), 400);
|
|
84
|
+
if (!existsSync(filePath)) return c.json(err("File not found"), 404);
|
|
85
|
+
|
|
86
|
+
const buffer = await Bun.file(filePath).arrayBuffer();
|
|
87
|
+
const result = await mammoth.convertToHtml({ arrayBuffer: buffer });
|
|
88
|
+
return c.json(ok({ html: result.value, warnings: result.messages }));
|
|
89
|
+
} catch (e) {
|
|
90
|
+
return c.json(err((e as Error).message), errorStatus(e));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
78
94
|
/** DELETE /api/fs/rmdir — delete a directory { path } */
|
|
79
95
|
fsBrowseRoutes.delete("/rmdir", async (c) => {
|
|
80
96
|
try {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState, useMemo, useEffect, useRef, useCallback } from "react";
|
|
2
2
|
import { Database, RefreshCw, GripHorizontal, Loader2 } from "lucide-react";
|
|
3
3
|
import { api } from "@/lib/api-client";
|
|
4
|
+
import { useTabStore } from "@/stores/tab-store";
|
|
4
5
|
import { useDatabase, type DbColumnInfo } from "./use-database";
|
|
5
6
|
import { SqlQueryEditor } from "./sql-query-editor";
|
|
6
7
|
import { ExportButton } from "./export-button";
|
|
@@ -21,12 +22,22 @@ function parseSqlFilters(sql: string): Record<string, string> {
|
|
|
21
22
|
interface Props { metadata?: Record<string, unknown>; tabId?: string }
|
|
22
23
|
|
|
23
24
|
/** Generic database viewer — works for any DB type via unified API */
|
|
24
|
-
export function DatabaseViewer({ metadata }: Props) {
|
|
25
|
+
export function DatabaseViewer({ metadata, tabId }: Props) {
|
|
25
26
|
const connectionId = metadata?.connectionId as number;
|
|
26
27
|
const connectionName = metadata?.connectionName as string | undefined;
|
|
27
28
|
const initialTable = metadata?.tableName as string | undefined;
|
|
28
29
|
const initialSchema = (metadata?.schemaName as string) ?? "public";
|
|
29
30
|
const initialSql = metadata?.initialSql as string | undefined;
|
|
31
|
+
const persistedSql = metadata?.currentSql as string | undefined;
|
|
32
|
+
|
|
33
|
+
// Persist SQL text to tab metadata (debounced via updateTab's built-in persist)
|
|
34
|
+
const updateTab = useTabStore((s) => s.updateTab);
|
|
35
|
+
const metadataRef = useRef(metadata);
|
|
36
|
+
metadataRef.current = metadata;
|
|
37
|
+
const handleSqlChange = useCallback((sql: string) => {
|
|
38
|
+
if (!tabId) return;
|
|
39
|
+
updateTab(tabId, { metadata: { ...metadataRef.current, currentSql: sql } });
|
|
40
|
+
}, [tabId, updateTab]);
|
|
30
41
|
|
|
31
42
|
const db = useDatabase(connectionId);
|
|
32
43
|
const [cachedTableNames, setCachedTableNames] = useState<{ name: string; schema: string }[]>([]);
|
|
@@ -183,7 +194,7 @@ export function DatabaseViewer({ metadata }: Props) {
|
|
|
183
194
|
<SqlQueryEditor
|
|
184
195
|
onExecute={handleExecuteQuery} loading={db.queryLoading}
|
|
185
196
|
defaultValue={defaultQuery} schemaInfo={schemaInfo}
|
|
186
|
-
|
|
197
|
+
onSqlChange={handleSqlChange} persistedSql={persistedSql} />
|
|
187
198
|
</div>
|
|
188
199
|
|
|
189
200
|
{/* Resize handle */}
|
|
@@ -9,8 +9,10 @@ interface SqlQueryEditorProps {
|
|
|
9
9
|
loading: boolean;
|
|
10
10
|
defaultValue?: string;
|
|
11
11
|
schemaInfo?: SchemaInfo;
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/** Called when the user edits the SQL text (for external persistence) */
|
|
13
|
+
onSqlChange?: (sql: string) => void;
|
|
14
|
+
/** Persisted SQL to restore on mount (takes priority over defaultValue if user hasn't edited) */
|
|
15
|
+
persistedSql?: string;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/** Find the SQL statement surrounding the cursor line (split by ;) */
|
|
@@ -43,13 +45,9 @@ export function getStatementAtCursor(text: string, cursorLine: number): string {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
/** Shared Monaco-based SQL query editor (editor only, no results) */
|
|
46
|
-
export function SqlQueryEditor({ onExecute, loading, defaultValue = "SELECT * FROM ", schemaInfo,
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
if (storageKey) { try { return sessionStorage.getItem(storageKey) ?? defaultValue; } catch { /* */ } }
|
|
50
|
-
return defaultValue;
|
|
51
|
-
});
|
|
52
|
-
const userEditedRef = useRef(false);
|
|
48
|
+
export function SqlQueryEditor({ onExecute, loading, defaultValue = "SELECT * FROM ", schemaInfo, onSqlChange, persistedSql }: SqlQueryEditorProps) {
|
|
49
|
+
const [query, setQuery] = useState(() => persistedSql ?? defaultValue);
|
|
50
|
+
const userEditedRef = useRef(!!persistedSql);
|
|
53
51
|
const editorRef = useRef<MonacoType.editor.IStandaloneCodeEditor | null>(null);
|
|
54
52
|
const monacoRef = useRef<typeof MonacoType | null>(null);
|
|
55
53
|
const disposableRef = useRef<MonacoType.IDisposable | null>(null);
|
|
@@ -107,7 +105,7 @@ export function SqlQueryEditor({ onExecute, loading, defaultValue = "SELECT * FR
|
|
|
107
105
|
language="sql"
|
|
108
106
|
theme={monacoTheme}
|
|
109
107
|
value={query}
|
|
110
|
-
onChange={(v) => { const val = v ?? ""; setQuery(val); userEditedRef.current = true;
|
|
108
|
+
onChange={(v) => { const val = v ?? ""; setQuery(val); userEditedRef.current = true; onSqlChange?.(val); }}
|
|
111
109
|
onMount={handleMount}
|
|
112
110
|
options={{
|
|
113
111
|
minimap: { enabled: false },
|
|
@@ -27,6 +27,7 @@ const ImagePreview = lazy(() => import("./image-preview").then((m) => ({ default
|
|
|
27
27
|
const PdfPreview = lazy(() => import("./pdf-preview").then((m) => ({ default: m.PdfPreview })));
|
|
28
28
|
const VideoPreview = lazy(() => import("./video-preview").then((m) => ({ default: m.VideoPreview })));
|
|
29
29
|
const AudioPreview = lazy(() => import("./audio-preview").then((m) => ({ default: m.AudioPreview })));
|
|
30
|
+
const DocxPreview = lazy(() => import("./docx-preview").then((m) => ({ default: m.DocxPreview })));
|
|
30
31
|
|
|
31
32
|
/** Image extensions renderable inline */
|
|
32
33
|
const IMAGE_EXTS = new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "ico"]);
|
|
@@ -87,6 +88,7 @@ export const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEdit
|
|
|
87
88
|
const ext = filePath ? getFileExt(filePath) : "";
|
|
88
89
|
const isImage = IMAGE_EXTS.has(ext);
|
|
89
90
|
const isPdf = ext === "pdf";
|
|
91
|
+
const isDocx = ext === "docx";
|
|
90
92
|
const isVideo = VIDEO_EXTS.has(ext);
|
|
91
93
|
const isAudio = AUDIO_EXTS.has(ext);
|
|
92
94
|
const isSqlite = SQLITE_EXTS.has(ext);
|
|
@@ -273,7 +275,7 @@ export const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEdit
|
|
|
273
275
|
}
|
|
274
276
|
if (!filePath) return;
|
|
275
277
|
if (!isExternalFile && !projectName) return;
|
|
276
|
-
if (isImage || isPdf || isVideo || isAudio) { setLoading(false); return; }
|
|
278
|
+
if (isImage || isPdf || isDocx || isVideo || isAudio) { setLoading(false); return; }
|
|
277
279
|
|
|
278
280
|
setLoading(true);
|
|
279
281
|
setError(null);
|
|
@@ -296,7 +298,7 @@ export const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEdit
|
|
|
296
298
|
});
|
|
297
299
|
|
|
298
300
|
return () => { if (saveTimerRef.current) clearTimeout(saveTimerRef.current); };
|
|
299
|
-
}, [filePath, projectName, isImage, isPdf, isExternalFile, isUntitled]);
|
|
301
|
+
}, [filePath, projectName, isImage, isPdf, isDocx, isExternalFile, isUntitled]);
|
|
300
302
|
|
|
301
303
|
// Real-time reload: listen for file:changed WS events, re-fetch if editor is clean
|
|
302
304
|
const unsavedRef = useRef(unsaved);
|
|
@@ -511,6 +513,7 @@ export const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEdit
|
|
|
511
513
|
|
|
512
514
|
if (isImage) return <Suspense fallback={<LoadingSpinner />}><ImagePreview filePath={filePath!} projectName={projectName!} /></Suspense>;
|
|
513
515
|
if (isPdf) return <Suspense fallback={<LoadingSpinner />}><PdfPreview filePath={filePath!} projectName={projectName!} /></Suspense>;
|
|
516
|
+
if (isDocx) return <Suspense fallback={<LoadingSpinner />}><DocxPreview filePath={filePath!} projectName={projectName} /></Suspense>;
|
|
514
517
|
if (isVideo) return <Suspense fallback={<LoadingSpinner />}><VideoPreview filePath={filePath!} projectName={projectName!} /></Suspense>;
|
|
515
518
|
if (isAudio) return <Suspense fallback={<LoadingSpinner />}><AudioPreview filePath={filePath!} projectName={projectName!} /></Suspense>;
|
|
516
519
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { Loader2, FileWarning } from "lucide-react";
|
|
3
|
+
import { api, projectUrl } from "@/lib/api-client";
|
|
4
|
+
|
|
5
|
+
interface DocxPreviewProps {
|
|
6
|
+
filePath: string;
|
|
7
|
+
projectName?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Preview .docx files by converting to HTML via mammoth on the backend */
|
|
11
|
+
export function DocxPreview({ filePath, projectName }: DocxPreviewProps) {
|
|
12
|
+
const [html, setHtml] = useState<string | null>(null);
|
|
13
|
+
const [loading, setLoading] = useState(true);
|
|
14
|
+
const [error, setError] = useState<string | null>(null);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
setLoading(true);
|
|
18
|
+
setError(null);
|
|
19
|
+
|
|
20
|
+
const isExternal = /^(\/|[A-Za-z]:[/\\])/.test(filePath);
|
|
21
|
+
const url = isExternal
|
|
22
|
+
? `/api/fs/docx-html?path=${encodeURIComponent(filePath)}`
|
|
23
|
+
: `${projectUrl(projectName!)}/files/docx-html?path=${encodeURIComponent(filePath)}`;
|
|
24
|
+
|
|
25
|
+
api
|
|
26
|
+
.get<{ html: string }>(url)
|
|
27
|
+
.then((data) => {
|
|
28
|
+
setHtml(data.html);
|
|
29
|
+
setLoading(false);
|
|
30
|
+
})
|
|
31
|
+
.catch((err) => {
|
|
32
|
+
setError(err instanceof Error ? err.message : "Failed to convert docx");
|
|
33
|
+
setLoading(false);
|
|
34
|
+
});
|
|
35
|
+
}, [filePath, projectName]);
|
|
36
|
+
|
|
37
|
+
// Re-fetch on file change events
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const handler = (e: Event) => {
|
|
40
|
+
const detail = (e as CustomEvent).detail;
|
|
41
|
+
if (detail.projectName !== projectName || detail.path !== filePath) return;
|
|
42
|
+
|
|
43
|
+
const isExternal = /^(\/|[A-Za-z]:[/\\])/.test(filePath);
|
|
44
|
+
const url = isExternal
|
|
45
|
+
? `/api/fs/docx-html?path=${encodeURIComponent(filePath)}`
|
|
46
|
+
: `${projectUrl(projectName!)}/files/docx-html?path=${encodeURIComponent(filePath)}`;
|
|
47
|
+
|
|
48
|
+
api.get<{ html: string }>(url).then((data) => setHtml(data.html)).catch(() => {});
|
|
49
|
+
};
|
|
50
|
+
window.addEventListener("file:changed", handler);
|
|
51
|
+
return () => window.removeEventListener("file:changed", handler);
|
|
52
|
+
}, [filePath, projectName]);
|
|
53
|
+
|
|
54
|
+
if (loading) {
|
|
55
|
+
return (
|
|
56
|
+
<div className="flex items-center justify-center h-full gap-2 text-text-secondary">
|
|
57
|
+
<Loader2 className="size-5 animate-spin" />
|
|
58
|
+
<span className="text-sm">Converting document...</span>
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (error) {
|
|
64
|
+
return (
|
|
65
|
+
<div className="flex flex-col items-center justify-center h-full gap-3 text-text-secondary">
|
|
66
|
+
<FileWarning className="size-10 text-text-subtle" />
|
|
67
|
+
<p className="text-sm">Failed to load document.</p>
|
|
68
|
+
<p className="text-xs text-text-subtle">{error}</p>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div className="h-full overflow-auto bg-white dark:bg-zinc-900">
|
|
75
|
+
<div
|
|
76
|
+
className="docx-preview max-w-3xl mx-auto px-6 py-8 text-sm text-foreground leading-relaxed
|
|
77
|
+
[&_table]:border-collapse [&_table]:w-full [&_table]:my-3
|
|
78
|
+
[&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1
|
|
79
|
+
[&_th]:border [&_th]:border-border [&_th]:px-2 [&_th]:py-1 [&_th]:font-semibold [&_th]:bg-muted/50
|
|
80
|
+
[&_img]:max-w-full [&_img]:h-auto [&_img]:rounded
|
|
81
|
+
[&_h1]:text-2xl [&_h1]:font-bold [&_h1]:mt-6 [&_h1]:mb-3
|
|
82
|
+
[&_h2]:text-xl [&_h2]:font-semibold [&_h2]:mt-5 [&_h2]:mb-2
|
|
83
|
+
[&_h3]:text-lg [&_h3]:font-medium [&_h3]:mt-4 [&_h3]:mb-2
|
|
84
|
+
[&_p]:my-2
|
|
85
|
+
[&_ul]:list-disc [&_ul]:pl-6 [&_ul]:my-2
|
|
86
|
+
[&_ol]:list-decimal [&_ol]:pl-6 [&_ol]:my-2
|
|
87
|
+
[&_li]:my-0.5"
|
|
88
|
+
dangerouslySetInnerHTML={{ __html: html ?? "" }}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { FileCode, Database, FolderOpen, Zap } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
/** Metadata for each command group — label and icon for the filter chip */
|
|
4
|
+
const GROUP_META: Record<string, { label: string; icon: React.ElementType }> = {
|
|
5
|
+
action: { label: "Actions", icon: Zap },
|
|
6
|
+
file: { label: "Files", icon: FileCode },
|
|
7
|
+
db: { label: "Database", icon: Database },
|
|
8
|
+
fs: { label: "Filesystem", icon: FolderOpen },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
interface CommandPaletteFilterChipsProps {
|
|
12
|
+
/** Groups that have data (stable, pre-query) */
|
|
13
|
+
availableGroups: string[];
|
|
14
|
+
/** Count of filtered results per group (updates with query) */
|
|
15
|
+
groupCounts: Record<string, number>;
|
|
16
|
+
/** Currently active filter groups */
|
|
17
|
+
activeFilters: Set<string>;
|
|
18
|
+
/** Toggle a group filter on/off */
|
|
19
|
+
onToggle: (group: string) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function CommandPaletteFilterChips({
|
|
23
|
+
availableGroups,
|
|
24
|
+
groupCounts,
|
|
25
|
+
activeFilters,
|
|
26
|
+
onToggle,
|
|
27
|
+
}: CommandPaletteFilterChipsProps) {
|
|
28
|
+
if (availableGroups.length <= 1) return null;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className="flex items-center gap-1.5 border-b border-border/50 px-3 py-1.5 overflow-x-auto">
|
|
32
|
+
{availableGroups.map((group) => {
|
|
33
|
+
const meta = GROUP_META[group];
|
|
34
|
+
if (!meta) return null;
|
|
35
|
+
const count = groupCounts[group] ?? 0;
|
|
36
|
+
const isActive = activeFilters.has(group);
|
|
37
|
+
const Icon = meta.icon;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<button
|
|
41
|
+
key={group}
|
|
42
|
+
type="button"
|
|
43
|
+
role="switch"
|
|
44
|
+
aria-checked={isActive}
|
|
45
|
+
aria-label={`Filter by ${meta.label}`}
|
|
46
|
+
onClick={() => onToggle(group)}
|
|
47
|
+
className={`inline-flex items-center gap-1 shrink-0 rounded-full border px-2.5 py-1 text-xs font-medium transition-colors ${
|
|
48
|
+
isActive
|
|
49
|
+
? "bg-accent/15 border-accent text-accent"
|
|
50
|
+
: "bg-surface border-border text-text-subtle hover:bg-surface-elevated"
|
|
51
|
+
} ${count === 0 ? "opacity-50" : ""}`}
|
|
52
|
+
>
|
|
53
|
+
<Icon className="size-3" />
|
|
54
|
+
<span>{meta.label}</span>
|
|
55
|
+
<span className="text-[10px] opacity-70">({count})</span>
|
|
56
|
+
</button>
|
|
57
|
+
);
|
|
58
|
+
})}
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -28,6 +28,7 @@ import { useCompareStore } from "@/stores/compare-store";
|
|
|
28
28
|
import { api } from "@/lib/api-client";
|
|
29
29
|
import { basename } from "@/lib/utils";
|
|
30
30
|
import { scoreFileSearchFast, compareScores, getFilename, type FileSearchScore } from "@/lib/score-file-search";
|
|
31
|
+
import { CommandPaletteFilterChips } from "@/components/layout/command-palette-filter-chips";
|
|
31
32
|
|
|
32
33
|
/** Max results to display — prevents rendering thousands of matches */
|
|
33
34
|
const MAX_RESULTS = 100;
|
|
@@ -120,6 +121,7 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
|
|
|
120
121
|
const [fsFiles, setFsFiles] = useState<string[]>([]);
|
|
121
122
|
const [fsLoading, setFsLoading] = useState(false);
|
|
122
123
|
const [dbResults, setDbResults] = useState<DbSearchResult[]>([]);
|
|
124
|
+
const [activeFilters, setActiveFilters] = useState<Set<string>>(new Set());
|
|
123
125
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
124
126
|
const listRef = useRef<HTMLDivElement>(null);
|
|
125
127
|
|
|
@@ -384,6 +386,38 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
|
|
|
384
386
|
return deferredQuery.trim().length >= 2 ? [...dbCommands, ...matched] : matched;
|
|
385
387
|
}, [searchIndex, actionCommands, fsCommands, dbCommands, deferredQuery]);
|
|
386
388
|
|
|
389
|
+
// Stable set of groups that have data (pre-query) — prevents chip flashing
|
|
390
|
+
const availableGroups = useMemo(() => {
|
|
391
|
+
const groups = new Set<string>();
|
|
392
|
+
for (const cmd of allCommands) groups.add(cmd.group);
|
|
393
|
+
if (dbResults.length > 0) groups.add("db");
|
|
394
|
+
if (fsFiles.length > 0) groups.add("fs");
|
|
395
|
+
return Array.from(groups);
|
|
396
|
+
}, [allCommands, dbResults.length, fsFiles.length]);
|
|
397
|
+
|
|
398
|
+
// Per-group counts from search-filtered results (updates with query)
|
|
399
|
+
const groupCounts = useMemo(() => {
|
|
400
|
+
const counts: Record<string, number> = {};
|
|
401
|
+
for (const cmd of filtered) counts[cmd.group] = (counts[cmd.group] ?? 0) + 1;
|
|
402
|
+
return counts;
|
|
403
|
+
}, [filtered]);
|
|
404
|
+
|
|
405
|
+
// Final display list — apply group filters as post-process
|
|
406
|
+
const displayItems = useMemo(() => {
|
|
407
|
+
if (activeFilters.size === 0) return filtered;
|
|
408
|
+
return filtered.filter((cmd) => activeFilters.has(cmd.group));
|
|
409
|
+
}, [filtered, activeFilters]);
|
|
410
|
+
|
|
411
|
+
const toggleFilter = useCallback((group: string) => {
|
|
412
|
+
setActiveFilters((prev) => {
|
|
413
|
+
const next = new Set(prev);
|
|
414
|
+
if (next.has(group)) next.delete(group);
|
|
415
|
+
else next.add(group);
|
|
416
|
+
return next;
|
|
417
|
+
});
|
|
418
|
+
setSelectedIdx(0);
|
|
419
|
+
}, []);
|
|
420
|
+
|
|
387
421
|
// Auto-load file index when palette opens and index isn't ready
|
|
388
422
|
useEffect(() => {
|
|
389
423
|
if (open && indexStatus === "idle" && activeProject) {
|
|
@@ -398,14 +432,15 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
|
|
|
398
432
|
setSelectedIdx(0);
|
|
399
433
|
setFsFiles([]);
|
|
400
434
|
setDbResults([]);
|
|
435
|
+
setActiveFilters(new Set());
|
|
401
436
|
requestAnimationFrame(() => inputRef.current?.focus());
|
|
402
437
|
}
|
|
403
438
|
}, [open]);
|
|
404
439
|
|
|
405
|
-
// Clamp selected index when
|
|
440
|
+
// Clamp selected index when display list changes
|
|
406
441
|
useEffect(() => {
|
|
407
|
-
setSelectedIdx((prev) => Math.min(prev, Math.max(
|
|
408
|
-
}, [
|
|
442
|
+
setSelectedIdx((prev) => Math.min(prev, Math.max(displayItems.length - 1, 0)));
|
|
443
|
+
}, [displayItems.length]);
|
|
409
444
|
|
|
410
445
|
// Scroll selected item into view
|
|
411
446
|
useEffect(() => {
|
|
@@ -430,7 +465,7 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
|
|
|
430
465
|
}, [query, activeProject, openTab, onClose]);
|
|
431
466
|
|
|
432
467
|
function handleKeyDown(e: React.KeyboardEvent) {
|
|
433
|
-
const len =
|
|
468
|
+
const len = displayItems.length;
|
|
434
469
|
switch (e.key) {
|
|
435
470
|
case "ArrowDown":
|
|
436
471
|
e.preventDefault();
|
|
@@ -443,7 +478,7 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
|
|
|
443
478
|
case "Enter":
|
|
444
479
|
e.preventDefault();
|
|
445
480
|
if (len > 0) {
|
|
446
|
-
|
|
481
|
+
displayItems[selectedIdx]?.action();
|
|
447
482
|
} else if (query.trim()) {
|
|
448
483
|
askAi();
|
|
449
484
|
}
|
|
@@ -510,11 +545,23 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
|
|
|
510
545
|
</div>
|
|
511
546
|
)}
|
|
512
547
|
|
|
548
|
+
{/* Filter chips — hidden in path mode */}
|
|
549
|
+
{!pathMode && (
|
|
550
|
+
<CommandPaletteFilterChips
|
|
551
|
+
availableGroups={availableGroups}
|
|
552
|
+
groupCounts={groupCounts}
|
|
553
|
+
activeFilters={activeFilters}
|
|
554
|
+
onToggle={toggleFilter}
|
|
555
|
+
/>
|
|
556
|
+
)}
|
|
557
|
+
|
|
513
558
|
{/* Results */}
|
|
514
559
|
<div ref={listRef} className="max-h-72 overflow-y-auto py-1">
|
|
515
|
-
{
|
|
560
|
+
{displayItems.length === 0 ? (
|
|
516
561
|
fsLoading ? (
|
|
517
562
|
<p className="px-3 py-4 text-sm text-text-subtle text-center">Searching...</p>
|
|
563
|
+
) : activeFilters.size > 0 && filtered.length > 0 ? (
|
|
564
|
+
<p className="px-3 py-4 text-sm text-text-subtle text-center">No results in selected filters</p>
|
|
518
565
|
) : query.trim() ? (
|
|
519
566
|
<button
|
|
520
567
|
onClick={askAi}
|
|
@@ -527,7 +574,7 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
|
|
|
527
574
|
<p className="px-3 py-4 text-sm text-text-subtle text-center">No results</p>
|
|
528
575
|
)
|
|
529
576
|
) : (
|
|
530
|
-
|
|
577
|
+
displayItems.map((cmd, i) => {
|
|
531
578
|
const Icon = cmd.icon;
|
|
532
579
|
return (
|
|
533
580
|
<button
|