@hienlh/ppm 0.9.6 → 0.9.8

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 (111) hide show
  1. package/.claude.bak/agent-memory/tester/MEMORY.md +3 -0
  2. package/.claude.bak/agent-memory/tester/project-ppm-test-conventions.md +32 -0
  3. package/CHANGELOG.md +21 -0
  4. package/bun.lock +129 -7
  5. package/dist/web/assets/{architectureDiagram-2XIMDMQ5-Z-4eN4za.js → architectureDiagram-2XIMDMQ5-DWBCPMLF.js} +1 -1
  6. package/dist/web/assets/{blockDiagram-WCTKOSBZ-BCLqzhuZ.js → blockDiagram-WCTKOSBZ-TEF8Ally.js} +1 -1
  7. package/dist/web/assets/browser-tab-zJXwFb1y.js +1 -0
  8. package/dist/web/assets/{c4Diagram-IC4MRINW-0Vp0Jeas.js → c4Diagram-IC4MRINW-dV22iAsY.js} +1 -1
  9. package/dist/web/assets/channel-wrd-NHWf.js +1 -0
  10. package/dist/web/assets/chat-tab-CFyDR47n.js +8 -0
  11. package/dist/web/assets/{chunk-7R4GIKGN-Dv-4cAYn.js → chunk-7R4GIKGN-BbIFzsIv.js} +1 -1
  12. package/dist/web/assets/{chunk-GEFDOKGD-D-pKjlVd.js → chunk-GEFDOKGD-BbQkJu8C.js} +1 -1
  13. package/dist/web/assets/{chunk-GLR3WWYH-DKikpoJM.js → chunk-GLR3WWYH-CzYx4w-r.js} +2 -2
  14. package/dist/web/assets/{chunk-HHEYEP7N-C7vxA5i9.js → chunk-HHEYEP7N-HRhYy3kG.js} +1 -1
  15. package/dist/web/assets/{chunk-JSJVCQXG-99JzIdPr.js → chunk-JSJVCQXG-23tyvw8k.js} +1 -1
  16. package/dist/web/assets/{chunk-KX2RTZJC-CRq1OBZv.js → chunk-KX2RTZJC-sQ0o-39C.js} +1 -1
  17. package/dist/web/assets/{chunk-KYZI473N-Bb0MCaIO.js → chunk-KYZI473N-BcUZNnwd.js} +1 -1
  18. package/dist/web/assets/{chunk-NQ4KR5QH-z_blpjxi.js → chunk-NQ4KR5QH-wMgTlP7f.js} +1 -1
  19. package/dist/web/assets/{chunk-O4XLMI2P-nDhi_cVu.js → chunk-O4XLMI2P-JC6EGoUz.js} +1 -1
  20. package/dist/web/assets/{chunk-PQ6SQG4A-TF58UVMU.js → chunk-PQ6SQG4A-D6BTbCQw.js} +1 -1
  21. package/dist/web/assets/{chunk-PU5JKC2W-ek7k4QVB.js → chunk-PU5JKC2W-Dw8ClWch.js} +1 -1
  22. package/dist/web/assets/{chunk-WL4C6EOR-ByUrSRin.js → chunk-WL4C6EOR-DfofndiH.js} +1 -1
  23. package/dist/web/assets/{chunk-YBOYWFTD-rQG3QH5s.js → chunk-YBOYWFTD-CeU4Q-xC.js} +1 -1
  24. package/dist/web/assets/classDiagram-VBA2DB6C-lse8oZoJ.js +1 -0
  25. package/dist/web/assets/classDiagram-v2-RAHNMMFH-CxkwuInd.js +1 -0
  26. package/dist/web/assets/code-editor-LX1U5zLR.js +2 -0
  27. package/dist/web/assets/{csv-preview-ncSOnJSC.js → csv-preview-Doo6XsK0.js} +1 -1
  28. package/dist/web/assets/{dagre-DHq9bhnd.js → dagre-Dbb5k38K.js} +1 -1
  29. package/dist/web/assets/{dagre-KLK3FWXG-BdJr7Byp.js → dagre-KLK3FWXG-BH7aWGRP.js} +1 -1
  30. package/dist/web/assets/database-viewer-DeQyA5LK.js +1 -0
  31. package/dist/web/assets/{diagram-E7M64L7V-_db4pBVA.js → diagram-E7M64L7V-B1Qz70Do.js} +1 -1
  32. package/dist/web/assets/{diagram-IFDJBPK2-xKoeuiJx.js → diagram-IFDJBPK2-k55eVqVU.js} +1 -1
  33. package/dist/web/assets/{diagram-P4PSJMXO-C8tjJsev.js → diagram-P4PSJMXO-BkfNRc9U.js} +1 -1
  34. package/dist/web/assets/{diff-viewer-BdeL1mp2.js → diff-viewer-BiXgYdZ8.js} +1 -1
  35. package/dist/web/assets/dist-C4urk5JP.js +41 -0
  36. package/dist/web/assets/{dist-ovWkrgO-.js → dist-wVfsYfHS.js} +1 -1
  37. package/dist/web/assets/{erDiagram-INFDFZHY-BSh2z9Df.js → erDiagram-INFDFZHY-CKzVujYI.js} +1 -1
  38. package/dist/web/assets/{extension-webview-BAClIyub.js → extension-webview-DLlIuZOQ.js} +1 -1
  39. package/dist/web/assets/{flowDiagram-PKNHOUZH-oYaovqyp.js → flowDiagram-PKNHOUZH-DIqcTrDV.js} +1 -1
  40. package/dist/web/assets/{ganttDiagram-A5KZAMGK-DmL26q2P.js → ganttDiagram-A5KZAMGK-D4v7ZbVE.js} +1 -1
  41. package/dist/web/assets/git-graph-BpchaeYc.js +1 -0
  42. package/dist/web/assets/{gitGraphDiagram-K3NZZRJ6-CMoukSrY.js → gitGraphDiagram-K3NZZRJ6-BTXo57mF.js} +1 -1
  43. package/dist/web/assets/index-D-Vtz6Oy.js +37 -0
  44. package/dist/web/assets/index-D3XyoeN3.css +2 -0
  45. package/dist/web/assets/{infoDiagram-LFFYTUFH-DWwumDkq.js → infoDiagram-LFFYTUFH-B1CX0pbC.js} +1 -1
  46. package/dist/web/assets/{ishikawaDiagram-PHBUUO56-D05_LyL7.js → ishikawaDiagram-PHBUUO56-BOyvKMmB.js} +1 -1
  47. package/dist/web/assets/{journeyDiagram-4ABVD52K-B_L20qMe.js → journeyDiagram-4ABVD52K-ufoasAy6.js} +1 -1
  48. package/dist/web/assets/{kanban-definition-K7BYSVSG-CZ535BbZ.js → kanban-definition-K7BYSVSG-Bi0UTUeN.js} +1 -1
  49. package/dist/web/assets/keybindings-store-DMXYSZfe.js +1 -0
  50. package/dist/web/assets/{line-CVvo3dRu.js → line-B78g-52T.js} +1 -1
  51. package/dist/web/assets/{markdown-renderer-COndDkRD.js → markdown-renderer-_FS3Bpm9.js} +5 -5
  52. package/dist/web/assets/{mermaid-parser.core-C7UwoIh6.js → mermaid-parser.core-DMIWdgEW.js} +1 -1
  53. package/dist/web/assets/{mindmap-definition-YRQLILUH-x0MTutJp.js → mindmap-definition-YRQLILUH-BsfWvIoO.js} +1 -1
  54. package/dist/web/assets/{pieDiagram-SKSYHLDU-C1Gjrtzy.js → pieDiagram-SKSYHLDU-WP0XXw51.js} +1 -1
  55. package/dist/web/assets/postgres-viewer-BdFwZzy1.js +1 -0
  56. package/dist/web/assets/{quadrantDiagram-337W2JSQ-C8bzJCjQ.js → quadrantDiagram-337W2JSQ-FHMogtsh.js} +1 -1
  57. package/dist/web/assets/{requirementDiagram-Z7DCOOCP-pQyah6WB.js → requirementDiagram-Z7DCOOCP-BatTxyWb.js} +1 -1
  58. package/dist/web/assets/{sankeyDiagram-WA2Y5GQK-T6RgG-N8.js → sankeyDiagram-WA2Y5GQK-ClJuW3Hv.js} +1 -1
  59. package/dist/web/assets/{sequenceDiagram-2WXFIKYE-BQDJ4CVs.js → sequenceDiagram-2WXFIKYE-ByxQqGgs.js} +1 -1
  60. package/dist/web/assets/{settings-tab-CiDK6Jf2.js → settings-tab-DyqD7Rr6.js} +1 -1
  61. package/dist/web/assets/sqlite-viewer-BlT-kB8c.js +1 -0
  62. package/dist/web/assets/{stateDiagram-RAJIS63D-66vhiIuk.js → stateDiagram-RAJIS63D-f8opcZNY.js} +1 -1
  63. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-DrxVDY9q.js +1 -0
  64. package/dist/web/assets/{tab-store-BOgTrqRr.js → tab-store-CeOacjuH.js} +1 -1
  65. package/dist/web/assets/{terminal-tab-BvExlsRm.js → terminal-tab-DfplMwBA.js} +1 -1
  66. package/dist/web/assets/{timeline-definition-YZTLITO2-DwZqB3nn.js → timeline-definition-YZTLITO2-58BlOSf9.js} +1 -1
  67. package/dist/web/assets/{use-monaco-theme-BsMRP0ci.js → use-monaco-theme-DjfHhwSf.js} +1 -1
  68. package/dist/web/assets/{vennDiagram-LZ73GAT5-s9Z71fz-.js → vennDiagram-LZ73GAT5-BOSy9ma9.js} +1 -1
  69. package/dist/web/assets/{xychartDiagram-JWTSCODW-DRa_TH4B.js → xychartDiagram-JWTSCODW-z5MVJauZ.js} +1 -1
  70. package/dist/web/index.html +8 -8
  71. package/dist/web/sw.js +1 -1
  72. package/docs/project-changelog.md +31 -1
  73. package/docs/project-roadmap.md +4 -1
  74. package/package.json +3 -1
  75. package/src/server/helpers/error-status.ts +10 -0
  76. package/src/server/middleware/auth.ts +17 -6
  77. package/src/server/routes/file-download.ts +63 -0
  78. package/src/server/routes/files.ts +8 -17
  79. package/src/server/routes/project-scoped.ts +2 -0
  80. package/src/services/download-token.service.ts +37 -0
  81. package/src/web/components/chat/chat-history-bar.tsx +26 -36
  82. package/src/web/components/chat/chat-tab.tsx +0 -1
  83. package/src/web/components/chat/usage-badge.tsx +23 -10
  84. package/src/web/components/editor/code-editor.tsx +2 -0
  85. package/src/web/components/editor/editor-toolbar.tsx +14 -1
  86. package/src/web/components/explorer/file-tree.tsx +15 -0
  87. package/src/web/lib/file-download.ts +27 -0
  88. package/dist/web/assets/browser-tab-DOcEOjEa.js +0 -1
  89. package/dist/web/assets/channel-By7bn0Yq.js +0 -1
  90. package/dist/web/assets/chat-tab-Ck-DKBcT.js +0 -8
  91. package/dist/web/assets/classDiagram-VBA2DB6C-BA8Nj-_C.js +0 -1
  92. package/dist/web/assets/classDiagram-v2-RAHNMMFH-DjYu-6mn.js +0 -1
  93. package/dist/web/assets/code-editor-pu7p8kxA.js +0 -2
  94. package/dist/web/assets/database-viewer-Byj9izvr.js +0 -1
  95. package/dist/web/assets/dist-DIV6WgAG.js +0 -41
  96. package/dist/web/assets/git-graph-DnXGjims.js +0 -1
  97. package/dist/web/assets/index-C6uPEeqG.js +0 -37
  98. package/dist/web/assets/index-CjwJM7yL.css +0 -2
  99. package/dist/web/assets/keybindings-store-DclBEjd4.js +0 -1
  100. package/dist/web/assets/postgres-viewer-CQODrSyu.js +0 -1
  101. package/dist/web/assets/sqlite-viewer-kMmzSn7j.js +0 -1
  102. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-BGVqj_g9.js +0 -1
  103. package/docs/streaming-input-guide.md +0 -267
  104. package/snapshot-state.md +0 -1526
  105. package/test-session-ops.mjs +0 -444
  106. package/test-tokens.mjs +0 -212
  107. /package/dist/web/assets/{jsx-runtime-kMwlnEGE.js → jsx-runtime-O3jQaKZd.js} +0 -0
  108. /package/dist/web/assets/{preload-helper-Bf_JiD2A.js → preload-helper-uTix4PVD.js} +0 -0
  109. /package/dist/web/assets/{react-SKk5z-bm.js → react-ER-4DN55.js} +0 -0
  110. /package/dist/web/assets/{table-DFevCOMd.js → table-CWv1Oy39.js} +0 -0
  111. /package/dist/web/assets/{tag-CXMT0QB6.js → tag-CFrhsWuM.js} +0 -0
