@hienlh/ppm 0.13.53 → 0.13.55
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 +22 -0
- package/assets/skills/ppm/SKILL.md +2 -2
- package/assets/skills/ppm/references/cli-reference.md +11 -0
- package/assets/skills/ppm/references/http-api.md +7 -1
- package/dist/web/assets/ai-settings-section-AxLbNnLW.js +1 -0
- package/dist/web/assets/{api-settings-C3T95dWg.js → api-settings-BJTjIG4U.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-CkdUQjA_.js +1 -0
- package/dist/web/assets/arrow-down-D825m4vm.js +1 -0
- package/dist/web/assets/{audio-preview-DzlMrjXC.js → audio-preview-B53oeW0y.js} +1 -1
- package/dist/web/assets/chat-tab-Clzw7eDP.js +16 -0
- package/dist/web/assets/chevron-down-BMo4cBth.js +1 -0
- package/dist/web/assets/code-editor-BgU5lFVC.js +8 -0
- package/dist/web/assets/{conflict-editor-DsL9J6Ao.js → conflict-editor-C3l3pgtV.js} +3 -3
- package/dist/web/assets/csv-parser-D1b_lg2T.js +6 -0
- package/dist/web/assets/{csv-preview-B3Dyhgho.js → csv-preview-asMfgR0r.js} +2 -2
- package/dist/web/assets/{data-grid-overlay-editor-C1UUm7Ob.js → data-grid-overlay-editor-DGjqvYn6.js} +1 -1
- package/dist/web/assets/database-viewer-DNYgu_Jv.js +1 -0
- package/dist/web/assets/diff-viewer-Dec4mKgl.js +4 -0
- package/dist/web/assets/{esm-DCbn6xno.js → esm-xVTUq__o.js} +1 -1
- package/dist/web/assets/{extension-webview-SqqLBksj.js → extension-webview-b7T0yAq2.js} +1 -1
- package/dist/web/assets/eye-off-BacF7RVS.js +1 -0
- package/dist/web/assets/git-log-panel-CWTTJERX.js +1 -0
- package/dist/web/assets/gitGraph-HDMCJU4V-D3UR56AG.js +1 -0
- package/dist/web/assets/glide-data-grid-_9gGGfZy.js +136 -0
- package/dist/web/assets/{image-preview-CVERB6Hn.js → image-preview-CzXKlWft.js} +1 -1
- package/dist/web/assets/index-1_isAfRS.js +27 -0
- package/dist/web/assets/index-CDPVPZHJ.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-DUhLSKI2.js +1 -0
- package/dist/web/assets/{input-_LFQwhzd.js → input-By_lZeCs.js} +1 -1
- package/dist/web/assets/keybindings-store-BicDU0b1.js +1 -0
- package/dist/web/assets/{markdown-renderer-F5aFyJ-g.js → markdown-renderer-DWIBF9Jg.js} +3 -3
- package/dist/web/assets/notification-store-D_2wCv0z.js +1 -0
- package/dist/web/assets/{number-overlay-editor-CyEqxXcg.js → number-overlay-editor-DtUBprPW.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-BIpeVUGW.js +1 -0
- package/dist/web/assets/panel-store-C9VAhbZz.js +1 -0
- package/dist/web/assets/{pdf-preview-RgwYR2Lj.js → pdf-preview-C51mDesS.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-CNoizzjb.js +1 -0
- package/dist/web/assets/port-forwarding-tab-BmRMiN32.js +1 -0
- package/dist/web/assets/{postgres-viewer-Dq2nI9jE.js → postgres-viewer-DuiEoUGK.js} +3 -3
- package/dist/web/assets/project-store-DlbHpIq0.js +1 -0
- package/dist/web/assets/radar-KQ55EAFF-7dns-ho5.js +1 -0
- package/dist/web/assets/{settings-store-8FpQDjEA.js → settings-store-DQUFTPk2.js} +2 -2
- package/dist/web/assets/settings-tab-p3lxp6_T.js +1 -0
- package/dist/web/assets/{sql-query-editor-CL6O_4eW.js → sql-query-editor-BA80nuKp.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-CcJz9Bva.js → sqlite-viewer-Bev2XJe7.js} +1 -1
- package/dist/web/assets/system-monitor-tab-DfpsOgL3.js +1 -0
- package/dist/web/assets/{tab-store-CNas5Ny8.js → tab-store-CIcbSn0c.js} +1 -1
- package/dist/web/assets/{terminal-tab-BlyuDIu5.js → terminal-tab-Ca5kyUS7.js} +2 -2
- package/dist/web/assets/treemap-KZPCXAKY-D3DZCLoE.js +1 -0
- package/dist/web/assets/{use-blob-url-DB4nNruT.js → use-blob-url-VgTGpely.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-DEI-tJAh.js → use-monaco-theme-BLIgarH5.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-D2KKkqNs.js → vendor-mermaid-DkqjpqJK.js} +2 -2
- package/dist/web/assets/{video-preview-C8s0VXIf.js → video-preview-Bvd0OaYA.js} +1 -1
- package/dist/web/assets/wifi-LJEyIdXf.js +1 -0
- package/dist/web/index.html +21 -20
- package/dist/web/sw.js +1 -1
- package/docs/project-changelog.md +38 -1
- package/docs/system-architecture.md +2 -1
- package/package.json +1 -1
- package/packages/ext-git-graph/src/webview-html.ts +29 -8
- package/src/cli/commands/db-cmd.ts +30 -4
- package/src/server/index.ts +4 -0
- package/src/server/middleware/auth.ts +9 -0
- package/src/server/routes/resources.ts +61 -0
- package/src/services/ppmbot/cli-reference-default.ts +6 -1
- package/src/services/resource-monitor-utils.ts +129 -0
- package/src/services/resource-monitor.service.ts +122 -0
- package/src/web/components/editor/editor-breadcrumb.tsx +8 -1
- package/src/web/components/git/git-log-panel.tsx +206 -0
- package/src/web/components/git/git-ref-badge.tsx +150 -0
- package/src/web/components/git/git-status-panel.tsx +18 -0
- package/src/web/components/layout/mobile-nav.tsx +2 -0
- package/src/web/components/layout/sidebar.tsx +6 -0
- package/src/web/components/layout/tab-bar.tsx +3 -0
- package/src/web/components/layout/tab-content.tsx +10 -0
- package/src/web/components/layout/tab-pool.tsx +2 -0
- package/src/web/components/system/resource-status-bar.tsx +66 -0
- package/src/web/components/system/sparkline-canvas.tsx +64 -0
- package/src/web/components/system/system-monitor-tab.tsx +194 -0
- package/src/web/hooks/use-resource-monitor.ts +114 -0
- package/src/web/stores/panel-store.ts +1 -1
- package/src/web/stores/tab-store.ts +3 -1
- package/templates/skill/SKILL.md.tmpl +1 -1
- package/dist/web/assets/ai-settings-section-AuV6Lzz2.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-fAJMexNi.js +0 -1
- package/dist/web/assets/chat-tab-BpP-9jSF.js +0 -16
- package/dist/web/assets/code-editor-DUrnjDXe.js +0 -8
- package/dist/web/assets/csv-parser-Dly5nqE1.js +0 -6
- package/dist/web/assets/database-viewer-BzZ_B08X.js +0 -1
- package/dist/web/assets/diff-viewer-BTtOJWuk.js +0 -4
- package/dist/web/assets/file-store-DOxcU_7s.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-ClRAoBAn.js +0 -1
- package/dist/web/assets/glide-data-grid-YCbGSPc8.js +0 -136
- package/dist/web/assets/index-CKKoR3gY.css +0 -2
- package/dist/web/assets/index-D3gMHLKc.js +0 -27
- package/dist/web/assets/info-3K5VOQVL-D8uyBfC_.js +0 -1
- package/dist/web/assets/keybindings-store-BY4JJMPB.js +0 -1
- package/dist/web/assets/notification-store-CmFhp1D7.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-BJj3FH_w.js +0 -1
- package/dist/web/assets/panel-store-C8wwxBpn.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-BKfHRBz7.js +0 -1
- package/dist/web/assets/port-forwarding-tab-CRBTvvYM.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-DkybKTt9.js +0 -1
- package/dist/web/assets/scroll-area-BDi_FNzr.js +0 -1
- package/dist/web/assets/settings-tab-BrtuPA9W.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-BvDgIWW9.js +0 -1
- /package/dist/web/assets/{api-client-DIhJ5qVW.js → api-client-BK4NPNoY.js} +0 -0
- /package/dist/web/assets/{chevron-right-DnHIvvcy.js → chevron-right-CD8e6Aj4.js} +0 -0
- /package/dist/web/assets/{code-DGBecc50.js → code-DiNmA3eR.js} +0 -0
- /package/dist/web/assets/{data-grid-types-D2cHE8hx.js → data-grid-types-DzL5W2em.js} +0 -0
- /package/dist/web/assets/{database-DOWH9-Vv.js → database-Dc8mr-dP.js} +0 -0
- /package/dist/web/assets/{dist-BoIkGNC8.js → dist-BM2EHhLH.js} +0 -0
- /package/dist/web/assets/{dist-DVk8T0R5.js → dist-CohudVKa.js} +0 -0
- /package/dist/web/assets/{file-exclamation-point-BwzaQ50n.js → file-exclamation-point-B__2Hrd6.js} +0 -0
- /package/dist/web/assets/{globe-B4Ilypbs.js → globe-CQ8NAYvi.js} +0 -0
- /package/dist/web/assets/{katex-C10ndCVt.js → katex-CHaeM9QC.js} +0 -0
- /package/dist/web/assets/{lib-C2D8j3K3.js → lib-LPmTkMu4.js} +0 -0
- /package/dist/web/assets/{react-DMIOAtcX.js → react-DHBl6KRc.js} +0 -0
- /package/dist/web/assets/{refresh-cw-BjrAbUJe.js → refresh-cw-CRD2qr4U.js} +0 -0
- /package/dist/web/assets/{search-tM8K5zWU.js → search-D90WJ5fo.js} +0 -0
- /package/dist/web/assets/{sparkles-CulWHe4c.js → sparkles-KCOEy7QI.js} +0 -0
- /package/dist/web/assets/{table-BzjWcs87.js → table-2wDtM4_B.js} +0 -0
- /package/dist/web/assets/{text-wrap-DJz9Bgpa.js → text-wrap-AZErifCu.js} +0 -0
- /package/dist/web/assets/{utils-CQux7CsO.js → utils-CSCvNZxE.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-D1P36hcr.js → vendor-xterm-vh96p1Au.js} +0 -0
- /package/dist/web/assets/{x-BPReZWnP.js → x-ClICkcxR.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as e}from"./vendor-markdown-0Mxgxy0L.js";import{t}from"./file-exclamation-point-
|
|
1
|
+
import{b as e}from"./vendor-markdown-0Mxgxy0L.js";import{t}from"./file-exclamation-point-B__2Hrd6.js";import"./api-client-BK4NPNoY.js";import{$ as n}from"./index-1_isAfRS.js";import{t as r}from"./use-blob-url-VgTGpely.js";var i=e();function a({filePath:e,projectName:a}){let{blobUrl:o,error:s}=r(e,a);return s?(0,i.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,i.jsx)(t,{className:`size-10 text-text-subtle`}),(0,i.jsx)(`p`,{className:`text-sm`,children:`Failed to load video.`})]}):o?(0,i.jsx)(`div`,{className:`flex items-center justify-center h-full p-4 bg-surface overflow-auto`,children:(0,i.jsx)(`video`,{src:o,controls:!0,className:`max-w-full max-h-full`})}):(0,i.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,i.jsx)(n,{className:`size-5 animate-spin text-text-subtle`})})}export{a as VideoPreview};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./createLucideIcon-BjHrJDVb.js";var t=e(`wifi`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M2 8.82a15 15 0 0 1 20 0`,key:`dnpr2z`}],[`path`,{d:`M5 12.859a10 10 0 0 1 14 0`,key:`1x1e6c`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}]]);export{t};
|
package/dist/web/index.html
CHANGED
|
@@ -39,30 +39,31 @@
|
|
|
39
39
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
40
40
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
41
41
|
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600;700&family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
42
|
-
<script type="module" crossorigin src="/assets/index-
|
|
42
|
+
<script type="module" crossorigin src="/assets/index-1_isAfRS.js"></script>
|
|
43
43
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-FhOqtrmT.js">
|
|
44
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-mermaid-
|
|
44
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-mermaid-DkqjpqJK.js">
|
|
45
45
|
<link rel="modulepreload" crossorigin href="/assets/vendor-markdown-0Mxgxy0L.js">
|
|
46
46
|
<link rel="modulepreload" crossorigin href="/assets/vendor-ui-UXCWAcmi.js">
|
|
47
|
-
<link rel="modulepreload" crossorigin href="/assets/utils-
|
|
47
|
+
<link rel="modulepreload" crossorigin href="/assets/utils-CSCvNZxE.js">
|
|
48
48
|
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-BjHrJDVb.js">
|
|
49
|
-
<link rel="modulepreload" crossorigin href="/assets/x-
|
|
50
|
-
<link rel="modulepreload" crossorigin href="/assets/input-
|
|
51
|
-
<link rel="modulepreload" crossorigin href="/assets/react-
|
|
52
|
-
<link rel="modulepreload" crossorigin href="/assets/api-client-
|
|
53
|
-
<link rel="modulepreload" crossorigin href="/assets/settings-store-
|
|
54
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
55
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
56
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
57
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
58
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
59
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
60
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
61
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
62
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
63
|
-
<link rel="modulepreload" crossorigin href="/assets/panel-store-
|
|
64
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
65
|
-
<link rel="
|
|
49
|
+
<link rel="modulepreload" crossorigin href="/assets/x-ClICkcxR.js">
|
|
50
|
+
<link rel="modulepreload" crossorigin href="/assets/input-By_lZeCs.js">
|
|
51
|
+
<link rel="modulepreload" crossorigin href="/assets/react-DHBl6KRc.js">
|
|
52
|
+
<link rel="modulepreload" crossorigin href="/assets/api-client-BK4NPNoY.js">
|
|
53
|
+
<link rel="modulepreload" crossorigin href="/assets/settings-store-DQUFTPk2.js">
|
|
54
|
+
<link rel="modulepreload" crossorigin href="/assets/eye-off-BacF7RVS.js">
|
|
55
|
+
<link rel="modulepreload" crossorigin href="/assets/chevron-down-BMo4cBth.js">
|
|
56
|
+
<link rel="modulepreload" crossorigin href="/assets/globe-CQ8NAYvi.js">
|
|
57
|
+
<link rel="modulepreload" crossorigin href="/assets/refresh-cw-CRD2qr4U.js">
|
|
58
|
+
<link rel="modulepreload" crossorigin href="/assets/api-settings-BJTjIG4U.js">
|
|
59
|
+
<link rel="modulepreload" crossorigin href="/assets/ai-settings-section-AxLbNnLW.js">
|
|
60
|
+
<link rel="modulepreload" crossorigin href="/assets/database-Dc8mr-dP.js">
|
|
61
|
+
<link rel="modulepreload" crossorigin href="/assets/chevron-right-CD8e6Aj4.js">
|
|
62
|
+
<link rel="modulepreload" crossorigin href="/assets/search-D90WJ5fo.js">
|
|
63
|
+
<link rel="modulepreload" crossorigin href="/assets/panel-store-C9VAhbZz.js">
|
|
64
|
+
<link rel="modulepreload" crossorigin href="/assets/project-store-DlbHpIq0.js">
|
|
65
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-store-CIcbSn0c.js">
|
|
66
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CDPVPZHJ.css">
|
|
66
67
|
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
|
67
68
|
<body class="bg-[#0f1419] text-[#e5e7eb] font-sans antialiased">
|
|
68
69
|
<div id="portal" style="position: fixed; left: 0; top: 0; z-index: 9999;" /></div>
|
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":"908e287cc604cc7fffb8611e126eb727","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/refresh-cw-BjrAbUJe.js"},{"revision":null,"url":"assets/panel-store-C8wwxBpn.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/glide-data-grid-YCbGSPc8.js"},{"revision":null,"url":"assets/input-_LFQwhzd.js"},{"revision":null,"url":"assets/data-grid-overlay-editor-C1UUm7Ob.js"},{"revision":null,"url":"assets/esm-DCbn6xno.js"},{"revision":null,"url":"assets/code-editor-DUrnjDXe.js"},{"revision":null,"url":"assets/table-BzjWcs87.js"},{"revision":null,"url":"assets/text-wrap-DJz9Bgpa.js"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/treemap-KZPCXAKY-BvDgIWW9.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-BJj3FH_w.js"},{"revision":null,"url":"assets/sparkles-CulWHe4c.js"},{"revision":null,"url":"assets/chat-tab-BpP-9jSF.js"},{"revision":null,"url":"assets/use-blob-url-DB4nNruT.js"},{"revision":null,"url":"assets/number-overlay-editor-CyEqxXcg.js"},{"revision":null,"url":"assets/search-tM8K5zWU.js"},{"revision":null,"url":"assets/globe-B4Ilypbs.js"},{"revision":null,"url":"assets/pdf-preview-RgwYR2Lj.js"},{"revision":null,"url":"assets/github.min-D2BCvnWf.css"},{"revision":null,"url":"assets/index-D3gMHLKc.js"},{"revision":null,"url":"assets/database-DOWH9-Vv.js"},{"revision":null,"url":"assets/dist-DVk8T0R5.js"},{"revision":null,"url":"assets/port-forwarding-tab-CRBTvvYM.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/database-viewer-BzZ_B08X.js"},{"revision":null,"url":"assets/scroll-area-BDi_FNzr.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-fAJMexNi.js"},{"revision":null,"url":"assets/postgres-viewer-Dq2nI9jE.js"},{"revision":null,"url":"assets/glide-data-grid-nthEL3fk.css"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/diff-viewer-BTtOJWuk.js"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/settings-store-8FpQDjEA.js"},{"revision":null,"url":"assets/file-store-DOxcU_7s.js"},{"revision":null,"url":"assets/keybindings-store-BY4JJMPB.js"},{"revision":null,"url":"assets/vendor-mermaid-D2KKkqNs.js"},{"revision":null,"url":"assets/dist-BoIkGNC8.js"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/vendor-xterm-D1P36hcr.js"},{"revision":null,"url":"assets/lib-C2D8j3K3.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/ai-settings-section-AuV6Lzz2.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/react-DMIOAtcX.js"},{"revision":null,"url":"assets/utils-CQux7CsO.js"},{"revision":null,"url":"assets/csv-parser-Dly5nqE1.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/use-monaco-theme-DEI-tJAh.js"},{"revision":null,"url":"assets/vendor-ui-UXCWAcmi.js"},{"revision":null,"url":"assets/image-preview-CVERB6Hn.js"},{"revision":null,"url":"assets/code-DGBecc50.js"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/github-dark-dimmed.min-BrpRStFV.css"},{"revision":null,"url":"assets/terminal-tab-BlyuDIu5.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/file-exclamation-point-BwzaQ50n.js"},{"revision":null,"url":"assets/api-client-DIhJ5qVW.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-DkybKTt9.js"},{"revision":null,"url":"assets/info-3K5VOQVL-D8uyBfC_.js"},{"revision":null,"url":"assets/sql-query-editor-CL6O_4eW.js"},{"revision":null,"url":"assets/csv-preview-B3Dyhgho.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/settings-tab-BrtuPA9W.js"},{"revision":null,"url":"assets/conflict-editor-DsL9J6Ao.js"},{"revision":null,"url":"assets/tab-store-CNas5Ny8.js"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/data-grid-types-D2cHE8hx.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-ClRAoBAn.js"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/notification-store-CmFhp1D7.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-BKfHRBz7.js"},{"revision":null,"url":"assets/x-BPReZWnP.js"},{"revision":null,"url":"assets/chevron-right-DnHIvvcy.js"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/api-settings-C3T95dWg.js"},{"revision":null,"url":"assets/katex-C10ndCVt.js"},{"revision":null,"url":"assets/sqlite-viewer-CcJz9Bva.js"},{"revision":null,"url":"assets/extension-webview-SqqLBksj.js"},{"revision":null,"url":"assets/markdown-renderer-F5aFyJ-g.js"},{"revision":null,"url":"assets/audio-preview-DzlMrjXC.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/index-CKKoR3gY.css"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":null,"url":"assets/video-preview-C8s0VXIf.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":"63bd4ab1b5c42a305941a3a738963ffd","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/project-store-DlbHpIq0.js"},{"revision":null,"url":"assets/utils-CSCvNZxE.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/table-2wDtM4_B.js"},{"revision":null,"url":"assets/katex-CHaeM9QC.js"},{"revision":null,"url":"assets/extension-webview-b7T0yAq2.js"},{"revision":null,"url":"assets/arrow-down-D825m4vm.js"},{"revision":null,"url":"assets/api-settings-BJTjIG4U.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-CNoizzjb.js"},{"revision":null,"url":"assets/code-editor-BgU5lFVC.js"},{"revision":null,"url":"assets/chat-tab-Clzw7eDP.js"},{"revision":null,"url":"assets/esm-xVTUq__o.js"},{"revision":null,"url":"assets/audio-preview-B53oeW0y.js"},{"revision":null,"url":"assets/settings-tab-p3lxp6_T.js"},{"revision":null,"url":"assets/sql-query-editor-BA80nuKp.js"},{"revision":null,"url":"assets/keybindings-store-BicDU0b1.js"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/port-forwarding-tab-BmRMiN32.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-7dns-ho5.js"},{"revision":null,"url":"assets/chevron-down-BMo4cBth.js"},{"revision":null,"url":"assets/react-DHBl6KRc.js"},{"revision":null,"url":"assets/conflict-editor-C3l3pgtV.js"},{"revision":null,"url":"assets/sqlite-viewer-Bev2XJe7.js"},{"revision":null,"url":"assets/github.min-D2BCvnWf.css"},{"revision":null,"url":"assets/treemap-KZPCXAKY-D3DZCLoE.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/dist-CohudVKa.js"},{"revision":null,"url":"assets/glide-data-grid-nthEL3fk.css"},{"revision":null,"url":"assets/settings-store-DQUFTPk2.js"},{"revision":null,"url":"assets/use-blob-url-VgTGpely.js"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/terminal-tab-Ca5kyUS7.js"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/vendor-xterm-vh96p1Au.js"},{"revision":null,"url":"assets/wifi-LJEyIdXf.js"},{"revision":null,"url":"assets/tab-store-CIcbSn0c.js"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/video-preview-Bvd0OaYA.js"},{"revision":null,"url":"assets/notification-store-D_2wCv0z.js"},{"revision":null,"url":"assets/use-monaco-theme-BLIgarH5.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/panel-store-C9VAhbZz.js"},{"revision":null,"url":"assets/chevron-right-CD8e6Aj4.js"},{"revision":null,"url":"assets/data-grid-types-DzL5W2em.js"},{"revision":null,"url":"assets/index-CDPVPZHJ.css"},{"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/globe-CQ8NAYvi.js"},{"revision":null,"url":"assets/data-grid-overlay-editor-DGjqvYn6.js"},{"revision":null,"url":"assets/glide-data-grid-_9gGGfZy.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-D3UR56AG.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.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/packet-RMMSAZCW-BIpeVUGW.js"},{"revision":null,"url":"assets/file-exclamation-point-B__2Hrd6.js"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/github-dark-dimmed.min-BrpRStFV.css"},{"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/database-Dc8mr-dP.js"},{"revision":null,"url":"assets/eye-off-BacF7RVS.js"},{"revision":null,"url":"assets/vendor-mermaid-DkqjpqJK.js"},{"revision":null,"url":"assets/postgres-viewer-DuiEoUGK.js"},{"revision":null,"url":"assets/lib-LPmTkMu4.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/pdf-preview-C51mDesS.js"},{"revision":null,"url":"assets/markdown-renderer-DWIBF9Jg.js"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/index-1_isAfRS.js"},{"revision":null,"url":"assets/git-log-panel-CWTTJERX.js"},{"revision":null,"url":"assets/system-monitor-tab-DfpsOgL3.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/diff-viewer-Dec4mKgl.js"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/architecture-PBZL5I3N-CkdUQjA_.js"},{"revision":null,"url":"assets/database-viewer-DNYgu_Jv.js"},{"revision":null,"url":"assets/number-overlay-editor-DtUBprPW.js"},{"revision":null,"url":"assets/csv-preview-asMfgR0r.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/input-By_lZeCs.js"},{"revision":null,"url":"assets/api-client-BK4NPNoY.js"},{"revision":null,"url":"assets/sparkles-KCOEy7QI.js"},{"revision":null,"url":"assets/ai-settings-section-AxLbNnLW.js"},{"revision":null,"url":"assets/image-preview-CzXKlWft.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/info-3K5VOQVL-DUhLSKI2.js"},{"revision":null,"url":"assets/x-ClICkcxR.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":null,"url":"assets/dist-BM2EHhLH.js"},{"revision":null,"url":"assets/csv-parser-D1b_lg2T.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||`/`)}))});
|
|
@@ -20,9 +20,46 @@ All notable changes to PPM are documented here. Format follows [Keep a Changelog
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
## [Unreleased] — 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
|
|
24
24
|
|
|
25
25
|
### Added
|
|
26
|
+
- **System Resource Monitor** — Real-time process monitoring with SSE streaming, sidebar status bar, and dedicated System Monitor tab
|
|
27
|
+
- 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
|
+
- Backend: SSE streaming route at `GET /api/system/resources/stream` with client count cap (max 5), manual reconnect with exponential backoff
|
|
29
|
+
- Backend: JSON snapshot endpoint at `GET /api/system/resources` + history endpoint at `GET /api/system/resources/history`
|
|
30
|
+
- Backend: Cross-platform support (`ps` on macOS/Linux, graceful skip on Windows native)
|
|
31
|
+
- Frontend: `useResourceMonitor()` hook provides shared EventSource with ref-counted singleton pattern, auto-reconnect, history ring buffer
|
|
32
|
+
- Frontend: Compact resource status bar in sidebar footer showing CPU%/RAM/process count with color-coded CPU thresholds (green <50%, yellow 50-80%, red >80%)
|
|
33
|
+
- Frontend: Full System Monitor tab with grouped processes, collapsible rows, individual process details, canvas-based sparklines (last 200 data points = ~10min)
|
|
34
|
+
- Frontend: Chat session status badges (streaming/idle) pulled from streaming store
|
|
35
|
+
- Frontend: Mobile-responsive layout with compact sparklines, touch-friendly collapsible groups
|
|
36
|
+
- Auth: Token in URL query param for SSE EventSource (standard fetch credentials for auth)
|
|
37
|
+
- Tests: Integration + unit tests for service, routes, hook, and components
|
|
38
|
+
|
|
39
|
+
**Technical Details:**
|
|
40
|
+
- **Files Created:**
|
|
41
|
+
- `src/services/resource-monitor.service.ts` — Process polling, categorization, ring buffer
|
|
42
|
+
- `src/server/routes/resources.ts` — SSE + JSON endpoints, client count tracking
|
|
43
|
+
- `src/web/hooks/use-resource-monitor.ts` — EventSource hook with singleton ref counting
|
|
44
|
+
- `src/web/components/system/resource-status-bar.tsx` — Compact status bar widget
|
|
45
|
+
- `src/web/components/system/system-monitor-tab.tsx` — Full monitoring dashboard
|
|
46
|
+
- `src/web/components/system/sparkline-canvas.tsx` — Canvas-based sparkline renderer
|
|
47
|
+
- `tests/integration/resource-monitor.test.ts` — Service integration tests
|
|
48
|
+
- `tests/integration/resources-route.test.ts` — Route integration tests
|
|
49
|
+
- `tests/integration/use-resource-monitor.test.ts` — Hook integration tests
|
|
50
|
+
- **Files Modified:**
|
|
51
|
+
- `src/server/index.ts` — Mount resources route
|
|
52
|
+
- `src/web/components/layout/tab-content.tsx` — Lazy-load system-monitor tab
|
|
53
|
+
- `src/web/stores/tab-store.ts` — Add "system-monitor" TabType
|
|
54
|
+
- `src/web/components/layout/sidebar.tsx` — Add ResourceStatusBar to footer
|
|
55
|
+
- **Type Changes:**
|
|
56
|
+
- New: `ProcessEntry` = { pid, ppid, cpu, ramMB, command }
|
|
57
|
+
- New: `ResourceGroup` = { type, label, cpu, ramMB, processes[] }
|
|
58
|
+
- New: `ResourceSnapshot` = { timestamp, server, total, groups[] }
|
|
59
|
+
- **Breaking Changes:** None (additive feature)
|
|
60
|
+
- **Performance:** ~50KB ring buffer (negligible), 3s polling lazy-started, SSE capped at 5 concurrent clients
|
|
61
|
+
|
|
62
|
+
### Added (continued)
|
|
26
63
|
- **Draft Messages** — Auto-save chat input as drafts per session
|
|
27
64
|
- Database: Schema v26 migration creates `chat_drafts` table with (project_path, session_id, content, attachments, updated_at) composite key
|
|
28
65
|
- Service: `DraftService` with get/upsert/delete/deleteOrphaned CRUD operations; 50KB content cap with silent truncation
|
|
@@ -228,8 +228,9 @@ Tab IDs are deterministic: `{type}:{identifier}` (e.g., `editor:src/index.ts`, `
|
|
|
228
228
|
| **TagService** | Session tagging CRUD, bulk operations, tag-session enrichment | seedDefaultTags, getTagsByProject, createTag, updateTag, deleteTag, setSessionTag, bulkSetSessionTag, getSessionTags, getTagSessionCounts |
|
|
229
229
|
| **DraftService** | Chat draft auto-save per session, 50KB cap | get, upsert, delete, deleteOrphaned |
|
|
230
230
|
| **FileFilterService** | Glob pattern matching + precedence-enforced filtering (hardcoded ⊂ global ⊂ project) | mergeFilters, isPathIgnored, matchesPattern |
|
|
231
|
+
| **ResourceMonitorService** | System resource monitoring with process tree, SSE streaming, 30-min history ring buffer | subscribe, unsubscribe, getLatest, getHistory, poll |
|
|
231
232
|
|
|
232
|
-
**Key Files:** `src/services/*.service.ts`, `src/services/tag.service.ts`, `src/services/ppmbot/*.ts`, `src/services/bash-output-spy.ts`, `src/services/file-filter.service.ts`, `src/cli/commands/bot-cmd.ts`
|
|
233
|
+
**Key Files:** `src/services/*.service.ts`, `src/services/tag.service.ts`, `src/services/ppmbot/*.ts`, `src/services/bash-output-spy.ts`, `src/services/resource-monitor.service.ts`, `src/services/file-filter.service.ts`, `src/cli/commands/bot-cmd.ts`
|
|
233
234
|
|
|
234
235
|
---
|
|
235
236
|
|
package/package.json
CHANGED
|
@@ -261,13 +261,16 @@ button:active { background: var(--surface); }
|
|
|
261
261
|
.col-date { width: 80px; min-width: 80px; color: var(--subtext); font-size: 11px; }
|
|
262
262
|
.col-hash { width: 60px; min-width: 60px; font-family: 'SF Mono', 'Fira Code', monospace; font-size: 10px; color: var(--subtle); }
|
|
263
263
|
|
|
264
|
-
/* Ref badges */
|
|
265
|
-
.ref-badge { display: inline-
|
|
266
|
-
.ref-head {
|
|
267
|
-
.ref-local {
|
|
268
|
-
.ref-remote {
|
|
269
|
-
.ref-tag {
|
|
270
|
-
.ref-stash {
|
|
264
|
+
/* Ref badges — border + tinted bg + dark text */
|
|
265
|
+
.ref-badge { display: inline-flex; align-items: center; gap: 3px; padding: 0px 5px; border-radius: 3px; font-size: 9px; font-weight: 600; margin-right: 3px; vertical-align: middle; line-height: 16px; border: 1px solid; color: #1a1a1a; }
|
|
266
|
+
.ref-head { border-color: var(--green); background: color-mix(in srgb, var(--green) 12%, transparent); }
|
|
267
|
+
.ref-local { border-color: var(--blue); background: color-mix(in srgb, var(--blue) 12%, transparent); }
|
|
268
|
+
.ref-remote { border-color: var(--purple); background: color-mix(in srgb, var(--purple) 12%, transparent); }
|
|
269
|
+
.ref-tag { border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 12%, transparent); }
|
|
270
|
+
.ref-stash { border-color: #808080; background: color-mix(in srgb, #808080 12%, transparent); }
|
|
271
|
+
@media (prefers-color-scheme: dark) {
|
|
272
|
+
.ref-badge { color: #e4e4e7; }
|
|
273
|
+
}
|
|
271
274
|
|
|
272
275
|
/* SVG graph — single SVG overlay */
|
|
273
276
|
#commit-list-wrapper { position: relative; }
|
|
@@ -1469,10 +1472,28 @@ function renderCommitList() {
|
|
|
1469
1472
|
msgCol.className = 'col-message';
|
|
1470
1473
|
let badges = '';
|
|
1471
1474
|
if (commit.refs) {
|
|
1475
|
+
// Merge remote+local refs: if origin/X and X both exist, show one "synced" badge
|
|
1476
|
+
const localNames = new Set(commit.refs.filter(r => r.type === 'head' || r.type === 'local').map(r => r.name));
|
|
1477
|
+
const mergedRemotes = new Set();
|
|
1478
|
+
commit.refs.forEach(ref => {
|
|
1479
|
+
if (ref.type === 'remote') {
|
|
1480
|
+
// Strip remote prefix (e.g. "origin/main" → "main")
|
|
1481
|
+
const slashIdx = ref.name.indexOf('/');
|
|
1482
|
+
const branchName = slashIdx >= 0 ? ref.name.slice(slashIdx + 1) : ref.name;
|
|
1483
|
+
if (localNames.has(branchName)) {
|
|
1484
|
+
mergedRemotes.add(ref.name); // skip this remote, local badge covers it
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1472
1488
|
commit.refs.forEach(ref => {
|
|
1473
1489
|
if (ref.type === 'tag' && !state.settings.showTags) return;
|
|
1474
1490
|
if (ref.type === 'remote' && !state.settings.showRemoteBranches) return;
|
|
1475
|
-
|
|
1491
|
+
if (mergedRemotes.has(ref.name)) return; // merged into local badge
|
|
1492
|
+
// For local/head refs that have a matching remote, add sync icon
|
|
1493
|
+
const isSynced = (ref.type === 'head' || ref.type === 'local') &&
|
|
1494
|
+
commit.refs.some(r => r.type === 'remote' && r.name.endsWith('/' + ref.name));
|
|
1495
|
+
const syncIcon = isSynced ? '<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/></svg> ' : '';
|
|
1496
|
+
badges += '<span class="ref-badge ref-' + ref.type + '">' + syncIcon + escHtml(ref.name) + '</span>';
|
|
1476
1497
|
});
|
|
1477
1498
|
}
|
|
1478
1499
|
msgCol.innerHTML = badges + formatCommitMessage(commit.message);
|
|
@@ -67,14 +67,26 @@ export function registerDbCommands(program: Command): void {
|
|
|
67
67
|
// ── ppm db list ──────────────────────────────────────────────────────
|
|
68
68
|
db.command("list")
|
|
69
69
|
.description("List all saved database connections")
|
|
70
|
-
.
|
|
70
|
+
.option("--json", "Output as JSON")
|
|
71
|
+
.action(async (options: { json?: boolean }) => {
|
|
71
72
|
try {
|
|
72
73
|
const { getConnections } = await import("../../services/db.service.ts");
|
|
73
74
|
const conns = getConnections();
|
|
74
75
|
if (conns.length === 0) {
|
|
76
|
+
if (options.json) { console.log("[]"); return; }
|
|
75
77
|
console.log(`${C.yellow}No connections saved.${C.reset} Run: ppm db add`);
|
|
76
78
|
return;
|
|
77
79
|
}
|
|
80
|
+
if (options.json) {
|
|
81
|
+
const data = conns.map((c) => {
|
|
82
|
+
const cfg = parseConfig(c);
|
|
83
|
+
let target = cfg.connectionString ?? cfg.path ?? null;
|
|
84
|
+
if (cfg.connectionString) target = maskPassword(target!);
|
|
85
|
+
return { id: c.id, name: c.name, type: c.type, group: c.group_name ?? null, readonly: !!c.readonly, connection: target };
|
|
86
|
+
});
|
|
87
|
+
console.log(JSON.stringify(data, null, 2));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
78
90
|
const rows = conns.map((c) => {
|
|
79
91
|
const cfg = parseConfig(c);
|
|
80
92
|
let target = cfg.connectionString ?? cfg.path ?? "-";
|
|
@@ -197,7 +209,8 @@ export function registerDbCommands(program: Command): void {
|
|
|
197
209
|
// ── ppm db tables ────────────────────────────────────────────────────
|
|
198
210
|
db.command("tables <name>")
|
|
199
211
|
.description("List tables in a database connection")
|
|
200
|
-
.
|
|
212
|
+
.option("--json", "Output as JSON")
|
|
213
|
+
.action(async (nameOrId: string, options: { json?: boolean }) => {
|
|
201
214
|
try {
|
|
202
215
|
const { resolveConnection } = await import("../../services/db.service.ts");
|
|
203
216
|
const conn = resolveConnection(nameOrId);
|
|
@@ -212,9 +225,11 @@ export function registerDbCommands(program: Command): void {
|
|
|
212
225
|
const tables = await postgresService.getTables(cfg.connectionString!);
|
|
213
226
|
await postgresService.closeAll();
|
|
214
227
|
if (tables.length === 0) {
|
|
228
|
+
if (options.json) { console.log("[]"); return; }
|
|
215
229
|
console.log(`${C.dim}No tables found.${C.reset}`);
|
|
216
230
|
return;
|
|
217
231
|
}
|
|
232
|
+
if (options.json) { console.log(JSON.stringify(tables, null, 2)); return; }
|
|
218
233
|
printTable(
|
|
219
234
|
["Schema", "Table", "Rows (est.)"],
|
|
220
235
|
tables.map((t) => [t.schema, t.name, String(t.rowCount)]),
|
|
@@ -224,9 +239,11 @@ export function registerDbCommands(program: Command): void {
|
|
|
224
239
|
const tables = sqliteService.getTables(cfg.path!, cfg.path!);
|
|
225
240
|
sqliteService.closeAll();
|
|
226
241
|
if (tables.length === 0) {
|
|
242
|
+
if (options.json) { console.log("[]"); return; }
|
|
227
243
|
console.log(`${C.dim}No tables found.${C.reset}`);
|
|
228
244
|
return;
|
|
229
245
|
}
|
|
246
|
+
if (options.json) { console.log(JSON.stringify(tables, null, 2)); return; }
|
|
230
247
|
printTable(
|
|
231
248
|
["Table", "Rows"],
|
|
232
249
|
tables.map((t) => [t.name, String(t.rowCount)]),
|
|
@@ -242,7 +259,8 @@ export function registerDbCommands(program: Command): void {
|
|
|
242
259
|
db.command("schema <name> <table>")
|
|
243
260
|
.description("Show table schema (columns, types, constraints)")
|
|
244
261
|
.option("-s, --schema <schema>", "PostgreSQL schema name", "public")
|
|
245
|
-
.
|
|
262
|
+
.option("--json", "Output as JSON")
|
|
263
|
+
.action(async (nameOrId: string, table: string, options: { schema: string; json?: boolean }) => {
|
|
246
264
|
try {
|
|
247
265
|
const { resolveConnection } = await import("../../services/db.service.ts");
|
|
248
266
|
const conn = resolveConnection(nameOrId);
|
|
@@ -256,6 +274,7 @@ export function registerDbCommands(program: Command): void {
|
|
|
256
274
|
const { postgresService } = await import("../../services/postgres.service.ts");
|
|
257
275
|
const cols = await postgresService.getTableSchema(cfg.connectionString!, table, options.schema);
|
|
258
276
|
await postgresService.closeAll();
|
|
277
|
+
if (options.json) { console.log(JSON.stringify(cols, null, 2)); return; }
|
|
259
278
|
printTable(
|
|
260
279
|
["Column", "Type", "Nullable", "PK", "Default"],
|
|
261
280
|
cols.map((c) => [c.name, c.type, c.nullable ? "YES" : "NO", c.pk ? "PK" : "", c.defaultValue ?? ""]),
|
|
@@ -264,6 +283,7 @@ export function registerDbCommands(program: Command): void {
|
|
|
264
283
|
const { sqliteService } = await import("../../services/sqlite.service.ts");
|
|
265
284
|
const cols = sqliteService.getTableSchema(cfg.path!, cfg.path!, table);
|
|
266
285
|
sqliteService.closeAll();
|
|
286
|
+
if (options.json) { console.log(JSON.stringify(cols, null, 2)); return; }
|
|
267
287
|
printTable(
|
|
268
288
|
["Column", "Type", "Not Null", "PK", "Default"],
|
|
269
289
|
cols.map((c) => [c.name, c.type, c.notnull ? "YES" : "NO", c.pk ? "PK" : "", c.dflt_value ?? ""]),
|
|
@@ -283,6 +303,7 @@ export function registerDbCommands(program: Command): void {
|
|
|
283
303
|
.option("--order <column>", "Order by column")
|
|
284
304
|
.option("--desc", "Descending order")
|
|
285
305
|
.option("-s, --schema <schema>", "PostgreSQL schema name", "public")
|
|
306
|
+
.option("--json", "Output as JSON")
|
|
286
307
|
.action(async (nameOrId: string, table: string, options) => {
|
|
287
308
|
try {
|
|
288
309
|
const { resolveConnection } = await import("../../services/db.service.ts");
|
|
@@ -302,6 +323,7 @@ export function registerDbCommands(program: Command): void {
|
|
|
302
323
|
cfg.connectionString!, table, options.schema, page, limit, options.order, orderDir,
|
|
303
324
|
);
|
|
304
325
|
await postgresService.closeAll();
|
|
326
|
+
if (options.json) { console.log(JSON.stringify(result, null, 2)); return; }
|
|
305
327
|
console.log(`${C.cyan}${table}${C.reset} — page ${result.page}, ${result.total} total rows\n`);
|
|
306
328
|
formatRows(result.columns, result.rows, limit);
|
|
307
329
|
} else {
|
|
@@ -310,6 +332,7 @@ export function registerDbCommands(program: Command): void {
|
|
|
310
332
|
cfg.path!, cfg.path!, table, page, limit, options.order, orderDir,
|
|
311
333
|
);
|
|
312
334
|
sqliteService.closeAll();
|
|
335
|
+
if (options.json) { console.log(JSON.stringify(result, null, 2)); return; }
|
|
313
336
|
console.log(`${C.cyan}${table}${C.reset} — page ${result.page}, ${result.total} total rows\n`);
|
|
314
337
|
formatRows(result.columns, result.rows, limit);
|
|
315
338
|
}
|
|
@@ -322,7 +345,8 @@ export function registerDbCommands(program: Command): void {
|
|
|
322
345
|
// ── ppm db query ─────────────────────────────────────────────────────
|
|
323
346
|
db.command("query <name> <sql>")
|
|
324
347
|
.description("Execute a SQL query against a saved connection")
|
|
325
|
-
.
|
|
348
|
+
.option("--json", "Output as JSON")
|
|
349
|
+
.action(async (nameOrId: string, sql: string, options: { json?: boolean }) => {
|
|
326
350
|
try {
|
|
327
351
|
const { resolveConnection } = await import("../../services/db.service.ts");
|
|
328
352
|
const conn = resolveConnection(nameOrId);
|
|
@@ -343,6 +367,7 @@ export function registerDbCommands(program: Command): void {
|
|
|
343
367
|
const { postgresService } = await import("../../services/postgres.service.ts");
|
|
344
368
|
const result = await postgresService.executeQuery(cfg.connectionString!, sql);
|
|
345
369
|
await postgresService.closeAll();
|
|
370
|
+
if (options.json) { console.log(JSON.stringify(result, null, 2)); return; }
|
|
346
371
|
if (result.changeType === "select") {
|
|
347
372
|
formatRows(result.columns, result.rows);
|
|
348
373
|
} else {
|
|
@@ -352,6 +377,7 @@ export function registerDbCommands(program: Command): void {
|
|
|
352
377
|
const { sqliteService } = await import("../../services/sqlite.service.ts");
|
|
353
378
|
const result = sqliteService.executeQuery(cfg.path!, cfg.path!, sql);
|
|
354
379
|
sqliteService.closeAll();
|
|
380
|
+
if (options.json) { console.log(JSON.stringify(result, null, 2)); return; }
|
|
355
381
|
if (result.changeType === "select") {
|
|
356
382
|
formatRows(result.columns, result.rows);
|
|
357
383
|
} else {
|
package/src/server/index.ts
CHANGED
|
@@ -139,6 +139,10 @@ app.route("/api/preview", portForwardingRoutes);
|
|
|
139
139
|
// Filesystem operations (browse, list, read, write) — consolidated in fs-browse route
|
|
140
140
|
app.route("/api/fs", fsBrowseRoutes);
|
|
141
141
|
|
|
142
|
+
// System resource monitoring (SSE + JSON)
|
|
143
|
+
import { resourceRoutes } from "./routes/resources.ts";
|
|
144
|
+
app.route("/api/system", resourceRoutes);
|
|
145
|
+
|
|
142
146
|
// API routes
|
|
143
147
|
app.route("/api/settings", settingsRoutes);
|
|
144
148
|
app.route("/api/settings/mcp", mcpRoutes);
|
|
@@ -25,6 +25,15 @@ export async function authMiddleware(c: Context, next: Next) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// Fallback: ?token= query param for SSE/EventSource (can't set custom headers)
|
|
29
|
+
// Scoped to /stream paths only to avoid leaking token in logs/referer on all GET routes
|
|
30
|
+
if (c.req.method === "GET" && c.req.path.endsWith("/stream")) {
|
|
31
|
+
const queryToken = c.req.query("token");
|
|
32
|
+
if (queryToken && queryToken === authConfig.token) {
|
|
33
|
+
return next();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
28
37
|
// Fallback: short-lived download token for browser-initiated downloads only
|
|
29
38
|
if (c.req.method === "GET") {
|
|
30
39
|
const path = c.req.path;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { resourceMonitor, type ResourceSnapshot } from "../../services/resource-monitor.service.ts";
|
|
3
|
+
import { ok } from "../../types/api.ts";
|
|
4
|
+
|
|
5
|
+
export const resourceRoutes = new Hono();
|
|
6
|
+
|
|
7
|
+
const MAX_SSE_CLIENTS = 5;
|
|
8
|
+
let sseClientCount = 0;
|
|
9
|
+
|
|
10
|
+
/** GET /resources — latest snapshot as JSON */
|
|
11
|
+
resourceRoutes.get("/resources", (c) => {
|
|
12
|
+
return c.json(ok(resourceMonitor.getLatest()));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/** GET /resources/history — full ring buffer */
|
|
16
|
+
resourceRoutes.get("/resources/history", (c) => {
|
|
17
|
+
return c.json(ok(resourceMonitor.getHistory()));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/** GET /resources/stream — SSE stream of snapshots every 3s */
|
|
21
|
+
resourceRoutes.get("/resources/stream", (c) => {
|
|
22
|
+
if (sseClientCount >= MAX_SSE_CLIENTS) {
|
|
23
|
+
return c.json({ ok: false, error: "Too many SSE clients" }, 429);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let callbackRef: ((s: ResourceSnapshot) => void) | null = null;
|
|
27
|
+
|
|
28
|
+
const stream = new ReadableStream({
|
|
29
|
+
start(controller) {
|
|
30
|
+
sseClientCount++;
|
|
31
|
+
const encoder = new TextEncoder();
|
|
32
|
+
|
|
33
|
+
// Send retry hint for reconnect interval
|
|
34
|
+
controller.enqueue(encoder.encode("retry: 5000\n\n"));
|
|
35
|
+
|
|
36
|
+
callbackRef = (snapshot: ResourceSnapshot) => {
|
|
37
|
+
try {
|
|
38
|
+
const data = `event: snapshot\ndata: ${JSON.stringify(snapshot)}\n\n`;
|
|
39
|
+
controller.enqueue(encoder.encode(data));
|
|
40
|
+
} catch {
|
|
41
|
+
// Client disconnected — cleanup happens in cancel
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
resourceMonitor.subscribe(callbackRef);
|
|
46
|
+
},
|
|
47
|
+
cancel() {
|
|
48
|
+
sseClientCount = Math.max(0, sseClientCount - 1);
|
|
49
|
+
if (callbackRef) resourceMonitor.unsubscribe(callbackRef);
|
|
50
|
+
callbackRef = null;
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return new Response(stream, {
|
|
55
|
+
headers: {
|
|
56
|
+
"Content-Type": "text/event-stream",
|
|
57
|
+
"Cache-Control": "no-cache",
|
|
58
|
+
"Connection": "keep-alive",
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -161,6 +161,7 @@ ppm chat delete <session-id>
|
|
|
161
161
|
\`\`\`
|
|
162
162
|
ppm db list
|
|
163
163
|
List all saved database connections
|
|
164
|
+
--json — Output as JSON
|
|
164
165
|
|
|
165
166
|
ppm db add
|
|
166
167
|
Add a new database connection
|
|
@@ -179,10 +180,12 @@ ppm db test <name>
|
|
|
179
180
|
|
|
180
181
|
ppm db tables <name>
|
|
181
182
|
List tables in a database connection
|
|
183
|
+
--json — Output as JSON
|
|
182
184
|
|
|
183
185
|
ppm db schema <name> <table>
|
|
184
186
|
Show table schema (columns, types, constraints)
|
|
185
187
|
-s, --schema <schema> — PostgreSQL schema name [default: public]
|
|
188
|
+
--json — Output as JSON
|
|
186
189
|
|
|
187
190
|
ppm db data <name> <table>
|
|
188
191
|
View table data (paginated)
|
|
@@ -191,9 +194,11 @@ ppm db data <name> <table>
|
|
|
191
194
|
--order <column> — Order by column
|
|
192
195
|
--desc — Descending order
|
|
193
196
|
-s, --schema <schema> — PostgreSQL schema name [default: public]
|
|
197
|
+
--json — Output as JSON
|
|
194
198
|
|
|
195
199
|
ppm db query <name> <sql>
|
|
196
200
|
Execute a SQL query against a saved connection
|
|
201
|
+
--json — Output as JSON
|
|
197
202
|
\`\`\`
|
|
198
203
|
## ppm autostart — Auto-start on boot
|
|
199
204
|
\`\`\`
|
|
@@ -322,6 +327,6 @@ ppm bot memory forget "<topic>"
|
|
|
322
327
|
\`\`\`
|
|
323
328
|
|
|
324
329
|
## Tips
|
|
325
|
-
- Use \`--json\` flag when parsing command output programmatically
|
|
330
|
+
- Use \`--json\` flag when parsing command output programmatically (available on most list/status commands — check \`--help\`)
|
|
326
331
|
- For git/chat/db operations: always specify \`--project <name>\` or connection name
|
|
327
332
|
`;
|