@hienlh/ppm 0.8.68 → 0.8.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/web/assets/{browser-tab-CtCbYDuw.js → browser-tab-sn8vZniz.js} +1 -1
- package/dist/web/assets/chat-tab-CVN2falD.js +8 -0
- package/dist/web/assets/{code-editor-B1u2B_S9.js → code-editor-BNAZzdyF.js} +1 -1
- package/dist/web/assets/{database-viewer-D9fH7muY.js → database-viewer-BOnawWoi.js} +1 -1
- package/dist/web/assets/{diff-viewer-CdAqWeV-.js → diff-viewer-CYSw0YBG.js} +1 -1
- package/dist/web/assets/{git-graph-BDUvkX0f.js → git-graph-BNTU6kmo.js} +1 -1
- package/dist/web/assets/{index-DtlqB_mF.js → index-ButO-DnP.js} +8 -8
- package/dist/web/assets/index-DJ1Bqwo4.css +2 -0
- package/dist/web/assets/keybindings-store-BxDBTcFM.js +1 -0
- package/dist/web/assets/{markdown-renderer-Bwac0-W_.js → markdown-renderer-CW2c3h_9.js} +1 -1
- package/dist/web/assets/{postgres-viewer-CqT43D2z.js → postgres-viewer-D95__akI.js} +1 -1
- package/dist/web/assets/{settings-tab-G59ZwloQ.js → settings-tab-CwLkeZaa.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-D6sxS0bk.js → sqlite-viewer-J18kIhk2.js} +1 -1
- package/dist/web/assets/{terminal-tab-IkfhM5s1.js → terminal-tab-BKETi9uD.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-gi_EBBX3.js → use-monaco-theme-Dsn8sLad.js} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/providers/claude-agent-sdk.ts +51 -8
- package/src/server/routes/chat.ts +17 -0
- package/src/server/ws/chat.ts +2 -2
- package/src/types/chat.ts +2 -1
- package/src/web/components/chat/chat-history-bar.tsx +34 -1
- package/src/web/components/chat/message-list.tsx +7 -0
- package/src/web/components/layout/editor-panel.tsx +96 -17
- package/src/web/hooks/use-chat.ts +11 -0
- package/dist/web/assets/chat-tab-Bx_6S_UY.js +0 -7
- package/dist/web/assets/index-DPI-YVJI.css +0 -2
- package/dist/web/assets/keybindings-store-DiM6OAOI.js +0 -1
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":"2055d75c29ab6cf30157b7d8b1539854","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"eb9818b9094675c0c5d303168f273345","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"9af0be92dcefdc1f1290441cb5ff5d9b","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"a261b429c39dbb75ae97972d7d005e6d","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"79953d804e1bbacecfd79b85fd679016","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"fdcba0d09aac31df7a0bc652f6e739bd","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-gi_EBBX3.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-IkfhM5s1.js"},{"revision":null,"url":"assets/terminal-tab-BrP-ENHg.css"},{"revision":null,"url":"assets/tag-CCtdV063.js"},{"revision":null,"url":"assets/table-C7X5UAEI.js"},{"revision":null,"url":"assets/tab-store-BCfMgMKM.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-D6sxS0bk.js"},{"revision":null,"url":"assets/settings-tab-G59ZwloQ.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-CqT43D2z.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-Bwac0-W_.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-DiM6OAOI.js"},{"revision":null,"url":"assets/katex-Bqvo_ZG0.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-Bi0UTUeN.js"},{"revision":null,"url":"assets/jsx-runtime-BRW_vwa9.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/input-BglMT33g.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-DtlqB_mF.js"},{"revision":null,"url":"assets/index-DPI-YVJI.css"},{"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-BDUvkX0f.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-D4v7ZbVE.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-DIqcTrDV.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-CKzVujYI.js"},{"revision":null,"url":"assets/dist-lF8CoYII.js"},{"revision":null,"url":"assets/dist-DylI9XxN.js"},{"revision":null,"url":"assets/dist-CSJdAyA9.js"},{"revision":null,"url":"assets/diff-viewer-CdAqWeV-.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-D9fH7muY.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-DLqYtXxt.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-B_AWZsOP.js"},{"revision":null,"url":"assets/columns-2-DpsNbZOc.js"},{"revision":null,"url":"assets/code-editor-B1u2B_S9.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-DeV0ehiG.js"},{"revision":null,"url":"assets/chat-tab-Bx_6S_UY.js"},{"revision":null,"url":"assets/channel-wrd-NHWf.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-dV22iAsY.js"},{"revision":null,"url":"assets/browser-tab-CtCbYDuw.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-TEF8Ally.js"},{"revision":null,"url":"assets/arrow-up--LjUXLEt.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-D21InCnR.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":"701ee8c3d0a9e1223807ecb6c8c1e7e4","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"eb9818b9094675c0c5d303168f273345","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"9af0be92dcefdc1f1290441cb5ff5d9b","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"a261b429c39dbb75ae97972d7d005e6d","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"79953d804e1bbacecfd79b85fd679016","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"fdcba0d09aac31df7a0bc652f6e739bd","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-Dsn8sLad.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-BrP-ENHg.css"},{"revision":null,"url":"assets/terminal-tab-BKETi9uD.js"},{"revision":null,"url":"assets/tag-CCtdV063.js"},{"revision":null,"url":"assets/table-C7X5UAEI.js"},{"revision":null,"url":"assets/tab-store-BCfMgMKM.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-J18kIhk2.js"},{"revision":null,"url":"assets/settings-tab-CwLkeZaa.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-D95__akI.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-CW2c3h_9.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-BxDBTcFM.js"},{"revision":null,"url":"assets/katex-Bqvo_ZG0.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-Bi0UTUeN.js"},{"revision":null,"url":"assets/jsx-runtime-BRW_vwa9.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/input-BglMT33g.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-DJ1Bqwo4.css"},{"revision":null,"url":"assets/index-ButO-DnP.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-BNTU6kmo.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-D4v7ZbVE.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-DIqcTrDV.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-CKzVujYI.js"},{"revision":null,"url":"assets/dist-lF8CoYII.js"},{"revision":null,"url":"assets/dist-DylI9XxN.js"},{"revision":null,"url":"assets/dist-CSJdAyA9.js"},{"revision":null,"url":"assets/diff-viewer-CYSw0YBG.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-BOnawWoi.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-DLqYtXxt.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-B_AWZsOP.js"},{"revision":null,"url":"assets/columns-2-DpsNbZOc.js"},{"revision":null,"url":"assets/code-editor-BNAZzdyF.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-DeV0ehiG.js"},{"revision":null,"url":"assets/chat-tab-CVN2falD.js"},{"revision":null,"url":"assets/channel-wrd-NHWf.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-dV22iAsY.js"},{"revision":null,"url":"assets/browser-tab-sn8vZniz.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-TEF8Ally.js"},{"revision":null,"url":"assets/arrow-up--LjUXLEt.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-D21InCnR.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||`/`)}))});
|
package/package.json
CHANGED
|
@@ -131,6 +131,16 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
131
131
|
return null;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/** Extract text content from an SDK assistant message */
|
|
135
|
+
private extractAssistantText(msg: unknown): string {
|
|
136
|
+
const content = (msg as any)?.message?.content;
|
|
137
|
+
if (!Array.isArray(content)) return "";
|
|
138
|
+
return content
|
|
139
|
+
.filter((b: any) => b.type === "text" && typeof b.text === "string")
|
|
140
|
+
.map((b: any) => b.text)
|
|
141
|
+
.join("");
|
|
142
|
+
}
|
|
143
|
+
|
|
134
144
|
/** Read current provider config from yaml (fresh each call) */
|
|
135
145
|
private getProviderConfig(): Partial<import("../types/config.ts").AIProviderConfig> {
|
|
136
146
|
const ai = configService.get("ai");
|
|
@@ -619,7 +629,18 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
619
629
|
// Full assistant message
|
|
620
630
|
if (msg.type === "assistant") {
|
|
621
631
|
// SDK assistant messages can carry an error field for auth/billing/rate-limit failures
|
|
622
|
-
|
|
632
|
+
let assistantError = (msg as any).error as string | undefined;
|
|
633
|
+
|
|
634
|
+
// SDK sometimes returns auth errors as text content without setting error field.
|
|
635
|
+
// Detect 401 pattern in text: "Failed to authenticate. API Error: 401 ..."
|
|
636
|
+
if (!assistantError) {
|
|
637
|
+
const textContent = this.extractAssistantText(msg);
|
|
638
|
+
if (textContent && /API Error:\s*401\b.*authentication_error/i.test(textContent)) {
|
|
639
|
+
assistantError = "authentication_failed";
|
|
640
|
+
console.warn(`[sdk] session=${sessionId} detected 401 in assistant text content — treating as auth error`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
623
644
|
if (assistantError) {
|
|
624
645
|
// Dump full SDK message for debugging
|
|
625
646
|
console.error(`[sdk] session=${sessionId} cwd=${effectiveCwd} assistant error: ${assistantError} (isFirst=${isFirstMessage} retry=${retryCount})`);
|
|
@@ -630,10 +651,11 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
630
651
|
authRetried = true;
|
|
631
652
|
try {
|
|
632
653
|
await accountService.refreshAccessToken(account.id, false);
|
|
633
|
-
console.log(`[sdk] session=${sessionId} OAuth token refreshed for ${account.id} — retrying`);
|
|
634
|
-
// Re-build env with refreshed token
|
|
635
654
|
const refreshedAccount = accountService.getWithTokens(account.id);
|
|
636
655
|
if (refreshedAccount) {
|
|
656
|
+
const label = refreshedAccount.label ?? refreshedAccount.email ?? "Unknown";
|
|
657
|
+
console.log(`[sdk] session=${sessionId} OAuth token refreshed for ${account.id} (${label}) — retrying`);
|
|
658
|
+
yield { type: "account_retry" as const, reason: "Token refreshed", accountId: refreshedAccount.id, accountLabel: label };
|
|
637
659
|
const retryEnv = this.buildQueryEnv(meta.projectPath, refreshedAccount);
|
|
638
660
|
const retryOpts = { ...queryOptions, sessionId: undefined, resume: undefined, env: retryEnv };
|
|
639
661
|
const rq = query({
|
|
@@ -660,6 +682,8 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
660
682
|
};
|
|
661
683
|
const hint = errorHints[assistantError] ?? `API error: ${assistantError}`;
|
|
662
684
|
yield { type: "error", message: hint };
|
|
685
|
+
// Skip emitting the raw 401 error as text content — already shown as error event
|
|
686
|
+
continue;
|
|
663
687
|
}
|
|
664
688
|
const content = (msg as any).message?.content;
|
|
665
689
|
if (Array.isArray(content)) {
|
|
@@ -715,11 +739,30 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
715
739
|
yield { type: "error", message: "Rate limited. This account is now on cooldown. Please retry." };
|
|
716
740
|
break;
|
|
717
741
|
} else if (errCode === 401) {
|
|
718
|
-
//
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
742
|
+
// Refresh token and retry with fresh session (same logic as assistant-level auth retry)
|
|
743
|
+
if (!authRetried) {
|
|
744
|
+
authRetried = true;
|
|
745
|
+
try {
|
|
746
|
+
await accountService.refreshAccessToken(account.id, false);
|
|
747
|
+
const refreshedAccount = accountService.getWithTokens(account.id);
|
|
748
|
+
if (refreshedAccount) {
|
|
749
|
+
const label = refreshedAccount.label ?? refreshedAccount.email ?? "Unknown";
|
|
750
|
+
console.log(`[sdk] 401 in result on account ${account.id} (${label}) — token refreshed, retrying`);
|
|
751
|
+
yield { type: "account_retry" as const, reason: "Token refreshed", accountId: refreshedAccount.id, accountLabel: label };
|
|
752
|
+
const retryEnv = this.buildQueryEnv(meta.projectPath, refreshedAccount);
|
|
753
|
+
const retryOpts = { ...queryOptions, sessionId: undefined, resume: undefined, env: retryEnv };
|
|
754
|
+
const rq = query({
|
|
755
|
+
prompt: message,
|
|
756
|
+
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
757
|
+
});
|
|
758
|
+
this.activeQueries.set(sessionId, rq);
|
|
759
|
+
eventSource = rq;
|
|
760
|
+
continue retryLoop;
|
|
761
|
+
}
|
|
762
|
+
} catch {
|
|
763
|
+
accountSelector.onAuthError(account.id);
|
|
764
|
+
}
|
|
765
|
+
} else {
|
|
723
766
|
accountSelector.onAuthError(account.id);
|
|
724
767
|
}
|
|
725
768
|
} else {
|
|
@@ -8,6 +8,7 @@ import { renameSession as sdkRenameSession } from "@anthropic-ai/claude-agent-sd
|
|
|
8
8
|
import { listSlashItems } from "../../services/slash-items.service.ts";
|
|
9
9
|
import { getCachedUsage, refreshUsageNow } from "../../services/claude-usage.service.ts";
|
|
10
10
|
import { getSessionLog } from "../../services/session-log.service.ts";
|
|
11
|
+
import { getSessionMapping } from "../../services/db.service.ts";
|
|
11
12
|
import { getSessionMapping, setSessionTitle } from "../../services/db.service.ts";
|
|
12
13
|
import { ok, err } from "../../types/api.ts";
|
|
13
14
|
|
|
@@ -169,6 +170,22 @@ chatRoutes.get("/sessions/:id/logs", (c) => {
|
|
|
169
170
|
}
|
|
170
171
|
});
|
|
171
172
|
|
|
173
|
+
/** GET /chat/sessions/:id/debug — session debug info (IDs, JSONL path) */
|
|
174
|
+
chatRoutes.get("/sessions/:id/debug", (c) => {
|
|
175
|
+
const ppmId = c.req.param("id");
|
|
176
|
+
const sdkId = getSessionMapping(ppmId) ?? ppmId;
|
|
177
|
+
const projectName = c.req.query("project") ?? "";
|
|
178
|
+
// Resolve JSONL path: ~/.claude/projects/<encoded-cwd>/<sdkId>.jsonl
|
|
179
|
+
const homedir = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
180
|
+
const provider = providerRegistry.get("claude") as any;
|
|
181
|
+
const projectPath = provider?.activeSessions?.get(ppmId)?.projectPath ?? "";
|
|
182
|
+
const encodedCwd = projectPath ? projectPath.replace(/\//g, "-") : "";
|
|
183
|
+
const jsonlDir = encodedCwd ? resolve(homedir, ".claude", "projects", encodedCwd) : "";
|
|
184
|
+
const jsonlPath = jsonlDir ? resolve(jsonlDir, `${sdkId}.jsonl`) : "";
|
|
185
|
+
const jsonlExists = jsonlPath ? existsSync(jsonlPath) : false;
|
|
186
|
+
return c.json(ok({ ppmSessionId: ppmId, sdkSessionId: sdkId, jsonlPath: jsonlExists ? jsonlPath : null, jsonlDir, projectPath }));
|
|
187
|
+
});
|
|
188
|
+
|
|
172
189
|
/** POST /chat/upload — upload files for chat attachments, returns server-side paths */
|
|
173
190
|
chatRoutes.post("/upload", async (c) => {
|
|
174
191
|
try {
|
package/src/server/ws/chat.ts
CHANGED
|
@@ -11,7 +11,7 @@ const CLEANUP_TIMEOUT_MS = 5 * 60_000; // 5min after Claude done + no FE
|
|
|
11
11
|
const MAX_TURN_EVENTS = 10_000; // memory safety cap
|
|
12
12
|
const BUFFERABLE_TYPES = new Set([
|
|
13
13
|
"text", "thinking", "tool_use", "tool_result",
|
|
14
|
-
"approval_request", "error", "done", "account_info",
|
|
14
|
+
"approval_request", "error", "done", "account_info", "account_retry",
|
|
15
15
|
]);
|
|
16
16
|
|
|
17
17
|
type ChatWsSocket = {
|
|
@@ -210,7 +210,7 @@ async function runStreamLoop(sessionId: string, providerId: string, content: str
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
// First content event — stop heartbeat, transition phase
|
|
213
|
-
const isMetadataEvent = evType === "account_info" || evType === "streaming_status";
|
|
213
|
+
const isMetadataEvent = evType === "account_info" || evType === "account_retry" || evType === "streaming_status";
|
|
214
214
|
if (!firstEventReceived && !isMetadataEvent) {
|
|
215
215
|
firstEventReceived = true;
|
|
216
216
|
const waitMs = Date.now() - startTime;
|
package/src/types/chat.ts
CHANGED
|
@@ -90,7 +90,8 @@ export type ChatEvent =
|
|
|
90
90
|
| { type: "approval_request"; requestId: string; tool: string; input: unknown }
|
|
91
91
|
| { type: "error"; message: string }
|
|
92
92
|
| { type: "done"; sessionId: string; resultSubtype?: ResultSubtype; numTurns?: number; contextWindowPct?: number }
|
|
93
|
-
| { type: "account_info"; accountId: string; accountLabel: string }
|
|
93
|
+
| { type: "account_info"; accountId: string; accountLabel: string }
|
|
94
|
+
| { type: "account_retry"; reason: string; accountId?: string; accountLabel?: string };
|
|
94
95
|
|
|
95
96
|
export type ToolApprovalHandler = (
|
|
96
97
|
tool: string,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
2
|
-
import { History, Settings2, Loader2, MessageSquare, RefreshCw, Search, Pencil, Check, X, BellOff } from "lucide-react";
|
|
2
|
+
import { History, Settings2, Loader2, MessageSquare, RefreshCw, Search, Pencil, Check, X, BellOff, Bug, ClipboardCheck } from "lucide-react";
|
|
3
3
|
import { Activity } from "lucide-react";
|
|
4
4
|
import { api, projectUrl } from "@/lib/api-client";
|
|
5
5
|
import { useTabStore } from "@/stores/tab-store";
|
|
@@ -48,6 +48,34 @@ function pctColor(pct: number): string {
|
|
|
48
48
|
return "text-green-500";
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
function DebugCopyButton({ sessionId, projectName }: { sessionId: string; projectName: string }) {
|
|
52
|
+
const [copied, setCopied] = useState(false);
|
|
53
|
+
return (
|
|
54
|
+
<button
|
|
55
|
+
onClick={async () => {
|
|
56
|
+
try {
|
|
57
|
+
const data = await api.get<{ ppmSessionId: string; sdkSessionId: string; jsonlPath: string | null; projectPath: string }>(
|
|
58
|
+
`${projectUrl(projectName)}/chat/sessions/${sessionId}/debug?project=${encodeURIComponent(projectName)}`,
|
|
59
|
+
);
|
|
60
|
+
const info = [
|
|
61
|
+
`PPM Session: ${data.ppmSessionId}`,
|
|
62
|
+
`SDK Session: ${data.sdkSessionId}`,
|
|
63
|
+
data.jsonlPath ? `JSONL: ${data.jsonlPath}` : `JSONL: not found`,
|
|
64
|
+
data.projectPath ? `Project: ${data.projectPath}` : null,
|
|
65
|
+
].filter(Boolean).join("\n");
|
|
66
|
+
await navigator.clipboard.writeText(info);
|
|
67
|
+
setCopied(true);
|
|
68
|
+
setTimeout(() => setCopied(false), 1500);
|
|
69
|
+
} catch { /* silent */ }
|
|
70
|
+
}}
|
|
71
|
+
className={`p-1 rounded transition-colors ${copied ? "text-green-500 bg-green-500/10" : "text-text-subtle hover:text-text-secondary hover:bg-surface-elevated"}`}
|
|
72
|
+
title={copied ? "Copied!" : "Copy session debug info"}
|
|
73
|
+
>
|
|
74
|
+
{copied ? <ClipboardCheck className="size-3" /> : <Bug className="size-3" />}
|
|
75
|
+
</button>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
51
79
|
export function ChatHistoryBar({
|
|
52
80
|
projectName, usageInfo, contextWindowPct, usageLoading, refreshUsage, lastFetchedAt,
|
|
53
81
|
sessionId, onSelectSession, onBugReport, isConnected, onReconnect,
|
|
@@ -195,6 +223,11 @@ export function ChatHistoryBar({
|
|
|
195
223
|
</button>
|
|
196
224
|
)}
|
|
197
225
|
|
|
226
|
+
{/* Debug info — copy session IDs + JSONL path */}
|
|
227
|
+
{sessionId && (
|
|
228
|
+
<DebugCopyButton sessionId={sessionId} projectName={projectName} />
|
|
229
|
+
)}
|
|
230
|
+
|
|
198
231
|
{/* Connection indicator */}
|
|
199
232
|
{onReconnect && (
|
|
200
233
|
<button
|
|
@@ -610,6 +610,13 @@ function InterleavedEvents({ events, isStreaming, projectName }: { events: ChatE
|
|
|
610
610
|
groups.push({ kind: "thinking", content: thinkingBuffer });
|
|
611
611
|
thinkingBuffer = "";
|
|
612
612
|
}
|
|
613
|
+
if (event.type === "account_retry") {
|
|
614
|
+
if (textBuffer) { groups.push({ kind: "text", content: textBuffer }); textBuffer = ""; }
|
|
615
|
+
const label = (event as any).accountLabel ?? "another account";
|
|
616
|
+
const reason = (event as any).reason ?? "Auth failed";
|
|
617
|
+
groups.push({ kind: "text", content: `\n\n> ↻ ${reason} — retrying with **${label}**...\n\n` });
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
613
620
|
if (event.type === "text") {
|
|
614
621
|
textBuffer += event.content;
|
|
615
622
|
} else if (event.type === "tool_use") {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { Suspense, lazy } from "react";
|
|
1
|
+
import { Suspense, lazy, useEffect, useState, useCallback } from "react";
|
|
2
2
|
import { Loader2, Terminal, MessageSquare, GitBranch } from "lucide-react";
|
|
3
3
|
import { usePanelStore } from "@/stores/panel-store";
|
|
4
4
|
import { useProjectStore } from "@/stores/project-store";
|
|
5
5
|
import type { TabType } from "@/stores/tab-store";
|
|
6
|
+
import { api, projectUrl } from "@/lib/api-client";
|
|
7
|
+
import type { SessionInfo } from "../../../types/chat";
|
|
6
8
|
import { TabBar } from "./tab-bar";
|
|
7
9
|
import { SplitDropOverlay } from "./split-drop-overlay";
|
|
8
10
|
import { cn } from "@/lib/utils";
|
|
@@ -74,8 +76,45 @@ export function EditorPanel({ panelId, projectName }: EditorPanelProps) {
|
|
|
74
76
|
);
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
function formatRelativeDate(iso: string): string {
|
|
80
|
+
try {
|
|
81
|
+
const date = new Date(iso);
|
|
82
|
+
const now = new Date();
|
|
83
|
+
const diffMs = now.getTime() - date.getTime();
|
|
84
|
+
const diffMin = Math.floor(diffMs / 60_000);
|
|
85
|
+
if (diffMin < 1) return "Just now";
|
|
86
|
+
if (diffMin < 60) return `${diffMin}m ago`;
|
|
87
|
+
const diffHr = Math.floor(diffMin / 60);
|
|
88
|
+
if (diffHr < 24) return `${diffHr}h ago`;
|
|
89
|
+
const diffDay = Math.floor(diffHr / 24);
|
|
90
|
+
if (diffDay < 7) return `${diffDay}d ago`;
|
|
91
|
+
return date.toLocaleDateString(undefined, { month: "short", day: "numeric" });
|
|
92
|
+
} catch {
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const MAX_RECENT_SESSIONS = 5;
|
|
98
|
+
|
|
77
99
|
function EmptyPanel({ panelId }: { panelId: string }) {
|
|
78
100
|
const activeProject = useProjectStore((s) => s.activeProject);
|
|
101
|
+
const [sessions, setSessions] = useState<SessionInfo[]>([]);
|
|
102
|
+
const [loadingSessions, setLoadingSessions] = useState(false);
|
|
103
|
+
|
|
104
|
+
const loadSessions = useCallback(async () => {
|
|
105
|
+
if (!activeProject?.name) return;
|
|
106
|
+
setLoadingSessions(true);
|
|
107
|
+
try {
|
|
108
|
+
const data = await api.get<SessionInfo[]>(`${projectUrl(activeProject.name)}/chat/sessions`);
|
|
109
|
+
setSessions(data.slice(0, MAX_RECENT_SESSIONS));
|
|
110
|
+
} catch {
|
|
111
|
+
// silently ignore — empty state still functional without sessions
|
|
112
|
+
} finally {
|
|
113
|
+
setLoadingSessions(false);
|
|
114
|
+
}
|
|
115
|
+
}, [activeProject?.name]);
|
|
116
|
+
|
|
117
|
+
useEffect(() => { loadSessions(); }, [loadSessions]);
|
|
79
118
|
|
|
80
119
|
function openTab(type: TabType) {
|
|
81
120
|
const needsProject = type !== "settings";
|
|
@@ -86,23 +125,63 @@ function EmptyPanel({ panelId }: { panelId: string }) {
|
|
|
86
125
|
);
|
|
87
126
|
}
|
|
88
127
|
|
|
128
|
+
function openSession(session: SessionInfo) {
|
|
129
|
+
usePanelStore.getState().openTab(
|
|
130
|
+
{
|
|
131
|
+
type: "chat",
|
|
132
|
+
title: session.title || "Chat",
|
|
133
|
+
projectId: activeProject?.name ?? null,
|
|
134
|
+
metadata: { projectName: activeProject?.name, sessionId: session.id, providerId: session.providerId },
|
|
135
|
+
closable: true,
|
|
136
|
+
},
|
|
137
|
+
panelId,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
89
141
|
return (
|
|
90
|
-
<div className="flex flex-col
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
142
|
+
<div className="flex flex-col h-full overflow-y-auto text-text-secondary">
|
|
143
|
+
<div className="flex flex-col items-center justify-center gap-6 px-4 flex-1">
|
|
144
|
+
<p className="text-sm">Open a tab to get started</p>
|
|
145
|
+
<div className="grid grid-cols-3 gap-2 w-full max-w-sm">
|
|
146
|
+
{QUICK_OPEN_TABS.map((opt) => {
|
|
147
|
+
const Icon = opt.icon;
|
|
148
|
+
return (
|
|
149
|
+
<button
|
|
150
|
+
key={opt.type}
|
|
151
|
+
onClick={() => openTab(opt.type)}
|
|
152
|
+
className="flex flex-col items-center justify-center gap-1.5 px-2 py-3 rounded-md border border-border bg-surface hover:bg-surface-elevated active:bg-surface-elevated text-xs text-foreground transition-colors"
|
|
153
|
+
>
|
|
154
|
+
<Icon className="size-5" />
|
|
155
|
+
{opt.label}
|
|
156
|
+
</button>
|
|
157
|
+
);
|
|
158
|
+
})}
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
{activeProject && !loadingSessions && sessions.length > 0 && (
|
|
162
|
+
<div className="flex flex-col gap-2 w-full max-w-sm">
|
|
163
|
+
<p className="text-xs text-text-subtle text-center">Recent chats</p>
|
|
164
|
+
<div className="w-full rounded-md border border-border bg-surface overflow-hidden">
|
|
165
|
+
{sessions.map((session) => (
|
|
166
|
+
<button
|
|
167
|
+
key={session.id}
|
|
168
|
+
onClick={() => openSession(session)}
|
|
169
|
+
className="flex items-center gap-2.5 w-full px-3 py-2.5 text-left hover:bg-surface-elevated active:bg-surface-elevated transition-colors border-b border-border/50 last:border-0"
|
|
170
|
+
>
|
|
171
|
+
<MessageSquare className="size-3.5 shrink-0 text-text-subtle" />
|
|
172
|
+
<span className="flex-1 min-w-0 text-xs font-medium truncate text-text-primary">
|
|
173
|
+
{session.title || "Untitled"}
|
|
174
|
+
</span>
|
|
175
|
+
{session.updatedAt && (
|
|
176
|
+
<span className="text-[10px] text-text-subtle shrink-0">
|
|
177
|
+
{formatRelativeDate(session.updatedAt)}
|
|
178
|
+
</span>
|
|
179
|
+
)}
|
|
180
|
+
</button>
|
|
181
|
+
))}
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
)}
|
|
106
185
|
</div>
|
|
107
186
|
</div>
|
|
108
187
|
);
|
|
@@ -118,6 +118,17 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
118
118
|
break;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
case "account_retry": {
|
|
122
|
+
// Update streaming account to the new one being tried
|
|
123
|
+
if (ev.accountId && ev.accountLabel) {
|
|
124
|
+
streamingAccountRef.current = { accountId: ev.accountId, accountLabel: ev.accountLabel };
|
|
125
|
+
}
|
|
126
|
+
// Surface retry as a system-level event in the stream
|
|
127
|
+
streamingEventsRef.current.push(ev as ChatEvent);
|
|
128
|
+
syncMessages();
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
|
|
121
132
|
case "text": {
|
|
122
133
|
const pid = ev.parentToolUseId as string | undefined;
|
|
123
134
|
if (pid && routeToParent(ev as ChatEvent, pid)) {
|