@@ -39,21 +39,21 @@
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-C6uPEeqG.js"></script>
42
+ <script type="module" crossorigin src="/assets/index-D-Vtz6Oy.js"></script>
43
43
  <link rel="modulepreload" crossorigin href="/assets/chunk-CFjPhJqf.js">
44
- <link rel="modulepreload" crossorigin href="/assets/preload-helper-Bf_JiD2A.js">
44
+ <link rel="modulepreload" crossorigin href="/assets/preload-helper-uTix4PVD.js">
45
45
  <link rel="modulepreload" crossorigin href="/assets/react-nm2Ru1Pt.js">
46
+ <link rel="modulepreload" crossorigin href="/assets/createLucideIcon-PuMiQgHl.js">
46
47
  <link rel="modulepreload" crossorigin href="/assets/react-dom-Bpkvzu3U.js">
47
- <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-kMwlnEGE.js">
48
- <link rel="modulepreload" crossorigin href="/assets/dist-DIV6WgAG.js">
48
+ <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-O3jQaKZd.js">
49
+ <link rel="modulepreload" crossorigin href="/assets/dist-C4urk5JP.js">
49
50
  <link rel="modulepreload" crossorigin href="/assets/utils-BNytJOb1.js">
50
- <link rel="modulepreload" crossorigin href="/assets/createLucideIcon-PuMiQgHl.js">
51
51
  <link rel="modulepreload" crossorigin href="/assets/chevron-right-5HgK6l7K.js">
