@hienlh/ppm 0.9.0-beta.4 → 0.9.0-beta.5

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.

Potentially problematic release.


This version of @hienlh/ppm might be problematic. Click here for more details.

Files changed (27) hide show
  1. package/CHANGELOG.md +21 -8
  2. package/dist/web/assets/browser-tab-CEYAwJUI.js +1 -0
  3. package/dist/web/assets/chat-tab-C8bt4tdL.js +7 -0
  4. package/dist/web/assets/{code-editor-BRMOypkX.js → code-editor-BVt8uVtX.js} +1 -1
  5. package/dist/web/assets/{database-viewer-CEoDpzPz.js → database-viewer-CNi9B6tN.js} +1 -1
  6. package/dist/web/assets/{diff-viewer-jDU2bcGj.js → diff-viewer-CnjvJhwy.js} +1 -1
  7. package/dist/web/assets/{git-graph-DMQzw4Sp.js → git-graph-BNbraUOe.js} +1 -1
  8. package/dist/web/assets/{index-QiSWS6f-.js → index-CKvJPAPG.js} +3 -3
  9. package/dist/web/assets/keybindings-store-Cmf2viOa.js +1 -0
  10. package/dist/web/assets/{markdown-renderer-BCjJbGP8.js → markdown-renderer-CFW_zoSR.js} +1 -1
  11. package/dist/web/assets/{postgres-viewer-s0snZ9CL.js → postgres-viewer-Dg23WW__.js} +1 -1
  12. package/dist/web/assets/{settings-tab-2YkgmrY0.js → settings-tab-rB971cXs.js} +1 -1
  13. package/dist/web/assets/{sqlite-viewer-B5GNwXaG.js → sqlite-viewer-D3N938wy.js} +1 -1
  14. package/dist/web/assets/{terminal-tab-MRg8y1xF.js → terminal-tab-BdHlIi8e.js} +2 -2
  15. package/dist/web/index.html +1 -1
  16. package/dist/web/sw.js +1 -1
  17. package/package.json +1 -1
  18. package/src/providers/claude-agent-sdk.ts +212 -76
  19. package/src/server/ws/chat.ts +103 -73
  20. package/src/types/api.ts +1 -1
  21. package/src/types/chat.ts +2 -0
  22. package/src/web/components/chat/chat-tab.tsx +3 -3
  23. package/src/web/components/chat/message-input.tsx +41 -4
  24. package/src/web/hooks/use-chat.ts +21 -9
  25. package/dist/web/assets/browser-tab-BhTdeeZd.js +0 -1
  26. package/dist/web/assets/chat-tab-ZiiUVOxM.js +0 -7
  27. package/dist/web/assets/keybindings-store-BplH-yiN.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":"449f8c10830c0468fda5727a6f347626","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-BRvXOVlG.js"},{"revision":null,"url":"assets/vennDiagram-LZ73GAT5-DfYFnniI.js"},{"revision":null,"url":"assets/utils-Bslrbb-G.js"},{"revision":null,"url":"assets/use-monaco-theme-BQzvItNE.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-BL9OJq3X.js"},{"revision":null,"url":"assets/timeline-definition-YZTLITO2-DrjxCpEM.js"},{"revision":null,"url":"assets/terminal-tab-MRg8y1xF.js"},{"revision":null,"url":"assets/terminal-tab-BrP-ENHg.css"},{"revision":null,"url":"assets/tag-CENGyt_L.js"},{"revision":null,"url":"assets/table-C9jDaRl2.js"},{"revision":null,"url":"assets/tab-store-DSz5PQI0.js"},{"revision":null,"url":"assets/switch-mjGtIVDJ.js"},{"revision":null,"url":"assets/stateDiagram-v2-FVOUBMTO-D7qSAjnK.js"},{"revision":null,"url":"assets/stateDiagram-RAJIS63D-C16aO8tn.js"},{"revision":null,"url":"assets/src-CLWraeNW.js"},{"revision":null,"url":"assets/sqlite-viewer-B5GNwXaG.js"},{"revision":null,"url":"assets/settings-tab-2YkgmrY0.js"},{"revision":null,"url":"assets/settings-store-D3dJqGhB.js"},{"revision":null,"url":"assets/sequenceDiagram-2WXFIKYE-BtRvoUTC.js"},{"revision":null,"url":"assets/sankeyDiagram-WA2Y5GQK-DEGGYsk7.js"},{"revision":null,"url":"assets/rough.esm-c4PR5shF.js"},{"revision":null,"url":"assets/requirementDiagram-Z7DCOOCP-1WWjMQB_.js"},{"revision":null,"url":"assets/react-nm2Ru1Pt.js"},{"revision":null,"url":"assets/react-BPIfZRKM.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-CHptMqVT.js"},{"revision":null,"url":"assets/quadrantDiagram-337W2JSQ-BaRFqlsA.js"},{"revision":null,"url":"assets/preload-helper-CsoeaaUJ.js"},{"revision":null,"url":"assets/postgres-viewer-s0snZ9CL.js"},{"revision":null,"url":"assets/pieDiagram-SKSYHLDU-seSK40d1.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-B0h6hM1j.js"},{"revision":null,"url":"assets/path-CuyvWNAH.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-BbzPU9BK.js"},{"revision":null,"url":"assets/ordinal-CIoJK3nc.js"},{"revision":null,"url":"assets/mindmap-definition-YRQLILUH-DIv-LMXG.js"},{"revision":null,"url":"assets/mermaid-parser.core-BY8JfkE_.js"},{"revision":null,"url":"assets/math-a44lmFDa.js"},{"revision":null,"url":"assets/markdown-renderer-BCjJbGP8.js"},{"revision":null,"url":"assets/linear-BdqW7iQu.js"},{"revision":null,"url":"assets/line--xyfYP3x.js"},{"revision":null,"url":"assets/keybindings-store-BplH-yiN.js"},{"revision":null,"url":"assets/katex-C3cZrCvP.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-BMUhjxqj.js"},{"revision":null,"url":"assets/jsx-runtime-BRW_vwa9.js"},{"revision":null,"url":"assets/journeyDiagram-4ABVD52K-DFQXUZsc.js"},{"revision":null,"url":"assets/ishikawaDiagram-PHBUUO56-cW7SMLa_.js"},{"revision":null,"url":"assets/isEmpty-DXomfd7J.js"},{"revision":null,"url":"assets/isArrayLikeObject-DvHDmeBe.js"},{"revision":null,"url":"assets/input-DGlv6gt_.js"},{"revision":null,"url":"assets/init-vVpfz1D6.js"},{"revision":null,"url":"assets/infoDiagram-LFFYTUFH-DFh9c-S2.js"},{"revision":null,"url":"assets/info-3K5VOQVL-CbpovIYU.js"},{"revision":null,"url":"assets/index-QiSWS6f-.js"},{"revision":null,"url":"assets/index-B4Iz1Wbi.css"},{"revision":null,"url":"assets/graphlib-BbbiUImY.js"},{"revision":null,"url":"assets/gitGraphDiagram-K3NZZRJ6-L7sj3Bs-.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-D5qEPjgs.js"},{"revision":null,"url":"assets/git-graph-DMQzw4Sp.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-BVlftqyZ.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-B9h_Ba-v.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-DK4QEZYh.js"},{"revision":null,"url":"assets/dist-Ckxnw5rl.js"},{"revision":null,"url":"assets/dist-CMmNEgEP.js"},{"revision":null,"url":"assets/diff-viewer-jDU2bcGj.js"},{"revision":null,"url":"assets/diagram-P4PSJMXO--nUaNiyB.js"},{"revision":null,"url":"assets/diagram-IFDJBPK2-NvhckwcA.js"},{"revision":null,"url":"assets/diagram-E7M64L7V-CkDC2uAj.js"},{"revision":null,"url":"assets/defaultLocale-D_VMtRaY.js"},{"revision":null,"url":"assets/database-viewer-CEoDpzPz.js"},{"revision":null,"url":"assets/dagre-KLK3FWXG-Br4t5TRV.js"},{"revision":null,"url":"assets/dagre-CWo8w9wK.js"},{"revision":null,"url":"assets/cytoscape.esm-B-QQuWwK.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-C1QJ6GPW.js"},{"revision":null,"url":"assets/columns-2-Bcg3QJBg.js"},{"revision":null,"url":"assets/code-editor-BRMOypkX.js"},{"revision":null,"url":"assets/clone-DNDy9Sms.js"},{"revision":null,"url":"assets/classDiagram-v2-RAHNMMFH-Bo5WN2ok.js"},{"revision":null,"url":"assets/classDiagram-VBA2DB6C-CqaIqYPn.js"},{"revision":null,"url":"assets/chunk-YBOYWFTD-COdZIaX4.js"},{"revision":null,"url":"assets/chunk-XZSTWKYB-5W2emiq4.js"},{"revision":null,"url":"assets/chunk-XPW4576I-CsGTseUr.js"},{"revision":null,"url":"assets/chunk-XIRO2GV7-DUmQrLsF.js"},{"revision":null,"url":"assets/chunk-WL4C6EOR-BHFnnXOt.js"},{"revision":null,"url":"assets/chunk-R5LLSJPH-LdG7RqsM.js"},{"revision":null,"url":"assets/chunk-QZHKN3VN-gaBt0Rbd.js"},{"revision":null,"url":"assets/chunk-PU5JKC2W-D3thuSok.js"},{"revision":null,"url":"assets/chunk-PQ6SQG4A-EdgQyTqa.js"},{"revision":null,"url":"assets/chunk-OZEHJAEY-LfXT4p8B.js"},{"revision":null,"url":"assets/chunk-O4XLMI2P-BdXwVXjJ.js"},{"revision":null,"url":"assets/chunk-NQ4KR5QH-BRj25yO7.js"},{"revision":null,"url":"assets/chunk-MX3YWQON-BnPzQK-O.js"},{"revision":null,"url":"assets/chunk-L3YUKLVL-DNFj84V6.js"},{"revision":null,"url":"assets/chunk-KYZI473N-CBRPKraG.js"},{"revision":null,"url":"assets/chunk-KX2RTZJC-BRj-ZEvL.js"},{"revision":null,"url":"assets/chunk-JSJVCQXG-Pb-JMOgO.js"},{"revision":null,"url":"assets/chunk-HHEYEP7N-BnRVfNc5.js"},{"revision":null,"url":"assets/chunk-GLR3WWYH-Bx2UL5jF.js"},{"revision":null,"url":"assets/chunk-GEFDOKGD-B82RP9ow.js"},{"revision":null,"url":"assets/chunk-FMBD7UC4-JCLgVcaC.js"},{"revision":null,"url":"assets/chunk-EGIJ26TM-Cgt-qg75.js"},{"revision":null,"url":"assets/chunk-CFjPhJqf.js"},{"revision":null,"url":"assets/chunk-C72U2L5F-CcEW1AMZ.js"},{"revision":null,"url":"assets/chunk-7R4GIKGN-DvbvLUIN.js"},{"revision":null,"url":"assets/chunk-7E7YKBS2-CuYKSUgJ.js"},{"revision":null,"url":"assets/chunk-55IACEB6-Dp0pTM5r.js"},{"revision":null,"url":"assets/chunk-4BX2VUAB-0YMkpW2S.js"},{"revision":null,"url":"assets/chat-tab-ZiiUVOxM.js"},{"revision":null,"url":"assets/channel-CKNZAqoN.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-DzjR91sM.js"},{"revision":null,"url":"assets/browser-tab-BhTdeeZd.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-CU2t4NHJ.js"},{"revision":null,"url":"assets/arrow-left-C_j9Ki73.js"},{"revision":null,"url":"assets/array-CLwNaqU1.js"},{"revision":null,"url":"assets/architectureDiagram-2XIMDMQ5-BVEUkQYB.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-281eTKQ3.js"},{"revision":null,"url":"assets/arc-D0bJaFyD.js"},{"revision":null,"url":"assets/api-settings-CuUkz5gb.js"},{"revision":null,"url":"assets/api-client-icCZ-07C.js"},{"revision":null,"url":"assets/_baseUniq-DCb0mkTp.js"},{"revision":null,"url":"assets/_basePickBy-COwDPZl_.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":"d7aed6bbe50b5c895ef7f95d52f2cc4d","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-BRvXOVlG.js"},{"revision":null,"url":"assets/vennDiagram-LZ73GAT5-DfYFnniI.js"},{"revision":null,"url":"assets/utils-Bslrbb-G.js"},{"revision":null,"url":"assets/use-monaco-theme-BQzvItNE.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-BL9OJq3X.js"},{"revision":null,"url":"assets/timeline-definition-YZTLITO2-DrjxCpEM.js"},{"revision":null,"url":"assets/terminal-tab-BrP-ENHg.css"},{"revision":null,"url":"assets/terminal-tab-BdHlIi8e.js"},{"revision":null,"url":"assets/tag-CENGyt_L.js"},{"revision":null,"url":"assets/table-C9jDaRl2.js"},{"revision":null,"url":"assets/tab-store-DSz5PQI0.js"},{"revision":null,"url":"assets/switch-mjGtIVDJ.js"},{"revision":null,"url":"assets/stateDiagram-v2-FVOUBMTO-D7qSAjnK.js"},{"revision":null,"url":"assets/stateDiagram-RAJIS63D-C16aO8tn.js"},{"revision":null,"url":"assets/src-CLWraeNW.js"},{"revision":null,"url":"assets/sqlite-viewer-D3N938wy.js"},{"revision":null,"url":"assets/settings-tab-rB971cXs.js"},{"revision":null,"url":"assets/settings-store-D3dJqGhB.js"},{"revision":null,"url":"assets/sequenceDiagram-2WXFIKYE-BtRvoUTC.js"},{"revision":null,"url":"assets/sankeyDiagram-WA2Y5GQK-DEGGYsk7.js"},{"revision":null,"url":"assets/rough.esm-c4PR5shF.js"},{"revision":null,"url":"assets/requirementDiagram-Z7DCOOCP-1WWjMQB_.js"},{"revision":null,"url":"assets/react-nm2Ru1Pt.js"},{"revision":null,"url":"assets/react-BPIfZRKM.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-CHptMqVT.js"},{"revision":null,"url":"assets/quadrantDiagram-337W2JSQ-BaRFqlsA.js"},{"revision":null,"url":"assets/preload-helper-CsoeaaUJ.js"},{"revision":null,"url":"assets/postgres-viewer-Dg23WW__.js"},{"revision":null,"url":"assets/pieDiagram-SKSYHLDU-seSK40d1.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-B0h6hM1j.js"},{"revision":null,"url":"assets/path-CuyvWNAH.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-BbzPU9BK.js"},{"revision":null,"url":"assets/ordinal-CIoJK3nc.js"},{"revision":null,"url":"assets/mindmap-definition-YRQLILUH-DIv-LMXG.js"},{"revision":null,"url":"assets/mermaid-parser.core-BY8JfkE_.js"},{"revision":null,"url":"assets/math-a44lmFDa.js"},{"revision":null,"url":"assets/markdown-renderer-CFW_zoSR.js"},{"revision":null,"url":"assets/linear-BdqW7iQu.js"},{"revision":null,"url":"assets/line--xyfYP3x.js"},{"revision":null,"url":"assets/keybindings-store-Cmf2viOa.js"},{"revision":null,"url":"assets/katex-C3cZrCvP.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-BMUhjxqj.js"},{"revision":null,"url":"assets/jsx-runtime-BRW_vwa9.js"},{"revision":null,"url":"assets/journeyDiagram-4ABVD52K-DFQXUZsc.js"},{"revision":null,"url":"assets/ishikawaDiagram-PHBUUO56-cW7SMLa_.js"},{"revision":null,"url":"assets/isEmpty-DXomfd7J.js"},{"revision":null,"url":"assets/isArrayLikeObject-DvHDmeBe.js"},{"revision":null,"url":"assets/input-DGlv6gt_.js"},{"revision":null,"url":"assets/init-vVpfz1D6.js"},{"revision":null,"url":"assets/infoDiagram-LFFYTUFH-DFh9c-S2.js"},{"revision":null,"url":"assets/info-3K5VOQVL-CbpovIYU.js"},{"revision":null,"url":"assets/index-CKvJPAPG.js"},{"revision":null,"url":"assets/index-B4Iz1Wbi.css"},{"revision":null,"url":"assets/graphlib-BbbiUImY.js"},{"revision":null,"url":"assets/gitGraphDiagram-K3NZZRJ6-L7sj3Bs-.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-D5qEPjgs.js"},{"revision":null,"url":"assets/git-graph-BNbraUOe.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-BVlftqyZ.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-B9h_Ba-v.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-DK4QEZYh.js"},{"revision":null,"url":"assets/dist-Ckxnw5rl.js"},{"revision":null,"url":"assets/dist-CMmNEgEP.js"},{"revision":null,"url":"assets/diff-viewer-CnjvJhwy.js"},{"revision":null,"url":"assets/diagram-P4PSJMXO--nUaNiyB.js"},{"revision":null,"url":"assets/diagram-IFDJBPK2-NvhckwcA.js"},{"revision":null,"url":"assets/diagram-E7M64L7V-CkDC2uAj.js"},{"revision":null,"url":"assets/defaultLocale-D_VMtRaY.js"},{"revision":null,"url":"assets/database-viewer-CNi9B6tN.js"},{"revision":null,"url":"assets/dagre-KLK3FWXG-Br4t5TRV.js"},{"revision":null,"url":"assets/dagre-CWo8w9wK.js"},{"revision":null,"url":"assets/cytoscape.esm-B-QQuWwK.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-C1QJ6GPW.js"},{"revision":null,"url":"assets/columns-2-Bcg3QJBg.js"},{"revision":null,"url":"assets/code-editor-BVt8uVtX.js"},{"revision":null,"url":"assets/clone-DNDy9Sms.js"},{"revision":null,"url":"assets/classDiagram-v2-RAHNMMFH-Bo5WN2ok.js"},{"revision":null,"url":"assets/classDiagram-VBA2DB6C-CqaIqYPn.js"},{"revision":null,"url":"assets/chunk-YBOYWFTD-COdZIaX4.js"},{"revision":null,"url":"assets/chunk-XZSTWKYB-5W2emiq4.js"},{"revision":null,"url":"assets/chunk-XPW4576I-CsGTseUr.js"},{"revision":null,"url":"assets/chunk-XIRO2GV7-DUmQrLsF.js"},{"revision":null,"url":"assets/chunk-WL4C6EOR-BHFnnXOt.js"},{"revision":null,"url":"assets/chunk-R5LLSJPH-LdG7RqsM.js"},{"revision":null,"url":"assets/chunk-QZHKN3VN-gaBt0Rbd.js"},{"revision":null,"url":"assets/chunk-PU5JKC2W-D3thuSok.js"},{"revision":null,"url":"assets/chunk-PQ6SQG4A-EdgQyTqa.js"},{"revision":null,"url":"assets/chunk-OZEHJAEY-LfXT4p8B.js"},{"revision":null,"url":"assets/chunk-O4XLMI2P-BdXwVXjJ.js"},{"revision":null,"url":"assets/chunk-NQ4KR5QH-BRj25yO7.js"},{"revision":null,"url":"assets/chunk-MX3YWQON-BnPzQK-O.js"},{"revision":null,"url":"assets/chunk-L3YUKLVL-DNFj84V6.js"},{"revision":null,"url":"assets/chunk-KYZI473N-CBRPKraG.js"},{"revision":null,"url":"assets/chunk-KX2RTZJC-BRj-ZEvL.js"},{"revision":null,"url":"assets/chunk-JSJVCQXG-Pb-JMOgO.js"},{"revision":null,"url":"assets/chunk-HHEYEP7N-BnRVfNc5.js"},{"revision":null,"url":"assets/chunk-GLR3WWYH-Bx2UL5jF.js"},{"revision":null,"url":"assets/chunk-GEFDOKGD-B82RP9ow.js"},{"revision":null,"url":"assets/chunk-FMBD7UC4-JCLgVcaC.js"},{"revision":null,"url":"assets/chunk-EGIJ26TM-Cgt-qg75.js"},{"revision":null,"url":"assets/chunk-CFjPhJqf.js"},{"revision":null,"url":"assets/chunk-C72U2L5F-CcEW1AMZ.js"},{"revision":null,"url":"assets/chunk-7R4GIKGN-DvbvLUIN.js"},{"revision":null,"url":"assets/chunk-7E7YKBS2-CuYKSUgJ.js"},{"revision":null,"url":"assets/chunk-55IACEB6-Dp0pTM5r.js"},{"revision":null,"url":"assets/chunk-4BX2VUAB-0YMkpW2S.js"},{"revision":null,"url":"assets/chat-tab-C8bt4tdL.js"},{"revision":null,"url":"assets/channel-CKNZAqoN.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-DzjR91sM.js"},{"revision":null,"url":"assets/browser-tab-CEYAwJUI.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-CU2t4NHJ.js"},{"revision":null,"url":"assets/arrow-left-C_j9Ki73.js"},{"revision":null,"url":"assets/array-CLwNaqU1.js"},{"revision":null,"url":"assets/architectureDiagram-2XIMDMQ5-BVEUkQYB.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-281eTKQ3.js"},{"revision":null,"url":"assets/arc-D0bJaFyD.js"},{"revision":null,"url":"assets/api-settings-CuUkz5gb.js"},{"revision":null,"url":"assets/api-client-icCZ-07C.js"},{"revision":null,"url":"assets/_baseUniq-DCb0mkTp.js"},{"revision":null,"url":"assets/_basePickBy-COwDPZl_.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.9.0-beta.4",
