@hienlh/ppm 0.13.54 → 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.
Files changed (121) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/http-api.md +7 -1
  4. package/dist/web/assets/ai-settings-section-AxLbNnLW.js +1 -0
  5. package/dist/web/assets/{api-settings-C3T95dWg.js → api-settings-BJTjIG4U.js} +1 -1
  6. package/dist/web/assets/architecture-PBZL5I3N-CkdUQjA_.js +1 -0
  7. package/dist/web/assets/arrow-down-D825m4vm.js +1 -0
  8. package/dist/web/assets/{audio-preview-BF1LU0eY.js → audio-preview-B53oeW0y.js} +1 -1
  9. package/dist/web/assets/chat-tab-Clzw7eDP.js +16 -0
  10. package/dist/web/assets/chevron-down-BMo4cBth.js +1 -0
  11. package/dist/web/assets/code-editor-BgU5lFVC.js +8 -0
  12. package/dist/web/assets/{conflict-editor-DcVj0Z-q.js → conflict-editor-C3l3pgtV.js} +3 -3
  13. package/dist/web/assets/csv-parser-D1b_lg2T.js +6 -0
  14. package/dist/web/assets/{csv-preview-B3Dyhgho.js → csv-preview-asMfgR0r.js} +2 -2
  15. package/dist/web/assets/{data-grid-overlay-editor-C1UUm7Ob.js → data-grid-overlay-editor-DGjqvYn6.js} +1 -1
  16. package/dist/web/assets/database-viewer-DNYgu_Jv.js +1 -0
  17. package/dist/web/assets/diff-viewer-Dec4mKgl.js +4 -0
  18. package/dist/web/assets/{esm-DCbn6xno.js → esm-xVTUq__o.js} +1 -1
  19. package/dist/web/assets/{extension-webview-DCmfZH6p.js → extension-webview-b7T0yAq2.js} +1 -1
  20. package/dist/web/assets/eye-off-BacF7RVS.js +1 -0
  21. package/dist/web/assets/git-log-panel-CWTTJERX.js +1 -0
  22. package/dist/web/assets/gitGraph-HDMCJU4V-D3UR56AG.js +1 -0
  23. package/dist/web/assets/glide-data-grid-_9gGGfZy.js +136 -0
  24. package/dist/web/assets/{image-preview-BIJGvZ5-.js → image-preview-CzXKlWft.js} +1 -1
  25. package/dist/web/assets/index-1_isAfRS.js +27 -0
  26. package/dist/web/assets/index-CDPVPZHJ.css +2 -0
  27. package/dist/web/assets/info-3K5VOQVL-DUhLSKI2.js +1 -0
  28. package/dist/web/assets/{input-_LFQwhzd.js → input-By_lZeCs.js} +1 -1
  29. package/dist/web/assets/keybindings-store-BicDU0b1.js +1 -0
  30. package/dist/web/assets/{markdown-renderer-CwKRCQuc.js → markdown-renderer-DWIBF9Jg.js} +3 -3
  31. package/dist/web/assets/notification-store-D_2wCv0z.js +1 -0
  32. package/dist/web/assets/{number-overlay-editor-CyEqxXcg.js → number-overlay-editor-DtUBprPW.js} +1 -1
  33. package/dist/web/assets/packet-RMMSAZCW-BIpeVUGW.js +1 -0
  34. package/dist/web/assets/panel-store-C9VAhbZz.js +1 -0
  35. package/dist/web/assets/{pdf-preview-CbUTv4dX.js → pdf-preview-C51mDesS.js} +1 -1
  36. package/dist/web/assets/pie-UPGHQEXC-CNoizzjb.js +1 -0
  37. package/dist/web/assets/port-forwarding-tab-BmRMiN32.js +1 -0
  38. package/dist/web/assets/{postgres-viewer-C-A4MMtt.js → postgres-viewer-DuiEoUGK.js} +3 -3
  39. package/dist/web/assets/project-store-DlbHpIq0.js +1 -0
  40. package/dist/web/assets/radar-KQ55EAFF-7dns-ho5.js +1 -0
  41. package/dist/web/assets/{settings-store-8FpQDjEA.js → settings-store-DQUFTPk2.js} +2 -2
  42. package/dist/web/assets/settings-tab-p3lxp6_T.js +1 -0
  43. package/dist/web/assets/{sql-query-editor-Cu9mYyfb.js → sql-query-editor-BA80nuKp.js} +1 -1
  44. package/dist/web/assets/{sqlite-viewer-D6ngJJgP.js → sqlite-viewer-Bev2XJe7.js} +1 -1
  45. package/dist/web/assets/system-monitor-tab-DfpsOgL3.js +1 -0
  46. package/dist/web/assets/{tab-store-CNas5Ny8.js → tab-store-CIcbSn0c.js} +1 -1
  47. package/dist/web/assets/{terminal-tab-CyuBxW2x.js → terminal-tab-Ca5kyUS7.js} +2 -2
  48. package/dist/web/assets/treemap-KZPCXAKY-D3DZCLoE.js +1 -0
  49. package/dist/web/assets/{use-blob-url-DB4nNruT.js → use-blob-url-VgTGpely.js} +1 -1
  50. package/dist/web/assets/{use-monaco-theme-DEI-tJAh.js → use-monaco-theme-BLIgarH5.js} +1 -1
  51. package/dist/web/assets/{vendor-mermaid-D2KKkqNs.js → vendor-mermaid-DkqjpqJK.js} +2 -2
  52. package/dist/web/assets/{video-preview-ChP5ypMo.js → video-preview-Bvd0OaYA.js} +1 -1
  53. package/dist/web/assets/wifi-LJEyIdXf.js +1 -0
  54. package/dist/web/index.html +21 -20
  55. package/dist/web/sw.js +1 -1
  56. package/docs/project-changelog.md +38 -1
  57. package/docs/system-architecture.md +2 -1
  58. package/package.json +1 -1
  59. package/packages/ext-git-graph/src/webview-html.ts +29 -8
  60. package/src/server/index.ts +4 -0
  61. package/src/server/middleware/auth.ts +9 -0
  62. package/src/server/routes/resources.ts +61 -0
  63. package/src/services/resource-monitor-utils.ts +129 -0
  64. package/src/services/resource-monitor.service.ts +122 -0
  65. package/src/web/components/git/git-log-panel.tsx +206 -0
  66. package/src/web/components/git/git-ref-badge.tsx +150 -0
  67. package/src/web/components/git/git-status-panel.tsx +18 -0
  68. package/src/web/components/layout/mobile-nav.tsx +2 -0
  69. package/src/web/components/layout/sidebar.tsx +6 -0
  70. package/src/web/components/layout/tab-bar.tsx +3 -0
  71. package/src/web/components/layout/tab-content.tsx +10 -0
  72. package/src/web/components/layout/tab-pool.tsx +2 -0
  73. package/src/web/components/system/resource-status-bar.tsx +66 -0
  74. package/src/web/components/system/sparkline-canvas.tsx +64 -0
  75. package/src/web/components/system/system-monitor-tab.tsx +194 -0
  76. package/src/web/hooks/use-resource-monitor.ts +114 -0
  77. package/src/web/stores/panel-store.ts +1 -1
  78. package/src/web/stores/tab-store.ts +3 -1
  79. package/dist/web/assets/ai-settings-section-AuV6Lzz2.js +0 -1
  80. package/dist/web/assets/architecture-PBZL5I3N-fAJMexNi.js +0 -1
  81. package/dist/web/assets/chat-tab-CCOkAmh8.js +0 -16
  82. package/dist/web/assets/code-editor-BptkAFVa.js +0 -8
  83. package/dist/web/assets/csv-parser-Dly5nqE1.js +0 -6
  84. package/dist/web/assets/database-viewer-CYrsNjRy.js +0 -1
  85. package/dist/web/assets/diff-viewer-DMBviO6l.js +0 -4
  86. package/dist/web/assets/file-store-DOxcU_7s.js +0 -1
  87. package/dist/web/assets/gitGraph-HDMCJU4V-ClRAoBAn.js +0 -1
  88. package/dist/web/assets/glide-data-grid-DhZjCUqu.js +0 -136
  89. package/dist/web/assets/index-BA8zQtSN.js +0 -27
  90. package/dist/web/assets/index-CKKoR3gY.css +0 -2
  91. package/dist/web/assets/info-3K5VOQVL-D8uyBfC_.js +0 -1
  92. package/dist/web/assets/keybindings-store-BXumit4n.js +0 -1
  93. package/dist/web/assets/notification-store-B3Fgo6Qw.js +0 -1
  94. package/dist/web/assets/packet-RMMSAZCW-BJj3FH_w.js +0 -1
  95. package/dist/web/assets/panel-store-C8wwxBpn.js +0 -1
  96. package/dist/web/assets/pie-UPGHQEXC-BKfHRBz7.js +0 -1
  97. package/dist/web/assets/port-forwarding-tab-Nn3-C-Vu.js +0 -1
  98. package/dist/web/assets/radar-KQ55EAFF-DkybKTt9.js +0 -1
  99. package/dist/web/assets/scroll-area-BDi_FNzr.js +0 -1
  100. package/dist/web/assets/settings-tab-Bzlcvim9.js +0 -1
  101. package/dist/web/assets/treemap-KZPCXAKY-BvDgIWW9.js +0 -1
  102. /package/dist/web/assets/{api-client-DIhJ5qVW.js → api-client-BK4NPNoY.js} +0 -0
  103. /package/dist/web/assets/{chevron-right-DnHIvvcy.js → chevron-right-CD8e6Aj4.js} +0 -0
  104. /package/dist/web/assets/{code-DGBecc50.js → code-DiNmA3eR.js} +0 -0
  105. /package/dist/web/assets/{data-grid-types-D2cHE8hx.js → data-grid-types-DzL5W2em.js} +0 -0
  106. /package/dist/web/assets/{database-DOWH9-Vv.js → database-Dc8mr-dP.js} +0 -0
  107. /package/dist/web/assets/{dist-BoIkGNC8.js → dist-BM2EHhLH.js} +0 -0
  108. /package/dist/web/assets/{dist-DVk8T0R5.js → dist-CohudVKa.js} +0 -0
  109. /package/dist/web/assets/{file-exclamation-point-BwzaQ50n.js → file-exclamation-point-B__2Hrd6.js} +0 -0
  110. /package/dist/web/assets/{globe-B4Ilypbs.js → globe-CQ8NAYvi.js} +0 -0
  111. /package/dist/web/assets/{katex-C10ndCVt.js → katex-CHaeM9QC.js} +0 -0
  112. /package/dist/web/assets/{lib-C2D8j3K3.js → lib-LPmTkMu4.js} +0 -0
  113. /package/dist/web/assets/{react-DMIOAtcX.js → react-DHBl6KRc.js} +0 -0
  114. /package/dist/web/assets/{refresh-cw-BjrAbUJe.js → refresh-cw-CRD2qr4U.js} +0 -0
  115. /package/dist/web/assets/{search-tM8K5zWU.js → search-D90WJ5fo.js} +0 -0
  116. /package/dist/web/assets/{sparkles-CulWHe4c.js → sparkles-KCOEy7QI.js} +0 -0
  117. /package/dist/web/assets/{table-BzjWcs87.js → table-2wDtM4_B.js} +0 -0
  118. /package/dist/web/assets/{text-wrap-DJz9Bgpa.js → text-wrap-AZErifCu.js} +0 -0
  119. /package/dist/web/assets/{utils-CQux7CsO.js → utils-CSCvNZxE.js} +0 -0
  120. /package/dist/web/assets/{vendor-xterm-D1P36hcr.js → vendor-xterm-vh96p1Au.js} +0 -0
  121. /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-BwzaQ50n.js";import"./api-client-DIhJ5qVW.js";import{q as n}from"./index-BA8zQtSN.js";import{t as r}from"./use-blob-url-DB4nNruT.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};
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};
@@ -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-BA8zQtSN.js"></script>
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-D2KKkqNs.js">
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-CQux7CsO.js">
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-BPReZWnP.js">
50
- <link rel="modulepreload" crossorigin href="/assets/input-_LFQwhzd.js">
51
- <link rel="modulepreload" crossorigin href="/assets/react-DMIOAtcX.js">
52
- <link rel="modulepreload" crossorigin href="/assets/api-client-DIhJ5qVW.js">
53
- <link rel="modulepreload" crossorigin href="/assets/settings-store-8FpQDjEA.js">
54
- <link rel="modulepreload" crossorigin href="/assets/scroll-area-BDi_FNzr.js">
55
- <link rel="modulepreload" crossorigin href="/assets/globe-B4Ilypbs.js">
56
- <link rel="modulepreload" crossorigin href="/assets/refresh-cw-BjrAbUJe.js">
57
- <link rel="modulepreload" crossorigin href="/assets/api-settings-C3T95dWg.js">
58
- <link rel="modulepreload" crossorigin href="/assets/ai-settings-section-AuV6Lzz2.js">
59
- <link rel="modulepreload" crossorigin href="/assets/database-DOWH9-Vv.js">
60
- <link rel="modulepreload" crossorigin href="/assets/chevron-right-DnHIvvcy.js">
61
- <link rel="modulepreload" crossorigin href="/assets/search-tM8K5zWU.js">
62
- <link rel="modulepreload" crossorigin href="/assets/file-store-DOxcU_7s.js">
63
- <link rel="modulepreload" crossorigin href="/assets/panel-store-C8wwxBpn.js">
64
- <link rel="modulepreload" crossorigin href="/assets/tab-store-CNas5Ny8.js">
65
- <link rel="stylesheet" crossorigin href="/assets/index-CKKoR3gY.css">
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":"1b3bf6d92b305b4a210194c0d9c86584","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-DhZjCUqu.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/table-BzjWcs87.js"},{"revision":null,"url":"assets/markdown-renderer-CwKRCQuc.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/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/github.min-D2BCvnWf.css"},{"revision":null,"url":"assets/database-DOWH9-Vv.js"},{"revision":null,"url":"assets/database-viewer-CYrsNjRy.js"},{"revision":null,"url":"assets/dist-DVk8T0R5.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/scroll-area-BDi_FNzr.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-fAJMexNi.js"},{"revision":null,"url":"assets/glide-data-grid-nthEL3fk.css"},{"revision":null,"url":"assets/audio-preview-BF1LU0eY.js"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/image-preview-BIJGvZ5-.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/index-BA8zQtSN.js"},{"revision":null,"url":"assets/code-editor-BptkAFVa.js"},{"revision":null,"url":"assets/vendor-mermaid-D2KKkqNs.js"},{"revision":null,"url":"assets/dist-BoIkGNC8.js"},{"revision":null,"url":"assets/keybindings-store-BXumit4n.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/notification-store-B3Fgo6Qw.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/sqlite-viewer-D6ngJJgP.js"},{"revision":null,"url":"assets/use-monaco-theme-DEI-tJAh.js"},{"revision":null,"url":"assets/vendor-ui-UXCWAcmi.js"},{"revision":null,"url":"assets/pdf-preview-CbUTv4dX.js"},{"revision":null,"url":"assets/code-DGBecc50.js"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/chat-tab-CCOkAmh8.js"},{"revision":null,"url":"assets/github-dark-dimmed.min-BrpRStFV.css"},{"revision":null,"url":"assets/extension-webview-DCmfZH6p.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/port-forwarding-tab-Nn3-C-Vu.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/csv-preview-B3Dyhgho.js"},{"revision":null,"url":"assets/settings-tab-Bzlcvim9.js"},{"revision":null,"url":"assets/video-preview-ChP5ypMo.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/conflict-editor-DcVj0Z-q.js"},{"revision":null,"url":"assets/terminal-tab-CyuBxW2x.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/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/postgres-viewer-C-A4MMtt.js"},{"revision":null,"url":"assets/diff-viewer-DMBviO6l.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/index-CKKoR3gY.css"},{"revision":null,"url":"assets/sql-query-editor-Cu9mYyfb.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||`/`)}))});
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.13.54",
3
+ "version": "0.13.55",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
@@ -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-block; padding: 0px 5px; border-radius: 3px; font-size: 9px; font-weight: 600; margin-right: 3px; vertical-align: middle; line-height: 16px; }
266
- .ref-head { background: var(--green); color: #fff; }
267
- .ref-local { background: var(--blue); color: #fff; }
268
- .ref-remote { background: var(--purple); color: #fff; }
269
- .ref-tag { background: var(--yellow); color: #000; }
270
- .ref-stash { background: #808080; color: #fff; }
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
- badges += '<span class="ref-badge ref-' + ref.type + '">' + escHtml(ref.name) + '</span>';
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);
@@ -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
+ });
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Pure utility functions for resource monitoring:
3
+ * ps output parsing, process tree building, and categorization.
4
+ */
5
+
6
+ import type { ProcessEntry, ResourceGroup } from "./resource-monitor.service.ts";
7
+
8
+ // ── Categorization patterns ────────────────────────────────────────────
9
+
10
+ const CATEGORY_PATTERNS: [ResourceGroup["type"], RegExp][] = [
11
+ ["terminal", /^(bash|zsh|sh|fish|csh|tcsh|dash|ksh|pwsh|powershell)$/i],
12
+ ["ai-tool", /^(claude|anthropic)/i],
13
+ ["build", /^(node|bun|tsc|vite|webpack|esbuild|turbo|rollup|swc)$/i],
14
+ ];
15
+
16
+ function categorize(cmd: string): ResourceGroup["type"] {
17
+ const basename = cmd.split("/").pop()?.split(" ")[0] ?? cmd;
18
+ for (const [type, re] of CATEGORY_PATTERNS) {
19
+ if (re.test(basename)) return type;
20
+ }
21
+ return "unknown";
22
+ }
23
+
24
+ // ── Parser ─────────────────────────────────────────────────────────────
25
+
26
+ /** Parse `ps -e -o pid,ppid,%cpu,rss,args` output into structured entries */
27
+ export function parseProcessList(stdout: string): ProcessEntry[] {
28
+ const lines = stdout.trim().split("\n");
29
+ if (lines.length < 2) return [];
30
+
31
+ const entries: ProcessEntry[] = [];
32
+ for (let i = 1; i < lines.length; i++) {
33
+ const line = lines[i]?.trim();
34
+ if (!line) continue;
35
+ const parts = line.split(/\s+/);
36
+ if (parts.length < 5) continue;
37
+
38
+ const pid = parseInt(parts[0]!, 10);
39
+ const ppid = parseInt(parts[1]!, 10);
40
+ const cpu = parseFloat(parts[2]!);
41
+ const rssKB = parseInt(parts[3]!, 10);
42
+ const command = parts.slice(4).join(" ");
43
+
44
+ if (isNaN(pid) || pid === 0 || !command) continue;
45
+
46
+ entries.push({
47
+ pid,
48
+ ppid,
49
+ cpu: Math.round(cpu * 10) / 10,
50
+ ramMB: Math.round((rssKB / 1024) * 10) / 10,
51
+ command,
52
+ });
53
+ }
54
+ return entries;
55
+ }
56
+
57
+ // ── Tree builder ───────────────────────────────────────────────────────
58
+
59
+ /** Build flat list of all descendants of rootPid via ppid traversal */
60
+ export function buildTree(entries: ProcessEntry[], rootPid: number): ProcessEntry[] {
61
+ const childMap = new Map<number, ProcessEntry[]>();
62
+ for (const e of entries) {
63
+ const list = childMap.get(e.ppid) ?? [];
64
+ list.push(e);
65
+ childMap.set(e.ppid, list);
66
+ }
67
+
68
+ const result: ProcessEntry[] = [];
69
+ const queue = [rootPid];
70
+ while (queue.length > 0) {
71
+ const pid = queue.shift()!;
72
+ const children = childMap.get(pid) ?? [];
73
+ for (const child of children) {
74
+ result.push(child);
75
+ queue.push(child.pid);
76
+ }
77
+ }
78
+ return result;
79
+ }
80
+
81
+ // ── Grouping ───────────────────────────────────────────────────────────
82
+
83
+ const TYPE_LABELS: Record<ResourceGroup["type"], string> = {
84
+ server: "PPM Server",
85
+ terminal: "Terminals",
86
+ "ai-tool": "AI Tools",
87
+ build: "Build Tools",
88
+ unknown: "Other",
89
+ };
90
+
91
+ /** Group processes into resource groups by category */
92
+ export function groupProcesses(
93
+ serverEntry: ProcessEntry | undefined,
94
+ children: ProcessEntry[],
95
+ ): ResourceGroup[] {
96
+ const groups: ResourceGroup[] = [];
97
+
98
+ if (serverEntry) {
99
+ groups.push({
100
+ type: "server",
101
+ label: "PPM Server",
102
+ cpu: serverEntry.cpu,
103
+ ramMB: serverEntry.ramMB,
104
+ processes: [{ pid: serverEntry.pid, cpu: serverEntry.cpu, ramMB: serverEntry.ramMB, command: serverEntry.command }],
105
+ });
106
+ }
107
+
108
+ const buckets = new Map<ResourceGroup["type"], ProcessEntry[]>();
109
+ for (const child of children) {
110
+ const type = categorize(child.command);
111
+ const list = buckets.get(type) ?? [];
112
+ list.push(child);
113
+ buckets.set(type, list);
114
+ }
115
+
116
+ for (const type of ["terminal", "ai-tool", "build", "unknown"] as const) {
117
+ const procs = buckets.get(type);
118
+ if (!procs?.length) continue;
119
+ groups.push({
120
+ type,
121
+ label: TYPE_LABELS[type],
122
+ cpu: Math.round(procs.reduce((s, p) => s + p.cpu, 0) * 10) / 10,
123
+ ramMB: Math.round(procs.reduce((s, p) => s + p.ramMB, 0) * 10) / 10,
124
+ processes: procs.map((p) => ({ pid: p.pid, cpu: p.cpu, ramMB: p.ramMB, command: p.command })),
125
+ });
126
+ }
127
+
128
+ return groups;
129
+ }