52
- <link rel="modulepreload" crossorigin href="/assets/react-SKk5z-bm.js">
53
- <link rel="modulepreload" crossorigin href="/assets/tab-store-BOgTrqRr.js">
52
+ <link rel="modulepreload" crossorigin href="/assets/react-ER-4DN55.js">
53
+ <link rel="modulepreload" crossorigin href="/assets/tab-store-CeOacjuH.js">
54
54
  <link rel="modulepreload" crossorigin href="/assets/api-client-BfBM3I7n.js">
55
55
  <link rel="modulepreload" crossorigin href="/assets/api-settings-BUvk6Saw.js">
56
- <link rel="stylesheet" crossorigin href="/assets/index-CjwJM7yL.css">
56
+ <link rel="stylesheet" crossorigin href="/assets/index-D3XyoeN3.css">
57
57
  <link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
58
58
  <body class="bg-[#0f1419] text-[#e5e7eb] font-sans antialiased">
59
59
  <div id="root"></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":"a8204437b8db7ba021b6de4aff0de237","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.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":null,"url":"assets/xychartDiagram-JWTSCODW-DRa_TH4B.js"},{"revision":null,"url":"assets/vennDiagram-LZ73GAT5-s9Z71fz-.js"},{"revision":null,"url":"assets/utils-BNytJOb1.js"},{"revision":null,"url":"assets/use-monaco-theme-BsMRP0ci.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-B2Xkyv-K.js"},{"revision":null,"url":"assets/timeline-definition-YZTLITO2-DwZqB3nn.js"},{"revision":null,"url":"assets/terminal-tab-BvExlsRm.js"},{"revision":null,"url":"assets/terminal-tab-BrP-ENHg.css"},{"revision":null,"url":"assets/tag-CXMT0QB6.js"},{"revision":null,"url":"assets/table-DFevCOMd.js"},{"revision":null,"url":"assets/tab-store-BOgTrqRr.js"},{"revision":null,"url":"assets/stateDiagram-v2-FVOUBMTO-BGVqj_g9.js"},{"revision":null,"url":"assets/stateDiagram-RAJIS63D-66vhiIuk.js"},{"revision":null,"url":"assets/src-BqX54PbV.js"},{"revision":null,"url":"assets/sqlite-viewer-kMmzSn7j.js"},{"revision":null,"url":"assets/settings-tab-CiDK6Jf2.js"},{"revision":null,"url":"assets/sequenceDiagram-2WXFIKYE-BQDJ4CVs.js"},{"revision":null,"url":"assets/sankeyDiagram-WA2Y5GQK-T6RgG-N8.js"},{"revision":null,"url":"assets/rough.esm-JX0wREDd.js"},{"revision":null,"url":"assets/requirementDiagram-Z7DCOOCP-pQyah6WB.js"},{"revision":null,"url":"assets/react-nm2Ru1Pt.js"},{"revision":null,"url":"assets/react-dom-Bpkvzu3U.js"},{"revision":null,"url":"assets/react-SKk5z-bm.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-DH0AOkUy.js"},{"revision":null,"url":"assets/quadrantDiagram-337W2JSQ-C8bzJCjQ.js"},{"revision":null,"url":"assets/preload-helper-Bf_JiD2A.js"},{"revision":null,"url":"assets/postgres-viewer-CQODrSyu.js"},{"revision":null,"url":"assets/pieDiagram-SKSYHLDU-C1Gjrtzy.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-BHncZutv.js"},{"revision":null,"url":"assets/path-6uRLdFF7.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-DY5PNnZU.js"},{"revision":null,"url":"assets/ordinal-_K3x1fkz.js"},{"revision":null,"url":"assets/mindmap-definition-YRQLILUH-x0MTutJp.js"},{"revision":null,"url":"assets/mermaid-parser.core-C7UwoIh6.js"},{"revision":null,"url":"assets/math-069Z4SuC.js"},{"revision":null,"url":"assets/markdown-renderer-COndDkRD.js"},{"revision":null,"url":"assets/linear-DP4mkX3m.js"},{"revision":null,"url":"assets/line-CVvo3dRu.js"},{"revision":null,"url":"assets/lib-BQ34Db2e.js"},{"revision":null,"url":"assets/keybindings-store-DclBEjd4.js"},{"revision":null,"url":"assets/katex-Bqvo_ZG0.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-CZ535BbZ.js"},{"revision":null,"url":"assets/jsx-runtime-kMwlnEGE.js"},{"revision":null,"url":"assets/journeyDiagram-4ABVD52K-B_L20qMe.js"},{"revision":null,"url":"assets/ishikawaDiagram-PHBUUO56-D05_LyL7.js"},{"revision":null,"url":"assets/isEmpty-bnrF3Qbc.js"},{"revision":null,"url":"assets/isArrayLikeObject-B_v2FtYn.js"},{"revision":null,"url":"assets/init-DlZdxViB.js"},{"revision":null,"url":"assets/infoDiagram-LFFYTUFH-DWwumDkq.js"},{"revision":null,"url":"assets/info-3K5VOQVL-_vRxVNUm.js"},{"revision":null,"url":"assets/index-CjwJM7yL.css"},{"revision":null,"url":"assets/index-C6uPEeqG.js"},{"revision":null,"url":"assets/graphlib-BcsNnGcW.js"},{"revision":null,"url":"assets/gitGraphDiagram-K3NZZRJ6-CMoukSrY.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-Bwna3and.js"},{"revision":null,"url":"assets/git-graph-DnXGjims.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-DmL26q2P.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-oYaovqyp.js"},{"revision":null,"url":"assets/extension-webview-BAClIyub.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-BSh2z9Df.js"},{"revision":null,"url":"assets/dist-ovWkrgO-.js"},{"revision":null,"url":"assets/dist-DIV6WgAG.js"},{"revision":null,"url":"assets/dist-CSJdAyA9.js"},{"revision":null,"url":"assets/diff-viewer-BdeL1mp2.js"},{"revision":null,"url":"assets/diagram-P4PSJMXO-C8tjJsev.js"},{"revision":null,"url":"assets/diagram-IFDJBPK2-xKoeuiJx.js"},{"revision":null,"url":"assets/diagram-E7M64L7V-_db4pBVA.js"},{"revision":null,"url":"assets/defaultLocale-5eAKkKJC.js"},{"revision":null,"url":"assets/database-viewer-Byj9izvr.js"},{"revision":null,"url":"assets/dagre-KLK3FWXG-BdJr7Byp.js"},{"revision":null,"url":"assets/dagre-DHq9bhnd.js"},{"revision":null,"url":"assets/cytoscape.esm-BW-DbntU.js"},{"revision":null,"url":"assets/csv-preview-ncSOnJSC.js"},{"revision":null,"url":"assets/createLucideIcon-PuMiQgHl.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-B_AWZsOP.js"},{"revision":null,"url":"assets/columns-2-cEVJHYd7.js"},{"revision":null,"url":"assets/code-editor-pu7p8kxA.js"},{"revision":null,"url":"assets/clone-LRxlvnMj.js"},{"revision":null,"url":"assets/classDiagram-v2-RAHNMMFH-DjYu-6mn.js"},{"revision":null,"url":"assets/classDiagram-VBA2DB6C-BA8Nj-_C.js"},{"revision":null,"url":"assets/chunk-YBOYWFTD-rQG3QH5s.js"},{"revision":null,"url":"assets/chunk-XZSTWKYB-DxAOx4hG.js"},{"revision":null,"url":"assets/chunk-XPW4576I-BPQQBakK.js"},{"revision":null,"url":"assets/chunk-XIRO2GV7-Djlmrely.js"},{"revision":null,"url":"assets/chunk-WL4C6EOR-ByUrSRin.js"},{"revision":null,"url":"assets/chunk-R5LLSJPH-CFwSJijQ.js"},{"revision":null,"url":"assets/chunk-QZHKN3VN-CYaTbeZf.js"},{"revision":null,"url":"assets/chunk-PU5JKC2W-ek7k4QVB.js"},{"revision":null,"url":"assets/chunk-PQ6SQG4A-TF58UVMU.js"},{"revision":null,"url":"assets/chunk-OZEHJAEY-BXhYx3nO.js"},{"revision":null,"url":"assets/chunk-O4XLMI2P-nDhi_cVu.js"},{"revision":null,"url":"assets/chunk-NQ4KR5QH-z_blpjxi.js"},{"revision":null,"url":"assets/chunk-MX3YWQON-BpS_PtKp.js"},{"revision":null,"url":"assets/chunk-L3YUKLVL-C7qGJrfV.js"},{"revision":null,"url":"assets/chunk-KYZI473N-Bb0MCaIO.js"},{"revision":null,"url":"assets/chunk-KX2RTZJC-CRq1OBZv.js"},{"revision":null,"url":"assets/chunk-JSJVCQXG-99JzIdPr.js"},{"revision":null,"url":"assets/chunk-HHEYEP7N-C7vxA5i9.js"},{"revision":null,"url":"assets/chunk-GLR3WWYH-DKikpoJM.js"},{"revision":null,"url":"assets/chunk-GEFDOKGD-D-pKjlVd.js"},{"revision":null,"url":"assets/chunk-FMBD7UC4-DXncblvW.js"},{"revision":null,"url":"assets/chunk-EGIJ26TM-DzqmU2Z7.js"},{"revision":null,"url":"assets/chunk-CFjPhJqf.js"},{"revision":null,"url":"assets/chunk-C72U2L5F-D21mS_6G.js"},{"revision":null,"url":"assets/chunk-7R4GIKGN-Dv-4cAYn.js"},{"revision":null,"url":"assets/chunk-7E7YKBS2-CiyUJxNI.js"},{"revision":null,"url":"assets/chunk-55IACEB6-DJ6BynZ4.js"},{"revision":null,"url":"assets/chunk-4BX2VUAB-D4tOov49.js"},{"revision":null,"url":"assets/chevron-right-5HgK6l7K.js"},{"revision":null,"url":"assets/chat-tab-Ck-DKBcT.js"},{"revision":null,"url":"assets/channel-By7bn0Yq.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-0Vp0Jeas.js"},{"revision":null,"url":"assets/browser-tab-DOcEOjEa.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-BCLqzhuZ.js"},{"revision":null,"url":"assets/arrow-up-BYhx9ckd.js"},{"revision":null,"url":"assets/array-B9UHiPd-.js"},{"revision":null,"url":"assets/architectureDiagram-2XIMDMQ5-Z-4eN4za.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-DEO2f3VD.js"},{"revision":null,"url":"assets/arc-BAOivWpI.js"},{"revision":null,"url":"assets/api-settings-BUvk6Saw.js"},{"revision":null,"url":"assets/api-client-BfBM3I7n.js"},{"revision":null,"url":"assets/_baseUniq-BT4Ow4Kk.js"},{"revision":null,"url":"assets/_basePickBy-5PGDJbfF.js"},{"revision":"79c8870653c8f419f2e3323085e1f4be","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.png`,badge:`/icon-192.png`,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":"0d1b5eaf54bcd4aeb918fd0e8da6a704","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.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":null,"url":"assets/xychartDiagram-JWTSCODW-z5MVJauZ.js"},{"revision":null,"url":"assets/vennDiagram-LZ73GAT5-BOSy9ma9.js"},{"revision":null,"url":"assets/utils-BNytJOb1.js"},{"revision":null,"url":"assets/use-monaco-theme-DjfHhwSf.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-B2Xkyv-K.js"},{"revision":null,"url":"assets/timeline-definition-YZTLITO2-58BlOSf9.js"},{"revision":null,"url":"assets/terminal-tab-DfplMwBA.js"},{"revision":null,"url":"assets/terminal-tab-BrP-ENHg.css"},{"revision":null,"url":"assets/tag-CFrhsWuM.js"},{"revision":null,"url":"assets/table-CWv1Oy39.js"},{"revision":null,"url":"assets/tab-store-CeOacjuH.js"},{"revision":null,"url":"assets/stateDiagram-v2-FVOUBMTO-DrxVDY9q.js"},{"revision":null,"url":"assets/stateDiagram-RAJIS63D-f8opcZNY.js"},{"revision":null,"url":"assets/src-BqX54PbV.js"},{"revision":null,"url":"assets/sqlite-viewer-BlT-kB8c.js"},{"revision":null,"url":"assets/settings-tab-DyqD7Rr6.js"},{"revision":null,"url":"assets/sequenceDiagram-2WXFIKYE-ByxQqGgs.js"},{"revision":null,"url":"assets/sankeyDiagram-WA2Y5GQK-ClJuW3Hv.js"},{"revision":null,"url":"assets/rough.esm-JX0wREDd.js"},{"revision":null,"url":"assets/requirementDiagram-Z7DCOOCP-BatTxyWb.js"},{"revision":null,"url":"assets/react-nm2Ru1Pt.js"},{"revision":null,"url":"assets/react-dom-Bpkvzu3U.js"},{"revision":null,"url":"assets/react-ER-4DN55.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-DH0AOkUy.js"},{"revision":null,"url":"assets/quadrantDiagram-337W2JSQ-FHMogtsh.js"},{"revision":null,"url":"assets/preload-helper-uTix4PVD.js"},{"revision":null,"url":"assets/postgres-viewer-BdFwZzy1.js"},{"revision":null,"url":"assets/pieDiagram-SKSYHLDU-WP0XXw51.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-BHncZutv.js"},{"revision":null,"url":"assets/path-6uRLdFF7.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-DY5PNnZU.js"},{"revision":null,"url":"assets/ordinal-_K3x1fkz.js"},{"revision":null,"url":"assets/mindmap-definition-YRQLILUH-BsfWvIoO.js"},{"revision":null,"url":"assets/mermaid-parser.core-DMIWdgEW.js"},{"revision":null,"url":"assets/math-069Z4SuC.js"},{"revision":null,"url":"assets/markdown-renderer-_FS3Bpm9.js"},{"revision":null,"url":"assets/linear-DP4mkX3m.js"},{"revision":null,"url":"assets/line-B78g-52T.js"},{"revision":null,"url":"assets/lib-BQ34Db2e.js"},{"revision":null,"url":"assets/keybindings-store-DMXYSZfe.js"},{"revision":null,"url":"assets/katex-Bqvo_ZG0.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-Bi0UTUeN.js"},{"revision":null,"url":"assets/jsx-runtime-O3jQaKZd.js"},{"revision":null,"url":"assets/journeyDiagram-4ABVD52K-ufoasAy6.js"},{"revision":null,"url":"assets/ishikawaDiagram-PHBUUO56-BOyvKMmB.js"},{"revision":null,"url":"assets/isEmpty-bnrF3Qbc.js"},{"revision":null,"url":"assets/isArrayLikeObject-B_v2FtYn.js"},{"revision":null,"url":"assets/init-DlZdxViB.js"},{"revision":null,"url":"assets/infoDiagram-LFFYTUFH-B1CX0pbC.js"},{"revision":null,"url":"assets/info-3K5VOQVL-_vRxVNUm.js"},{"revision":null,"url":"assets/index-D3XyoeN3.css"},{"revision":null,"url":"assets/index-D-Vtz6Oy.js"},{"revision":null,"url":"assets/graphlib-BcsNnGcW.js"},{"revision":null,"url":"assets/gitGraphDiagram-K3NZZRJ6-BTXo57mF.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-Bwna3and.js"},{"revision":null,"url":"assets/git-graph-BpchaeYc.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-D4v7ZbVE.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-DIqcTrDV.js"},{"revision":null,"url":"assets/extension-webview-DLlIuZOQ.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-CKzVujYI.js"},{"revision":null,"url":"assets/dist-wVfsYfHS.js"},{"revision":null,"url":"assets/dist-CSJdAyA9.js"},{"revision":null,"url":"assets/dist-C4urk5JP.js"},{"revision":null,"url":"assets/diff-viewer-BiXgYdZ8.js"},{"revision":null,"url":"assets/diagram-P4PSJMXO-BkfNRc9U.js"},{"revision":null,"url":"assets/diagram-IFDJBPK2-k55eVqVU.js"},{"revision":null,"url":"assets/diagram-E7M64L7V-B1Qz70Do.js"},{"revision":null,"url":"assets/defaultLocale-5eAKkKJC.js"},{"revision":null,"url":"assets/database-viewer-DeQyA5LK.js"},{"revision":null,"url":"assets/dagre-KLK3FWXG-BH7aWGRP.js"},{"revision":null,"url":"assets/dagre-Dbb5k38K.js"},{"revision":null,"url":"assets/cytoscape.esm-BW-DbntU.js"},{"revision":null,"url":"assets/csv-preview-Doo6XsK0.js"},{"revision":null,"url":"assets/createLucideIcon-PuMiQgHl.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-B_AWZsOP.js"},{"revision":null,"url":"assets/columns-2-cEVJHYd7.js"},{"revision":null,"url":"assets/code-editor-LX1U5zLR.js"},{"revision":null,"url":"assets/clone-LRxlvnMj.js"},{"revision":null,"url":"assets/classDiagram-v2-RAHNMMFH-CxkwuInd.js"},{"revision":null,"url":"assets/classDiagram-VBA2DB6C-lse8oZoJ.js"},{"revision":null,"url":"assets/chunk-YBOYWFTD-CeU4Q-xC.js"},{"revision":null,"url":"assets/chunk-XZSTWKYB-DxAOx4hG.js"},{"revision":null,"url":"assets/chunk-XPW4576I-BPQQBakK.js"},{"revision":null,"url":"assets/chunk-XIRO2GV7-Djlmrely.js"},{"revision":null,"url":"assets/chunk-WL4C6EOR-DfofndiH.js"},{"revision":null,"url":"assets/chunk-R5LLSJPH-CFwSJijQ.js"},{"revision":null,"url":"assets/chunk-QZHKN3VN-CYaTbeZf.js"},{"revision":null,"url":"assets/chunk-PU5JKC2W-Dw8ClWch.js"},{"revision":null,"url":"assets/chunk-PQ6SQG4A-D6BTbCQw.js"},{"revision":null,"url":"assets/chunk-OZEHJAEY-BXhYx3nO.js"},{"revision":null,"url":"assets/chunk-O4XLMI2P-JC6EGoUz.js"},{"revision":null,"url":"assets/chunk-NQ4KR5QH-wMgTlP7f.js"},{"revision":null,"url":"assets/chunk-MX3YWQON-BpS_PtKp.js"},{"revision":null,"url":"assets/chunk-L3YUKLVL-C7qGJrfV.js"},{"revision":null,"url":"assets/chunk-KYZI473N-BcUZNnwd.js"},{"revision":null,"url":"assets/chunk-KX2RTZJC-sQ0o-39C.js"},{"revision":null,"url":"assets/chunk-JSJVCQXG-23tyvw8k.js"},{"revision":null,"url":"assets/chunk-HHEYEP7N-HRhYy3kG.js"},{"revision":null,"url":"assets/chunk-GLR3WWYH-CzYx4w-r.js"},{"revision":null,"url":"assets/chunk-GEFDOKGD-BbQkJu8C.js"},{"revision":null,"url":"assets/chunk-FMBD7UC4-DXncblvW.js"},{"revision":null,"url":"assets/chunk-EGIJ26TM-DzqmU2Z7.js"},{"revision":null,"url":"assets/chunk-CFjPhJqf.js"},{"revision":null,"url":"assets/chunk-C72U2L5F-D21mS_6G.js"},{"revision":null,"url":"assets/chunk-7R4GIKGN-BbIFzsIv.js"},{"revision":null,"url":"assets/chunk-7E7YKBS2-CiyUJxNI.js"},{"revision":null,"url":"assets/chunk-55IACEB6-DJ6BynZ4.js"},{"revision":null,"url":"assets/chunk-4BX2VUAB-D4tOov49.js"},{"revision":null,"url":"assets/chevron-right-5HgK6l7K.js"},{"revision":null,"url":"assets/chat-tab-CFyDR47n.js"},{"revision":null,"url":"assets/channel-wrd-NHWf.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-dV22iAsY.js"},{"revision":null,"url":"assets/browser-tab-zJXwFb1y.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-TEF8Ally.js"},{"revision":null,"url":"assets/arrow-up-BYhx9ckd.js"},{"revision":null,"url":"assets/array-B9UHiPd-.js"},{"revision":null,"url":"assets/architectureDiagram-2XIMDMQ5-DWBCPMLF.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-DEO2f3VD.js"},{"revision":null,"url":"assets/arc-BAOivWpI.js"},{"revision":null,"url":"assets/api-settings-BUvk6Saw.js"},{"revision":null,"url":"assets/api-client-BfBM3I7n.js"},{"revision":null,"url":"assets/_baseUniq-BT4Ow4Kk.js"},{"revision":null,"url":"assets/_basePickBy-5PGDJbfF.js"},{"revision":"79c8870653c8f419f2e3323085e1f4be","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.png`,badge:`/icon-192.png`,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||`/`)}))});
