@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.
- package/.claude.bak/agent-memory/tester/MEMORY.md +3 -0
- package/.claude.bak/agent-memory/tester/project-ppm-test-conventions.md +32 -0
- package/CHANGELOG.md +21 -0
- package/bun.lock +129 -7
- package/dist/web/assets/{architectureDiagram-2XIMDMQ5-Z-4eN4za.js → architectureDiagram-2XIMDMQ5-DWBCPMLF.js} +1 -1
- package/dist/web/assets/{blockDiagram-WCTKOSBZ-BCLqzhuZ.js → blockDiagram-WCTKOSBZ-TEF8Ally.js} +1 -1
- package/dist/web/assets/browser-tab-zJXwFb1y.js +1 -0
- package/dist/web/assets/{c4Diagram-IC4MRINW-0Vp0Jeas.js → c4Diagram-IC4MRINW-dV22iAsY.js} +1 -1
- package/dist/web/assets/channel-wrd-NHWf.js +1 -0
- package/dist/web/assets/chat-tab-CFyDR47n.js +8 -0
- package/dist/web/assets/{chunk-7R4GIKGN-Dv-4cAYn.js → chunk-7R4GIKGN-BbIFzsIv.js} +1 -1
- package/dist/web/assets/{chunk-GEFDOKGD-D-pKjlVd.js → chunk-GEFDOKGD-BbQkJu8C.js} +1 -1
- package/dist/web/assets/{chunk-GLR3WWYH-DKikpoJM.js → chunk-GLR3WWYH-CzYx4w-r.js} +2 -2
- package/dist/web/assets/{chunk-HHEYEP7N-C7vxA5i9.js → chunk-HHEYEP7N-HRhYy3kG.js} +1 -1
- package/dist/web/assets/{chunk-JSJVCQXG-99JzIdPr.js → chunk-JSJVCQXG-23tyvw8k.js} +1 -1
- package/dist/web/assets/{chunk-KX2RTZJC-CRq1OBZv.js → chunk-KX2RTZJC-sQ0o-39C.js} +1 -1
- package/dist/web/assets/{chunk-KYZI473N-Bb0MCaIO.js → chunk-KYZI473N-BcUZNnwd.js} +1 -1
- package/dist/web/assets/{chunk-NQ4KR5QH-z_blpjxi.js → chunk-NQ4KR5QH-wMgTlP7f.js} +1 -1
- package/dist/web/assets/{chunk-O4XLMI2P-nDhi_cVu.js → chunk-O4XLMI2P-JC6EGoUz.js} +1 -1
- package/dist/web/assets/{chunk-PQ6SQG4A-TF58UVMU.js → chunk-PQ6SQG4A-D6BTbCQw.js} +1 -1
- package/dist/web/assets/{chunk-PU5JKC2W-ek7k4QVB.js → chunk-PU5JKC2W-Dw8ClWch.js} +1 -1
- package/dist/web/assets/{chunk-WL4C6EOR-ByUrSRin.js → chunk-WL4C6EOR-DfofndiH.js} +1 -1
- package/dist/web/assets/{chunk-YBOYWFTD-rQG3QH5s.js → chunk-YBOYWFTD-CeU4Q-xC.js} +1 -1
- package/dist/web/assets/classDiagram-VBA2DB6C-lse8oZoJ.js +1 -0
- package/dist/web/assets/classDiagram-v2-RAHNMMFH-CxkwuInd.js +1 -0
- package/dist/web/assets/code-editor-LX1U5zLR.js +2 -0
- package/dist/web/assets/{csv-preview-ncSOnJSC.js → csv-preview-Doo6XsK0.js} +1 -1
- package/dist/web/assets/{dagre-DHq9bhnd.js → dagre-Dbb5k38K.js} +1 -1
- package/dist/web/assets/{dagre-KLK3FWXG-BdJr7Byp.js → dagre-KLK3FWXG-BH7aWGRP.js} +1 -1
- package/dist/web/assets/database-viewer-DeQyA5LK.js +1 -0
- package/dist/web/assets/{diagram-E7M64L7V-_db4pBVA.js → diagram-E7M64L7V-B1Qz70Do.js} +1 -1
- package/dist/web/assets/{diagram-IFDJBPK2-xKoeuiJx.js → diagram-IFDJBPK2-k55eVqVU.js} +1 -1
- package/dist/web/assets/{diagram-P4PSJMXO-C8tjJsev.js → diagram-P4PSJMXO-BkfNRc9U.js} +1 -1
- package/dist/web/assets/{diff-viewer-BdeL1mp2.js → diff-viewer-BiXgYdZ8.js} +1 -1
- package/dist/web/assets/dist-C4urk5JP.js +41 -0
- package/dist/web/assets/{dist-ovWkrgO-.js → dist-wVfsYfHS.js} +1 -1
- package/dist/web/assets/{erDiagram-INFDFZHY-BSh2z9Df.js → erDiagram-INFDFZHY-CKzVujYI.js} +1 -1
- package/dist/web/assets/{extension-webview-BAClIyub.js → extension-webview-DLlIuZOQ.js} +1 -1
- package/dist/web/assets/{flowDiagram-PKNHOUZH-oYaovqyp.js → flowDiagram-PKNHOUZH-DIqcTrDV.js} +1 -1
- package/dist/web/assets/{ganttDiagram-A5KZAMGK-DmL26q2P.js → ganttDiagram-A5KZAMGK-D4v7ZbVE.js} +1 -1
- package/dist/web/assets/git-graph-BpchaeYc.js +1 -0
- package/dist/web/assets/{gitGraphDiagram-K3NZZRJ6-CMoukSrY.js → gitGraphDiagram-K3NZZRJ6-BTXo57mF.js} +1 -1
- package/dist/web/assets/index-D-Vtz6Oy.js +37 -0
- package/dist/web/assets/index-D3XyoeN3.css +2 -0
- package/dist/web/assets/{infoDiagram-LFFYTUFH-DWwumDkq.js → infoDiagram-LFFYTUFH-B1CX0pbC.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-PHBUUO56-D05_LyL7.js → ishikawaDiagram-PHBUUO56-BOyvKMmB.js} +1 -1
- package/dist/web/assets/{journeyDiagram-4ABVD52K-B_L20qMe.js → journeyDiagram-4ABVD52K-ufoasAy6.js} +1 -1
- package/dist/web/assets/{kanban-definition-K7BYSVSG-CZ535BbZ.js → kanban-definition-K7BYSVSG-Bi0UTUeN.js} +1 -1
- package/dist/web/assets/keybindings-store-DMXYSZfe.js +1 -0
- package/dist/web/assets/{line-CVvo3dRu.js → line-B78g-52T.js} +1 -1
- package/dist/web/assets/{markdown-renderer-COndDkRD.js → markdown-renderer-_FS3Bpm9.js} +5 -5
- package/dist/web/assets/{mermaid-parser.core-C7UwoIh6.js → mermaid-parser.core-DMIWdgEW.js} +1 -1
- package/dist/web/assets/{mindmap-definition-YRQLILUH-x0MTutJp.js → mindmap-definition-YRQLILUH-BsfWvIoO.js} +1 -1
- package/dist/web/assets/{pieDiagram-SKSYHLDU-C1Gjrtzy.js → pieDiagram-SKSYHLDU-WP0XXw51.js} +1 -1
- package/dist/web/assets/postgres-viewer-BdFwZzy1.js +1 -0
- package/dist/web/assets/{quadrantDiagram-337W2JSQ-C8bzJCjQ.js → quadrantDiagram-337W2JSQ-FHMogtsh.js} +1 -1
- package/dist/web/assets/{requirementDiagram-Z7DCOOCP-pQyah6WB.js → requirementDiagram-Z7DCOOCP-BatTxyWb.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-WA2Y5GQK-T6RgG-N8.js → sankeyDiagram-WA2Y5GQK-ClJuW3Hv.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-2WXFIKYE-BQDJ4CVs.js → sequenceDiagram-2WXFIKYE-ByxQqGgs.js} +1 -1
- package/dist/web/assets/{settings-tab-CiDK6Jf2.js → settings-tab-DyqD7Rr6.js} +1 -1
- package/dist/web/assets/sqlite-viewer-BlT-kB8c.js +1 -0
- package/dist/web/assets/{stateDiagram-RAJIS63D-66vhiIuk.js → stateDiagram-RAJIS63D-f8opcZNY.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-FVOUBMTO-DrxVDY9q.js +1 -0
- package/dist/web/assets/{tab-store-BOgTrqRr.js → tab-store-CeOacjuH.js} +1 -1
- package/dist/web/assets/{terminal-tab-BvExlsRm.js → terminal-tab-DfplMwBA.js} +1 -1
- package/dist/web/assets/{timeline-definition-YZTLITO2-DwZqB3nn.js → timeline-definition-YZTLITO2-58BlOSf9.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-BsMRP0ci.js → use-monaco-theme-DjfHhwSf.js} +1 -1
- package/dist/web/assets/{vennDiagram-LZ73GAT5-s9Z71fz-.js → vennDiagram-LZ73GAT5-BOSy9ma9.js} +1 -1
- package/dist/web/assets/{xychartDiagram-JWTSCODW-DRa_TH4B.js → xychartDiagram-JWTSCODW-z5MVJauZ.js} +1 -1
- package/dist/web/index.html +8 -8
- package/dist/web/sw.js +1 -1
- package/docs/project-changelog.md +31 -1
- package/docs/project-roadmap.md +4 -1
- package/package.json +3 -1
- package/src/server/helpers/error-status.ts +10 -0
- package/src/server/middleware/auth.ts +17 -6
- package/src/server/routes/file-download.ts +63 -0
- package/src/server/routes/files.ts +8 -17
- package/src/server/routes/project-scoped.ts +2 -0
- package/src/services/download-token.service.ts +37 -0
- package/src/web/components/chat/chat-history-bar.tsx +26 -36
- package/src/web/components/chat/chat-tab.tsx +0 -1
- package/src/web/components/chat/usage-badge.tsx +23 -10
- package/src/web/components/editor/code-editor.tsx +2 -0
- package/src/web/components/editor/editor-toolbar.tsx +14 -1
- package/src/web/components/explorer/file-tree.tsx +15 -0
- package/src/web/lib/file-download.ts +27 -0
- package/dist/web/assets/browser-tab-DOcEOjEa.js +0 -1
- package/dist/web/assets/channel-By7bn0Yq.js +0 -1
- package/dist/web/assets/chat-tab-Ck-DKBcT.js +0 -8
- package/dist/web/assets/classDiagram-VBA2DB6C-BA8Nj-_C.js +0 -1
- package/dist/web/assets/classDiagram-v2-RAHNMMFH-DjYu-6mn.js +0 -1
- package/dist/web/assets/code-editor-pu7p8kxA.js +0 -2
- package/dist/web/assets/database-viewer-Byj9izvr.js +0 -1
- package/dist/web/assets/dist-DIV6WgAG.js +0 -41
- package/dist/web/assets/git-graph-DnXGjims.js +0 -1
- package/dist/web/assets/index-C6uPEeqG.js +0 -37
- package/dist/web/assets/index-CjwJM7yL.css +0 -2
- package/dist/web/assets/keybindings-store-DclBEjd4.js +0 -1
- package/dist/web/assets/postgres-viewer-CQODrSyu.js +0 -1
- package/dist/web/assets/sqlite-viewer-kMmzSn7j.js +0 -1
- package/dist/web/assets/stateDiagram-v2-FVOUBMTO-BGVqj_g9.js +0 -1
- package/docs/streaming-input-guide.md +0 -267
- package/snapshot-state.md +0 -1526
- package/test-session-ops.mjs +0 -444
- package/test-tokens.mjs +0 -212
- /package/dist/web/assets/{jsx-runtime-kMwlnEGE.js → jsx-runtime-O3jQaKZd.js} +0 -0
- /package/dist/web/assets/{preload-helper-Bf_JiD2A.js → preload-helper-uTix4PVD.js} +0 -0
- /package/dist/web/assets/{react-SKk5z-bm.js → react-ER-4DN55.js} +0 -0
- /package/dist/web/assets/{table-DFevCOMd.js → table-CWv1Oy39.js} +0 -0
- /package/dist/web/assets/{tag-CXMT0QB6.js → tag-CFrhsWuM.js} +0 -0
package/dist/web/index.html
CHANGED
|
@@ -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-
|
|
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-
|
|
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-
|
|
48
|
-
<link rel="modulepreload" crossorigin href="/assets/dist-
|
|
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-
|
|
53
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-store-
|
|
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-
|
|
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.
|
|
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
|
|
package/docs/project-roadmap.md
CHANGED
|
@@ -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.
|
|
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 (
|
|
21
|
-
|
|
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
|
-
|
|
25
|
-
if (
|
|
26
|
-
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
214
|
-
{sessionId && providerId && providerId !== "mock"
|
|
215
|
-
<
|
|
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
|
-
</
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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}
|