3
+ "version": "0.9.0-beta.5",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
@@ -25,6 +25,84 @@ function getSdkSessionId(ppmId: string): string {
25
25
  return getSessionMapping(ppmId) ?? ppmId;
26
26
  }
27
27
 
28
+ // ── Streaming Input: message channel for persistent query ──
29
+
30
+ interface MessageController {
31
+ push(msg: any): void;
32
+ done(): void;
33
+ }
34
+
35
+ function createMessageChannel(): {
36
+ generator: AsyncGenerator<any, void, undefined>;
37
+ controller: MessageController;
38
+ } {
39
+ const queue: any[] = [];
40
+ let resolve: ((msg: any) => void) | null = null;
41
+ let isDone = false;
42
+
43
+ async function* gen(): AsyncGenerator<any, void, undefined> {
44
+ while (!isDone) {
45
+ if (queue.length > 0) {
46
+ yield queue.shift()!;
47
+ } else {
48
+ const msg = await new Promise<any>((r) => { resolve = r; });
49
+ if (!isDone) yield msg;
50
+ }
51
+ }
52
+ }
53
+
54
+ return {
55
+ generator: gen(),
56
+ controller: {
57
+ push(msg: any) {
58
+ if (isDone) return;
59
+ if (resolve) {
60
+ const r = resolve;
61
+ resolve = null;
62
+ r(msg);
63
+ } else {
64
+ queue.push(msg);
65
+ }
66
+ },
67
+ done() {
68
+ isDone = true;
69
+ if (resolve) {
70
+ const r = resolve;
71
+ resolve = null;
72
+ r(null); // Unblock pending promise; isDone prevents yield
73
+ }
74
+ },
75
+ },
76
+ };
77
+ }
78
+
79
+ /** Build a MessageParam with optional image content blocks */
80
+ function buildMessageParam(
81
+ text: string,
82
+ images?: Array<{ data: string; mediaType: string }>,
83
+ ): { role: 'user'; content: string | any[] } {
84
+ if (!images || images.length === 0) {
85
+ return { role: 'user' as const, content: text };
86
+ }
87
+ const blocks: any[] = [];
88
+ for (const img of images) {
89
+ blocks.push({
90
+ type: 'image',
91
+ source: { type: 'base64', media_type: img.mediaType, data: img.data },
92
+ });
93
+ }
94
+ if (text.trim()) {
95
+ blocks.push({ type: 'text', text });
96
+ }
97
+ return { role: 'user' as const, content: blocks };
98
+ }
99
+
100
+ interface StreamingSession {
101
+ meta: Session;
102
+ query: any;
103
+ controller: MessageController;
104
+ }
105
+
28
106
  /**
29
107
  * Pending approval: canUseTool callback creates a promise,
30
108
  * yields an approval_request event, then awaits resolution from FE.
@@ -50,6 +128,8 @@ export class ClaudeAgentSdkProvider implements AIProvider {
50
128
  private activeQueries = new Map<string, { close: () => void }>();
51
129
  /** Fork source: ppmSessionId → sourceSessionId (used on first message to fork) */