@@ -2,7 +2,37 @@
2
2
 
3
3
  All notable changes to PPM are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/).
4
4
 
5
- **Current Version:** v0.9.0
5
+ **Current Version:** v0.9.2
6
+
7
+ ---
8
+
9
+ ## [0.9.2] — 2026-04-04
10
+
11
+ ### Added
12
+ - **File Download Feature** — Single-file and folder-as-zip downloads with short-lived tokens
13
+ - Download tokens: one-time, 30s TTL, non-reusable
14
+ - Backend: POST `/files/download/token` for token generation, GET `/files/raw?download=true&dl_token=X` for file downloads, GET `/files/download/zip?path=X` for folder zips
15
+ - Frontend: Download context menu in file tree, download button in editor toolbar
16
+ - Security: Tokens scoped to download paths only, path traversal protection maintained
17
+ - Performance: Streaming via Bun.file() and archiver, no RAM buffering for large files
18
+ - Testing: 30 integration tests covering auth, streaming, path traversal, zip integrity
19
+
20
+ ### Technical Details
21
+ - **Files Created:**
22
+ - `src/services/download-token.service.ts` — In-memory token store with TTL cleanup
23
+ - `src/server/routes/file-download.ts` — Download endpoints (token + zip)
24
+ - `src/web/lib/file-download.ts` — Download utilities (single file + folder)
25
+ - `tests/integration/file-download.test.ts` — Integration tests
26
+ - **Files Modified:**
27
+ - `src/server/middleware/auth.ts` — Added dl_token fallback for downloads
28
+ - `src/server/routes/files.ts` — Added ?download=true mode
29
+ - `src/server/routes/project-scoped.ts` — Registered download routes
30
+ - `src/web/components/explorer/file-tree.tsx` — Added download context menu item
31
+ - `src/web/components/editor/editor-toolbar.tsx` — Added download button
32
+ - `src/web/components/editor/code-editor.tsx` — Passed filePath/projectName to toolbar
33
+ - `src/server/helpers/error-status.ts` — Extracted shared error helper
34
+ - **Dependencies:**
35
+ - `archiver` — Streaming zip library (well-maintained, ~500KB)
6
36
 
7
37
  ---
8
38
 
@@ -58,7 +58,7 @@ PPM is the **lightest path from phone to code** — a self-hosted, BYOK, multi-d
58
58
 
59
59
  **Theme:** Multi-provider AI (Claude + Cursor) + extension system. Ship a focused release, expand providers later.
60
60
 
61
- **Overall progress: 100%** (All 3 features complete)
61
+ **Overall progress: 100%** (All 3 core features complete)
62
62
 
63
63
  | Feature | Priority | Status | Description |
64
64
  |---------|----------|--------|-------------|
@@ -66,6 +66,9 @@ PPM is the **lightest path from phone to code** — a self-hosted, BYOK, multi-d
66
66
  | **MCP Management** | Medium | ✅ Done | REST API (CRUD + import), SQLite storage, Settings UI, auto-import from `~/.claude.json`, validation, SDK integration. |
67
67
  | **Extension architecture (Phase 1-6)** | High | ✅ Done | VSCode-compatible npm extensions, Bun Worker isolation, RPC protocol, state persistence, contribution registry, CLI support, dev mode. @ppm/vscode-compat API shim (commands, window, workspace). UI components (StatusBar, TreeView, WebviewPanel, QuickPick, InputBox). WS bridge for real-time ext↔browser communication. First extension: ext-database with tree view + SQL query panel. Unit tests + extension dev guide. |