52
130
  private forkSources = new Map<string, string>();
131
+ /** Streaming sessions: persistent query + message channel per session */
132
+ private streamingSessions = new Map<string, StreamingSession>();
53
133
 
54
134
  /** Auth-related env keys for diagnostic logging */
55
135
  private readonly AUTH_ENV_KEYS = ["ANTHROPIC_API_KEY", "ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN"];
@@ -220,6 +300,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
220
300
  }
221
301
 
222
302
  async deleteSession(sessionId: string): Promise<void> {
303
+ this.closeStreamingSession(sessionId);
223
304
  this.activeSessions.delete(sessionId);
224
305
  this.messageCount.delete(sessionId);
225
306
  }
@@ -260,11 +341,63 @@ export class ClaudeAgentSdkProvider implements AIProvider {
260
341
  }
261
342
  }
262
343
 
344
+ /**
345
+ * Push a follow-up message into an existing streaming session's generator.
346
+ * Called by WS handler for follow-up messages (Phase 2).
347
+ */
348
+ pushMessage(sessionId: string, content: string, opts?: { priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }> }): void {
349
+ const ss = this.streamingSessions.get(sessionId);
350
+ if (!ss) {
351
+ console.warn(`[sdk] pushMessage: no streaming session for ${sessionId}`);
352
+ return;
353
+ }
354
+ const msgContent = buildMessageParam(content, opts?.images);
355
+ ss.controller.push({
356
+ type: 'user',
357
+ message: msgContent,
358
+ parent_tool_use_id: null,
359
+ session_id: sessionId,
360
+ priority: opts?.priority ?? 'next',
361
+ });
362
+ console.log(`[sdk] pushMessage: session=${sessionId} priority=${opts?.priority ?? 'next'}`);
363
+ }
364
+
365
+ /** Close a streaming session — generator + query cleanup */
366
+ closeStreamingSession(sessionId: string): void {
367
+ const ss = this.streamingSessions.get(sessionId);
368
+ if (ss) {
369
+ ss.controller.done();
370
+ ss.query.close();
371
+ this.streamingSessions.delete(sessionId);
372
+ console.log(`[sdk] closeStreamingSession: session=${sessionId}`);
373
+ }
374
+ }
375
+
376
+ /** Check if a streaming session is active for a given session ID */
377
+ hasStreamingSession(sessionId: string): boolean {
378
+ return this.streamingSessions.has(sessionId);
379
+ }
380
+
263
381
  async *sendMessage(
264
382
  sessionId: string,
265
383
  message: string,
266
- opts?: import("./provider.interface.ts").SendMessageOpts & { forkSession?: boolean },
384
+ opts?: import("./provider.interface.ts").SendMessageOpts & { forkSession?: boolean; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }> },
267
385
  ): AsyncIterable<ChatEvent> {
386
+ // Follow-up: push into existing streaming session, yield nothing
387
+ const existingStream = this.streamingSessions.get(sessionId);
388
+ if (existingStream) {
389
+ const msgContent = buildMessageParam(message, opts?.images);
390
+ existingStream.controller.push({
391
+ type: 'user',
392
+ message: msgContent,
393
+ parent_tool_use_id: null,
394
+ session_id: sessionId,
395
+ priority: opts?.priority ?? 'next',
396
+ });
397
+ console.log(`[sdk] sendMessage follow-up: session=${sessionId} pushed to generator`);
398
+ return; // Events flow through first-message's consumer loop
399
+ }
400
+
268
401
  if (!this.activeSessions.has(sessionId)) {
269
402
  await this.resumeSession(sessionId);
270
403
  }
@@ -387,6 +520,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
387
520
  let resultSubtype: string | undefined;
388
521
  let resultNumTurns: number | undefined;
389
522
  let resultContextWindowPct: number | undefined;
523
+ let yieldedDone = false;
390
524
  try {
391
525
  // Resolve SDK's actual session ID for resume (may differ from PPM's UUID)
392
526
  // For fork: use the source session's SDK id
@@ -458,14 +592,25 @@ export class ClaudeAgentSdkProvider implements AIProvider {
458
592
  includePartialMessages: true,
459
593
  };
460
594
 
595
+ // Streaming input: create message channel and persistent query
596
+ const { generator: streamGen, controller: streamCtrl } = createMessageChannel();
597
+ const firstMsg = {
598
+ type: 'user' as const,
599
+ message: buildMessageParam(message),
600
+ parent_tool_use_id: null,
601
+ session_id: sessionId,
602
+ };
603
+ streamCtrl.push(firstMsg);
604
+
461
605
  const q = query({
462
- prompt: message,
606
+ prompt: streamGen,
463
607
  options: {
464
608
  ...queryOptions,
465
609
  ...(permissionHooks && { hooks: permissionHooks }),
466
610
  canUseTool,
467
611
  } as any,
468
612
  });
613
+ this.streamingSessions.set(sessionId, { meta, query: q, controller: streamCtrl });
469
614
  this.activeQueries.set(sessionId, q);
470
615
  let eventSource: AsyncIterable<any> = q;
471
616
 
@@ -480,22 +625,29 @@ export class ClaudeAgentSdkProvider implements AIProvider {
480
625
  let retryCount = 0;
481
626
  let authRetried = false;
482
627
 
628
+ let hadAnyEvents = false;
483
629
  retryLoop: while (true) {
484
630
  let sdkEventCount = 0;
485
631
  for await (const msg of eventSource) {
486
632
  sdkEventCount++;
633
+ hadAnyEvents = true;
487
634
  if (sdkEventCount === 1) {
488
635
  console.log(`[sdk] first event received: type=${(msg as any).type} subtype=${(msg as any).subtype ?? "none"}`);
489
636
  // Detect immediate failure: first event is a result with error + 0 turns
490
637
  if ((msg as any).type === "result" && (msg as any).subtype === "error_during_execution" && ((msg as any).num_turns ?? 0) === 0 && retryCount < MAX_RETRIES) {
491
638
  retryCount++;
492
639
  console.warn(`[sdk] transient error on first event — retrying (attempt ${retryCount}/${MAX_RETRIES})`);
493
- // Re-create query for retry don't reuse sessionId in case SDK partially created it
640
+ // Close failed query and old channel, create new channel + query for retry
641
+ streamCtrl.done();
642
+ q.close();
643
+ const { generator: retryGen, controller: retryCtrl } = createMessageChannel();
644
+ retryCtrl.push(firstMsg);
494
645
  const retryOpts = { ...queryOptions, sessionId: undefined, resume: undefined };
495
646
  const rq = query({
496
- prompt: message,
647
+ prompt: retryGen,
497
648
  options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
498
649
  });
650
+ this.streamingSessions.set(sessionId, { meta, query: rq, controller: retryCtrl });
499
651
  this.activeQueries.set(sessionId, rq);
500
652
  eventSource = rq;
501
653
  continue retryLoop;
@@ -641,11 +793,17 @@ export class ClaudeAgentSdkProvider implements AIProvider {
641
793
  const refreshedAccount = accountService.getWithTokens(account.id);
642
794
  if (refreshedAccount) {
643
795
  const retryEnv = this.buildQueryEnv(meta.projectPath, refreshedAccount);
796
+ // Close failed query and old channel, create new channel + query with refreshed token
797
+ streamCtrl.done();
798
+ q.close();
799
+ const { generator: authRetryGen, controller: authRetryCtrl } = createMessageChannel();
800
+ authRetryCtrl.push(firstMsg);
644
801
  const retryOpts = { ...queryOptions, sessionId: undefined, resume: undefined, env: retryEnv };
645
802
  const rq = query({
646
- prompt: message,
803
+ prompt: authRetryGen,
647
804
  options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
648
805
  });
806
+ this.streamingSessions.set(sessionId, { meta, query: rq, controller: authRetryCtrl });
649
807
  this.activeQueries.set(sessionId, rq);
650
808
  eventSource = rq;
651
809
  continue retryLoop;
@@ -717,9 +875,9 @@ export class ClaudeAgentSdkProvider implements AIProvider {
717
875
  const errCode = this.detectResultErrorCode(msg);
718
876
  if (errCode === 429) {
719
877
  accountSelector.onRateLimit(account.id);
720
- // Post-stream 429 already has content — surface error to user
878
+ // Post-stream 429 — surface error, continue waiting for next turn
721
879
  yield { type: "error", message: "Rate limited. This account is now on cooldown. Please retry." };
722
- break;
880
+ continue;
723
881
  } else if (errCode === 401) {
724
882
  // Try refresh once
725
883
  try {
@@ -827,7 +985,26 @@ export class ClaudeAgentSdkProvider implements AIProvider {
827
985
  }
828
986
  }
829
987
  }
830
- break;
988
+
989
+ // Streaming input: yield done for this turn, then continue for next turn
990
+ yieldedDone = true;
991
+ yield {
992
+ type: "done",
993
+ sessionId,
994
+ resultSubtype: resultSubtype as any,
995
+ numTurns: resultNumTurns,
996
+ contextWindowPct: resultContextWindowPct,
997
+ };
998
+
999
+ // Reset per-turn state for next turn
1000
+ lastPartialText = "";
1001
+ pendingToolCount = 0;
1002
+ assistantContent = "";
1003
+ resultSubtype = undefined;
1004
+ resultNumTurns = undefined;
1005
+ resultContextWindowPct = undefined;
1006
+ sdkEventCount = 0;
1007
+ continue; // Wait for next turn from generator
831
1008
  }
832
1009
  }
833
1010
 
@@ -836,7 +1013,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
836
1013
  yield approvalEvents.shift()!;
837
1014
  }
838
1015
 
839
- if (sdkEventCount === 0) {
1016
+ if (!hadAnyEvents) {
840
1017
  yield { type: "error", message: "Claude did not respond. Check that 'claude' CLI works in your terminal." };
841
1018
  }
842
1019
  break; // Exit retryLoop — normal completion
@@ -846,88 +1023,47 @@ export class ClaudeAgentSdkProvider implements AIProvider {
846
1023
  console.error(`[sdk] session=${sessionId} cwd=${meta.projectPath} error: ${msg}`);
847
1024
  if (msg.includes("abort") || msg.includes("closed")) {
848
1025
  // User-initiated abort or WS closed — nothing to report
849
- } else if (!isFirstMessage && msg.includes("exited with code")) {
850
- // SDK subprocess crashed during session resume retry as fresh session
851
- console.warn(`[sdk] session resume failed, retrying as fresh session`);
852
- try {
853
- const providerConfig = this.getProviderConfig();
854
- const effectiveCwd = meta.projectPath || homedir();
855
- const retryAccount = accountSelector.isEnabled() ? accountSelector.next() : null;
856
- const queryEnv = this.buildQueryEnv(meta.projectPath, retryAccount);
857
- const retryOptions = {
858
- ...(process.platform === "win32" && { executable: "node" }),
859
- cwd: effectiveCwd,
860
- systemPrompt: systemPromptOpt,
861
- settingSources: ["user", "project"],
862
- env: queryEnv,
863
- settings: { permissions: { allow: [], deny: [] } },
864
- allowedTools,
865
- permissionMode,
866
- allowDangerouslySkipPermissions: isBypass,
867
- ...(providerConfig.model && { model: providerConfig.model }),
868
- maxTurns: providerConfig.max_turns ?? 100,
869
- includePartialMessages: true,
870
- };
871
- const retryQuery = query({
872
- prompt: message,
873
- options: {
874
- ...retryOptions,
875
- ...(permissionHooks && { hooks: permissionHooks }),
876
- canUseTool,
877
- } as any,
878
- });
879
- this.activeQueries.set(sessionId, retryQuery);
880
- for await (const retryMsg of retryQuery) {
881
- if (retryMsg.type === "system") continue;
882
- if (retryMsg.type === "result") {
883
- const r = retryMsg as any;
884
- if (r.subtype && r.subtype !== "success") {
885
- const retryErrors = Array.isArray(r.errors) ? r.errors.join("\n") : "";
886
- yield { type: "error", message: retryErrors || `Agent stopped: ${r.subtype}` };
887
- }
888
- resultSubtype = r.subtype;
889
- resultNumTurns = r.num_turns;
890
- break;
891
- }
892
- if ((retryMsg as any).type === "assistant") {
893
- const content = (retryMsg as any).message?.content;
894
- if (Array.isArray(content)) {
895
- for (const block of content) {
896
- if (block.type === "text" && typeof block.text === "string") {
897
- yield { type: "text", content: block.text };
898
- }
899
- }
900
- }
901
- }
902
- }
903
- } catch (retryErr) {
904
- const retryMsg = (retryErr as Error).message ?? String(retryErr);
905
- console.error(`[sdk] retry also failed: ${retryMsg}`);
906
- yield { type: "error", message: `SDK error: ${msg}` };
907
- }
1026
+ } else if (msg.includes("exited with code")) {
1027
+ // Subprocess crashed session will auto-recover on next message
1028
+ console.warn(`[sdk] session=${sessionId} subprocess crashed: ${msg}`);
1029
+ yield { type: "error", message: `SDK subprocess crashed. Send another message to auto-recover.` };
908
1030
  } else {
909
1031
  yield { type: "error", message: `SDK error: ${msg}` };
910
1032
  }
911
1033
  } finally {
912
1034
  this.activeQueries.delete(sessionId);
1035
+ this.streamingSessions.delete(sessionId);
1036
+ console.log(`[sdk] session=${sessionId} streaming session ended`);
913
1037
  }
914
1038
 
915
- yield {
916
- type: "done",
917
- sessionId,
918
- resultSubtype: resultSubtype as any,
919
- numTurns: resultNumTurns,
920
- contextWindowPct: resultContextWindowPct,
921
- };
1039
+ // Final done event when query ends (crash, close, generator done)
1040
+ // Skip if we already yielded done from the result handler (avoid duplicate)
1041
+ if (!yieldedDone) {
1042
+ yield {
1043
+ type: "done",
1044
+ sessionId,
1045
+ resultSubtype: resultSubtype as any,
1046
+ numTurns: resultNumTurns,
1047
+ contextWindowPct: resultContextWindowPct,
1048
+ };
1049
+ }
922
1050
  }
923
1051
 
924
1052
 
925
- /** Abort an active query for a session */
1053
+ /** Interrupt the current turn — session stays alive for the next message */
926
1054
  abortQuery(sessionId: string): void {
1055
+ const ss = this.streamingSessions.get(sessionId);
1056
+ if (ss && typeof ss.query.interrupt === "function") {
1057
+ ss.query.interrupt().catch(() => {});
1058
+ console.log(`[sdk] abortQuery: interrupted session=${sessionId}`);
1059
+ return;
1060
+ }
1061
+ // Fallback: close query entirely and clean up streaming session
927
1062
  const q = this.activeQueries.get(sessionId);
928
1063
  if (q) {
929
1064
  q.close();
930
1065
  this.activeQueries.delete(sessionId);
1066
+ this.streamingSessions.delete(sessionId);
931
1067
  }
932
1068
  }
933
1069