68
68
 
69
+ **v0.9.x polish (post-release):**
70
+ - File download feature (v0.9.2) — Single-file + folder-as-zip downloads with short-lived tokens, context menu + toolbar UI
71
+
69
72
  **Multi-provider — v0.9 scope (reduced):**
70
73
  - Tier 1 (full agentic): Claude Agent SDK — file edit, terminal, git, full autonomy
71
74
  - Tier 2 (agentic CLI): Cursor — agentic via its own tool system
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.9.6",
3
+ "version": "0.9.8",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
@@ -22,6 +22,7 @@
22
22
  },
23
23
  "devDependencies": {
24
24
  "@tailwindcss/vite": "^4.2.1",
25
+ "@types/archiver": "^7.0.0",
25
26
  "@types/bun": "latest",
26
27
  "@types/js-yaml": "^4.0.9",
27
28
  "@types/node": "^25.5.0",
@@ -52,6 +53,7 @@
52
53
  "@xterm/addon-fit": "^0.11.0",
53
54
  "@xterm/addon-web-links": "^0.12.0",
54
55
  "@xterm/xterm": "^6.0.0",
56
+ "archiver": "^7.0.1",
55
57
  "class-variance-authority": "^0.7.1",
56
58
  "clsx": "^2.1.1",
57
59
  "commander": "^14.0.3",
@@ -0,0 +1,10 @@
1
+ import type { ContentfulStatusCode } from "hono/utils/http-status";
2
+ import { SecurityError, NotFoundError, ValidationError } from "../../services/file.service.ts";
3
+
4
+ /** Map domain error types to HTTP status codes */
5
+ export function errorStatus(e: unknown): ContentfulStatusCode {
6
+ if (e instanceof SecurityError) return 403;
7
+ if (e instanceof NotFoundError) return 404;
8
+ if (e instanceof ValidationError) return 400;
9
+ return 500;
10
+ }
@@ -1,5 +1,6 @@
1
1
  import type { Context, Next } from "hono";
2
2
  import { configService } from "../../services/config.service.ts";
3
+ import { consumeDownloadToken } from "../../services/download-token.service.ts";
3
4
  import { err } from "../../types/api.ts";
4
5
 
5
6
  /** Auth middleware — checks Bearer token against config */
@@ -17,14 +18,24 @@ export async function authMiddleware(c: Context, next: Next) {
17
18
  }
18
19
 
19
20
  const header = c.req.header("Authorization");
20
- if (!header || !header.startsWith("Bearer ")) {
21
- return c.json(err("Unauthorized"), 401);
21
+ if (header?.startsWith("Bearer ")) {
22
+ const token = header.slice(7);
23
+ if (token === authConfig.token) {
24
+ return next();
25
+ }
22
26
  }
23
27
 
24
- const token = header.slice(7);
25
- if (token !== authConfig.token) {
26
- return c.json(err("Unauthorized"), 401);
28
+ // Fallback: short-lived download token for browser-initiated downloads only
29
+ if (c.req.method === "GET") {
30
+ const path = c.req.path;
31
+ const isDownloadPath = path.endsWith("/files/raw") || path.endsWith("/files/download/zip");
32
+ if (isDownloadPath) {
33
+ const dlToken = c.req.query("dl_token");
34
+ if (dlToken && consumeDownloadToken(dlToken)) {
35
+ return next();
36
+ }
37
+ }
27
38
  }
28
39
 
29
- return next();
40
+ return c.json(err("Unauthorized"), 401);
30
41
  }
@@ -0,0 +1,63 @@
1
+ import { Hono } from "hono";
2
+ import { resolve, basename } from "node:path";
3
+ import { existsSync, statSync } from "node:fs";
4
+ import archiver from "archiver";
5
+ import { createDownloadToken } from "../../services/download-token.service.ts";
6
+ import { ok, err } from "../../types/api.ts";
7
+ import { errorStatus } from "../helpers/error-status.ts";
8
+
9
+ type Env = { Variables: { projectPath: string; projectName: string } };
10
+
11
+ export const downloadRoutes = new Hono<Env>();
12
+
13
+ /** POST /token — generate a short-lived download token */
14
+ downloadRoutes.post("/token", (c) => {
15
+ const token = createDownloadToken();
16
+ return c.json(ok({ token }));
17
+ });
18
+
19
+ /** GET /zip?path=... — stream folder as zip */
20
+ downloadRoutes.get("/zip", async (c) => {
21
+ try {
22
+ const projectPath = c.get("projectPath");
23
+ const dirPath = c.req.query("path");
24
+ if (!dirPath) return c.json(err("Missing query parameter: path"), 400);
25
+
26
+ const absPath = resolve(projectPath, dirPath);
27
+ if (!absPath.startsWith(projectPath + "/") && absPath !== projectPath) {
28
+ return c.json(err("Access denied"), 403);
29
+ }
30
+ if (!existsSync(absPath)) return c.json(err("Directory not found"), 404);
31
+
32
+ const stat = statSync(absPath);
33
+ if (!stat.isDirectory()) return c.json(err("Path is not a directory"), 400);
34
+
35
+ const folderName = basename(absPath);
36
+ const archive = archiver("zip", { zlib: { level: 5 } });
37
+
38
+ archive.glob("**/*", {
39
+ cwd: absPath,
40
+ ignore: [".git/**", "node_modules/**"],
41
+ dot: true,
42
+ });
43
+ archive.finalize();
44
+
45
+ // Convert Node stream to web ReadableStream
46
+ const webStream = new ReadableStream({
47
+ start(controller) {
48
+ archive.on("data", (chunk: Buffer) => controller.enqueue(chunk));
49
+ archive.on("end", () => controller.close());
50
+ archive.on("error", (e: Error) => controller.error(e));
51
+ },
52
+ });
53
+
54
+ return new Response(webStream, {
55
+ headers: {
56
+ "Content-Type": "application/zip",
57
+ "Content-Disposition": `attachment; filename="${folderName}.zip"`,
58
+ },
59
+ });
60
+ } catch (e) {
61
+ return c.json(err((e as Error).message), errorStatus(e));
62
+ }
63
+ });
@@ -1,26 +1,14 @@
1
1
  import { Hono } from "hono";
2
2
  import { resolve } from "node:path";
3
3
  import { existsSync } from "node:fs";
4
- import type { ContentfulStatusCode } from "hono/utils/http-status";
5
- import {
6
- fileService,
7
- SecurityError,
8
- NotFoundError,
9
- ValidationError,
10
- } from "../../services/file.service.ts";
4
+ import { fileService } from "../../services/file.service.ts";
11
5
  import { ok, err } from "../../types/api.ts";
6
+ import { errorStatus } from "../helpers/error-status.ts";
12
7
 
13
8
  type Env = { Variables: { projectPath: string; projectName: string } };
14
9
 
15
10
  export const fileRoutes = new Hono<Env>();
16
11
 
17
- /** Map error type to HTTP status code */
18
- function errorStatus(e: unknown): ContentfulStatusCode {
19
- if (e instanceof SecurityError) return 403;
20
- if (e instanceof NotFoundError) return 404;
21
- if (e instanceof ValidationError) return 400;
22
- return 500;
23
- }
24
12
 
25
13
  /** GET /files/tree?depth=3 */
26
14
  fileRoutes.get("/tree", (c) => {
@@ -34,7 +22,7 @@ fileRoutes.get("/tree", (c) => {
34
22
  }
35
23
  });
36
24
 
37
- /** GET /files/raw?path=... — serve file directly as binary (for PDF viewer, images, etc.) */
25
+ /** GET /files/raw?path=...&download=true — serve file directly as binary (for PDF viewer, images, downloads) */
38
26
  fileRoutes.get("/raw", (c) => {
39
27
  try {
40
28
  const projectPath = c.get("projectPath");
@@ -49,10 +37,13 @@ fileRoutes.get("/raw", (c) => {
49
37
  if (!existsSync(absPath)) return c.json(err("File not found"), 404);
50
38
 
51
39
  const file = Bun.file(absPath);
40
+ const download = c.req.query("download") === "true";
41
+ const filename = filePath.split("/").pop() ?? "download";
42
+
52
43
  return new Response(file.stream(), {
53
44
  headers: {
54
- "Content-Type": file.type || "application/octet-stream",
55
- "Content-Disposition": "inline",
45
+ "Content-Type": download ? "application/octet-stream" : (file.type || "application/octet-stream"),
46
+ "Content-Disposition": download ? `attachment; filename="${filename}"` : "inline",
56
47
  },
57
48
  });
58
49
  } catch (e) {
@@ -5,6 +5,7 @@ import { gitRoutes } from "./git.ts";
5
5
  import { fileRoutes } from "./files.ts";
6
6
  import { sqliteRoutes } from "./sqlite.ts";
7
7
  import { workspaceRoutes } from "./workspace.ts";
8
+ import { downloadRoutes } from "./file-download.ts";
8
9
 
9
10
  type Env = { Variables: { projectPath: string; projectName: string } };
10
11
 
@@ -29,3 +30,4 @@ projectScopedRouter.route("/git", gitRoutes);
29
30
  projectScopedRouter.route("/files", fileRoutes);
30
31
  projectScopedRouter.route("/sqlite", sqliteRoutes);
31
32
  projectScopedRouter.route("/workspace", workspaceRoutes);
33
+ projectScopedRouter.route("/files/download", downloadRoutes);
@@ -0,0 +1,37 @@
1
+ import { randomUUIDv7 } from "bun";
2
+
3
+ interface DownloadToken {
4
+ token: string;
5
+ createdAt: number;
6
+ }
7
+
8
+ const TTL_MS = 30_000;
9
+ const tokens = new Map<string, DownloadToken>();
10
+
11
+ /** Generate a one-time download token (30s TTL) */
12
+ export function createDownloadToken(): string {
13
+ const token = randomUUIDv7();
14
+ tokens.set(token, { token, createdAt: Date.now() });
15
+ cleanup();
16
+ return token;
17
+ }
18
+
19
+ /** Validate and consume a download token (one-time use) */
20
+ export function consumeDownloadToken(token: string): boolean {
21
+ const entry = tokens.get(token);
22
+ if (!entry) return false;
23
+ if (Date.now() - entry.createdAt > TTL_MS) {
24
+ tokens.delete(token);
25
+ return false;
26
+ }
27
+ tokens.delete(token);
28
+ return true;
29
+ }
30
+
31
+ /** Remove expired tokens */
32
+ function cleanup(): void {
33
+ const now = Date.now();
34
+ for (const [key, entry] of tokens) {
35
+ if (now - entry.createdAt > TTL_MS) tokens.delete(key);
36
+ }
37
+ }
@@ -15,7 +15,6 @@ type PanelType = "history" | "config" | "usage" | null;
15
15
  interface ChatHistoryBarProps {
16
16
  projectName: string;
17
17
  usageInfo: UsageInfo;
18
- contextWindowPct?: number | null;
19
18
  compactStatus?: "compacting" | null;
20
19
  usageLoading?: boolean;
21
20
  refreshUsage?: () => void;
@@ -80,7 +79,7 @@ function DebugCopyButton({ sessionId, projectName }: { sessionId: string; projec
80
79
  }
81
80
 
82
81
  export function ChatHistoryBar({
83
- projectName, usageInfo, contextWindowPct, compactStatus, usageLoading, refreshUsage, lastFetchedAt,
82
+ projectName, usageInfo, compactStatus, usageLoading, refreshUsage, lastFetchedAt,
84
83
  sessionId, providerId, onSelectSession, onBugReport, isConnected, onReconnect,
85
84
  }: ChatHistoryBarProps) {
86
85
  const [activePanel, setActivePanel] = useState<PanelType>(null);
@@ -210,25 +209,30 @@ export function ChatHistoryBar({
210
209
  <span>History</span>
211
210
  </button>
212
211
 
213
- {/* Active provider indicator */}
214
- {sessionId && providerId && providerId !== "mock" && (
215
- <span className="flex items-center gap-1 px-1.5 py-0.5 text-[11px] text-text-secondary">
212
+ {/* Active provider + AI Settings (combined) */}
213
+ {sessionId && providerId && providerId !== "mock" ? (
214
+ <button
215
+ onClick={() => togglePanel("config")}
216
+ className={`flex items-center gap-1 px-1.5 py-0.5 rounded text-[11px] transition-colors ${
217
+ activePanel === "config" ? "text-primary bg-primary/10" : "text-text-secondary hover:text-foreground hover:bg-surface-elevated"
218
+ }`}
219
+ title="AI Settings"
220
+ >
216
221
  <ProviderBadge providerId={providerId} />
217
222
  <span className="capitalize">{providerId}</span>
218
- </span>
223
+ </button>
224
+ ) : (
225
+ <button
226
+ onClick={() => togglePanel("config")}
227
+ className={`p-1 rounded transition-colors ${
228
+ activePanel === "config" ? "text-primary bg-primary/10" : "text-text-subtle hover:text-text-secondary hover:bg-surface-elevated"
229
+ }`}
230
+ title="AI Settings"
231
+ >
232
+ <Settings2 className="size-3" />
233
+ </button>
219
234
  )}
220
235
 
221
- {/* Config */}
222
- <button
223
- onClick={() => togglePanel("config")}
224
- className={`p-1 rounded transition-colors ${
225
- activePanel === "config" ? "text-primary bg-primary/10" : "text-text-subtle hover:text-text-secondary hover:bg-surface-elevated"
226
- }`}
227
- title="AI Settings"
228
- >
229
- <Settings2 className="size-3" />
230
- </button>
231
-
232
236
  {/* Usage & Accounts — full display for Claude, minimal for other providers */}
233
237
  {isClaudeProvider ? (
234
238
  <button
@@ -245,12 +249,6 @@ export function ChatHistoryBar({
245
249
  <span>5h:{fiveHourPct != null ? `${fiveHourPct}%` : "--%"}</span>
246
250
  <span className="text-text-subtle">·</span>
247
251
  <span>Wk:{sevenDayPct != null ? `${sevenDayPct}%` : "--%"}</span>
248
- {contextWindowPct != null && (
249
- <>
250
- <span className="text-text-subtle">·</span>
251
- <span className={pctColor(contextWindowPct)}>Ctx:{contextWindowPct}%</span>
252
- </>
253
- )}
254
252
  {compactStatus === "compacting" && (
255
253
  <>
256
254
  <span className="text-text-subtle">·</span>
@@ -259,19 +257,11 @@ export function ChatHistoryBar({
259
257
  )}
260
258
  </button>
261
259
  ) : (
262
- <>
263
- {contextWindowPct != null && (
264
- <span className={`flex items-center gap-1 px-1.5 py-0.5 text-[11px] font-medium tabular-nums ${pctColor(contextWindowPct)}`}>
265
- <Activity className="size-3" />
266
- <span>Ctx:{contextWindowPct}%</span>
267
- </span>
268
- )}
269
- {compactStatus === "compacting" && (
270
- <span className="text-[11px] px-1.5 py-0.5 text-blue-400 animate-pulse">
271
- compacting...
272
- </span>
273
- )}
274
- </>
260
+ compactStatus === "compacting" ? (
261
+ <span className="text-[11px] px-1.5 py-0.5 text-blue-400 animate-pulse">
262
+ compacting...
263
+ </span>
264
+ ) : null
275
265
  )}
276
266
 
277
267
  {/* Spacer */}
@@ -350,7 +350,6 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
350
350
  <ChatHistoryBar
351
351
  projectName={projectName}
352
352
  usageInfo={usageInfo}
353
- contextWindowPct={contextWindowPct}
354
353
  compactStatus={compactStatus}
355
354
  usageLoading={usageLoading}
356
355
  refreshUsage={refreshUsage}