@hienlh/ppm 0.22.1 → 0.22.2
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 +11 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/{accounts-settings-section-D3BylchP.js → accounts-settings-section-CLEAA_Jc.js} +1 -1
- package/dist/web/assets/{ai-resource-editor-BLPcnhTM.js → ai-resource-editor-C4ecid2g.js} +1 -1
- package/dist/web/assets/ai-settings-section-BOwGdiyH.js +1 -0
- package/dist/web/assets/ai-settings-section-Cqz13gRt.js +1 -0
- package/dist/web/assets/{api-client-C1ZwRL4Y.js → api-client-Jn3njtNw.js} +1 -1
- package/dist/web/assets/api-client-rSFnnCj4.js +1 -0
- package/dist/web/assets/{api-settings-_7Q-ULxp.js → api-settings-BxijvPBR.js} +1 -1
- package/dist/web/assets/{api-themes-DRAERo4Q.js → api-themes-CSUarkzD.js} +1 -1
- package/dist/web/assets/{appearance-settings-section-CiMdk3sb.js → appearance-settings-section-DbA8L-Vz.js} +1 -1
- package/dist/web/assets/{audio-preview-DsYvgKqj.js → audio-preview-CxJd8wRV.js} +1 -1
- package/dist/web/assets/{branch-review-tab-B1pFjlKM.js → branch-review-tab-CMTa2uSR.js} +1 -1
- package/dist/web/assets/chat-tab-BpdgqjSL.js +15 -0
- package/dist/web/assets/{code-editor-BJhOEsnZ.js → code-editor-B7y7-5KE.js} +3 -3
- package/dist/web/assets/{codex-daily-guard-CaCQJ4r_.js → codex-daily-guard-ChDPiXDx.js} +1 -1
- package/dist/web/assets/{conflict-editor-B7u_p49h.js → conflict-editor-Axs9Ad7A.js} +1 -1
- package/dist/web/assets/{csv-preview-CttjJU1e.js → csv-preview-DTUAW2HW.js} +1 -1
- package/dist/web/assets/{database-viewer-Ca4HxIfx.js → database-viewer-qXDiWeXj.js} +1 -1
- package/dist/web/assets/{diff-viewer-9-XjLIwa.js → diff-viewer-BtLiSpqe.js} +1 -1
- package/dist/web/assets/{docx-preview-CXuk-emm.js → docx-preview-Dxvy6h13.js} +1 -1
- package/dist/web/assets/{editor-language-service-D0DuEOs_.js → editor-language-service-D75GuLXP.js} +1 -1
- package/dist/web/assets/{explorer-body-VdCBqcZu.js → explorer-body-xg1-MhlW.js} +1 -1
- package/dist/web/assets/{explorer-window-content-BIsbl7Th.js → explorer-window-content-BeQocW3i.js} +1 -1
- package/dist/web/assets/{extension-manager-section-HkY7geS5.js → extension-manager-section-Bm2v3P-n.js} +1 -1
- package/dist/web/assets/{extension-webview-DZG8YHX9.js → extension-webview-CzxrAHyL.js} +1 -1
- package/dist/web/assets/{file-icons-BXdvggK2.js → file-icons-wS-OmEVu.js} +1 -1
- package/dist/web/assets/{file-store-ojgMXgAw.js → file-store-Ds3qJ4hC.js} +1 -1
- package/dist/web/assets/{files-settings-section-qnRtkX05.js → files-settings-section-Bd-_GeZU.js} +1 -1
- package/dist/web/assets/{format-file-meta-C77h04cZ.js → format-file-meta-PPi3ptkm.js} +1 -1
- package/dist/web/assets/{general-settings-section-BAFSZmCE.js → general-settings-section-CfNPHQUk.js} +1 -1
- package/dist/web/assets/{git-log-panel-2sGpfEla.js → git-log-panel-CtGxPzH6.js} +1 -1
- package/dist/web/assets/{git-repo-store-88Z8v-pF.js → git-repo-store-BCEPfUGT.js} +1 -1
- package/dist/web/assets/{glide-data-grid-f0hyITiF.js → glide-data-grid-iSo2vP0q.js} +1 -1
- package/dist/web/assets/{group-chat-tab-Ck6sk7yY.js → group-chat-tab-D1lx0zz-.js} +1 -1
- package/dist/web/assets/{image-preview-CzCc4_Do.js → image-preview-DeGD0HJu.js} +1 -1
- package/dist/web/assets/{index-CEZVxM4G.js → index-CN0G8uYY.js} +5 -5
- package/dist/web/assets/{jira-watcher-section-CeLmhvu1.js → jira-watcher-section-kyifZPTv.js} +1 -1
- package/dist/web/assets/keybindings-store-L5vV8DEJ.js +1 -0
- package/dist/web/assets/{keyboard-shortcuts-section-PVz6kuh2.js → keyboard-shortcuts-section-D2uJq4x9.js} +1 -1
- package/dist/web/assets/{markdown-renderer-C140Ijk0.js → markdown-renderer-BX1Q00sC.js} +1 -1
- package/dist/web/assets/markdown-renderer-CLUux0vA.js +1 -0
- package/dist/web/assets/{media-url-yfqHpPz0.js → media-url-DKK0YHxL.js} +1 -1
- package/dist/web/assets/{mobile-explorer-sheet-CUG_owdf.js → mobile-explorer-sheet-BHQDzpwK.js} +1 -1
- package/dist/web/assets/notification-store-BHgSy-ci.js +1 -0
- package/dist/web/assets/panel-store-D20Zuf3i.js +1 -0
- package/dist/web/assets/{pdf-preview-CmBI6E7d.js → pdf-preview-DAcfhfGm.js} +1 -1
- package/dist/web/assets/{postgres-viewer-8ZAqEALv.js → postgres-viewer-DPRsmgP5.js} +1 -1
- package/dist/web/assets/{ppmbot-settings-section-Cji-Mil-.js → ppmbot-settings-section-B5N1jHgm.js} +1 -1
- package/dist/web/assets/{problems-panel-a6_hrWvl.js → problems-panel-D_wZ4_Qg.js} +1 -1
- package/dist/web/assets/{process-table-CiIqlOIK.js → process-table-DahflyQn.js} +1 -1
- package/dist/web/assets/{project-framework-store-B70Q3dNM.js → project-framework-store-ViZgce6y.js} +1 -1
- package/dist/web/assets/{project-store-B87hLRSk.js → project-store-hNvwfqX3.js} +1 -1
- package/dist/web/assets/{proxy-settings-section-BjI4IFgp.js → proxy-settings-section-CLg_nlxn.js} +1 -1
- package/dist/web/assets/{query-audit-section-By6qyqdB.js → query-audit-section-BrfSo0s_.js} +1 -1
- package/dist/web/assets/{remote-desktop-clipboard-notice-eXYvwgx7.js → remote-desktop-clipboard-notice-Fi6cieGM.js} +1 -1
- package/dist/web/assets/{remote-desktop-mobile-sheet-Doh-fci-.js → remote-desktop-mobile-sheet-lLZ-oK73.js} +2 -2
- package/dist/web/assets/{remote-desktop-mobile-view-Dt8Akc3p.js → remote-desktop-mobile-view-j3v-4rYa.js} +1 -1
- package/dist/web/assets/{remote-desktop-readiness-gate-t83fqbID.js → remote-desktop-readiness-gate-CeLvcX_w.js} +1 -1
- package/dist/web/assets/{remote-desktop-window-content-CguhZMmx.js → remote-desktop-window-content-lwbkLsTC.js} +1 -1
- package/dist/web/assets/{run-in-terminal-CdefEe_R.js → run-in-terminal-D7W4IKb9.js} +1 -1
- package/dist/web/assets/{schedules-settings-section-BVkpW5ms.js → schedules-settings-section-C8OS0o80.js} +1 -1
- package/dist/web/assets/{send-to-chat-F207yH3u.js → send-to-chat-DNKhmHbi.js} +1 -1
- package/dist/web/assets/{settings-body-CoIxYAh6.js → settings-body-DgN22Z0W.js} +2 -2
- package/dist/web/assets/{settings-store-krC6bc79.js → settings-store-CsVSVgLp.js} +2 -2
- package/dist/web/assets/{settings-tab-7DKVUTbM.js → settings-tab-ChOs94iB.js} +1 -1
- package/dist/web/assets/{settings-window-content-3_39TeX-.js → settings-window-content-BnKMmg2a.js} +1 -1
- package/dist/web/assets/{sql-query-editor-CQB7Yp7U.js → sql-query-editor-BJZIIQsm.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-Bd7rjr1D.js → sqlite-viewer--cMeCZum.js} +1 -1
- package/dist/web/assets/{system-monitor-body-DsRXeMyU.js → system-monitor-body-CXiIrn0N.js} +2 -2
- package/dist/web/assets/system-monitor-tab-BJKrTSl0.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-ClPo4-El.js → system-monitor-window-content-Dy9fZJE3.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-d2TAD4PU.js → tab-host-window-content-BezqrAwC.js} +1 -1
- package/dist/web/assets/{tab-store-OJa1GPCq.js → tab-store-krAuHQ6_.js} +1 -1
- package/dist/web/assets/{team-member-sheet-7d2Qp-ie.js → team-member-sheet-CVM2QC3H.js} +2 -2
- package/dist/web/assets/{team-member-window-content-Bctg2gmg.js → team-member-window-content-D4RYKplm.js} +1 -1
- package/dist/web/assets/{terminal-tab-0HQic25V.js → terminal-tab-jikhQLct.js} +1 -1
- package/dist/web/assets/{tool-cards-CmLLRACd.js → tool-cards-D5jCQvqn.js} +2 -2
- package/dist/web/assets/{use-blob-url-CPtCcY3i.js → use-blob-url-DMGlPCQD.js} +1 -1
- package/dist/web/assets/{use-inline-blame-sDMjcz1-.js → use-inline-blame-BF8Y1KfV.js} +1 -1
- package/dist/web/assets/{use-lsp-CBgID-EU.js → use-lsp-Bx4oVtlk.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-gvhJ_jZh.js → use-monaco-theme-DHczXLMb.js} +1 -1
- package/dist/web/assets/{use-websocket-C9wlRliB.js → use-websocket-BWZkbleJ.js} +1 -1
- package/dist/web/assets/{video-preview-CSDK5j6H.js → video-preview-D191TvX9.js} +1 -1
- package/dist/web/assets/{window-pip-registry-yD6esSju.js → window-pip-registry-D1oXq-Dq.js} +1 -1
- package/dist/web/assets/ws-auth-BG-cdrQ8.js +1 -0
- package/dist/web/index.html +13 -13
- package/dist/web/sw.js +1 -1
- package/docs/architecture/workspace-and-ui.md +13 -0
- package/package.json +1 -1
- package/src/cli/commands/init.ts +1 -0
- package/src/providers/codex-app-server/codex-history.ts +26 -7
- package/src/providers/codex-app-server/codex-provider.ts +6 -4
- package/src/server/routes/chat.ts +1 -1
- package/src/server/routes/settings.ts +11 -5
- package/src/services/config.service.ts +2 -0
- package/src/types/chat.ts +1 -1
- package/src/types/config.ts +12 -1
- package/src/web/components/chat/chat-tab.tsx +162 -38
- package/src/web/components/chat/message-input.tsx +24 -0
- package/src/web/components/chat/model-thinking-selector.tsx +25 -5
- package/src/web/components/chat/new-chat-provider-gate.tsx +68 -0
- package/src/web/components/layout/editor-panel.tsx +1 -1
- package/src/web/components/layout/reparenting-tab.tsx +4 -2
- package/src/web/components/layout/tab-bar.tsx +1 -1
- package/src/web/components/settings/ai-settings-section.tsx +36 -0
- package/src/web/hooks/use-draft.ts +25 -4
- package/src/web/hooks/use-usage.ts +6 -4
- package/src/web/lib/api-client.ts +7 -1
- package/src/web/lib/api-settings.ts +1 -0
- package/src/web/lib/new-chat-provider.ts +8 -0
- package/src/web/stores/panel-store.ts +46 -3
- package/dist/web/assets/ai-settings-section-BtR7rF-T.js +0 -1
- package/dist/web/assets/ai-settings-section-r9JctHNM.js +0 -1
- package/dist/web/assets/api-client-pQL53cDQ.js +0 -1
- package/dist/web/assets/chat-tab-DZagX06m.js +0 -15
- package/dist/web/assets/keybindings-store-C_3ChOEf.js +0 -1
- package/dist/web/assets/markdown-renderer-Dz7-DYUg.js +0 -1
- package/dist/web/assets/notification-store-6vib1ISy.js +0 -1
- package/dist/web/assets/panel-store-CboGJAwh.js +0 -1
- package/dist/web/assets/system-monitor-tab-DdSZgux3.js +0 -1
- package/dist/web/assets/ws-auth-CEYVQ8NH.js +0 -1
package/dist/web/index.html
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600;700&family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
12
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
+
<script type="module" crossorigin src="/assets/index-CN0G8uYY.js"></script>
|
|
13
13
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-FhOqtrmT.js">
|
|
14
14
|
<link rel="modulepreload" crossorigin href="/assets/vendor-mermaid-BitiXJlL.js">
|
|
15
15
|
<link rel="modulepreload" crossorigin href="/assets/vendor-markdown-CuWCHIVb.js">
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
<link rel="modulepreload" crossorigin href="/assets/utils-Bmf_8h7Y.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="/assets/button-B9CTrsEf.js">
|
|
19
19
|
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-DoiEKeJ_.js">
|
|
20
|
-
<link rel="modulepreload" crossorigin href="/assets/api-client-
|
|
20
|
+
<link rel="modulepreload" crossorigin href="/assets/api-client-Jn3njtNw.js">
|
|
21
21
|
<link rel="modulepreload" crossorigin href="/assets/react-Bghu0NUO.js">
|
|
22
|
-
<link rel="modulepreload" crossorigin href="/assets/settings-store-
|
|
23
|
-
<link rel="modulepreload" crossorigin href="/assets/file-store-
|
|
22
|
+
<link rel="modulepreload" crossorigin href="/assets/settings-store-CsVSVgLp.js">
|
|
23
|
+
<link rel="modulepreload" crossorigin href="/assets/file-store-Ds3qJ4hC.js">
|
|
24
24
|
<link rel="modulepreload" crossorigin href="/assets/window-store-UC1jJeLM.js">
|
|
25
|
-
<link rel="modulepreload" crossorigin href="/assets/panel-store-
|
|
26
|
-
<link rel="modulepreload" crossorigin href="/assets/window-pip-registry-
|
|
27
|
-
<link rel="modulepreload" crossorigin href="/assets/format-file-meta-
|
|
25
|
+
<link rel="modulepreload" crossorigin href="/assets/panel-store-D20Zuf3i.js">
|
|
26
|
+
<link rel="modulepreload" crossorigin href="/assets/window-pip-registry-D1oXq-Dq.js">
|
|
27
|
+
<link rel="modulepreload" crossorigin href="/assets/format-file-meta-PPi3ptkm.js">
|
|
28
28
|
<link rel="modulepreload" crossorigin href="/assets/portal-container-context-BarKmT4S.js">
|
|
29
29
|
<link rel="modulepreload" crossorigin href="/assets/icons-DQjqk0lJ.js">
|
|
30
30
|
<link rel="modulepreload" crossorigin href="/assets/context-menu-C6pIsf83.js">
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
<link rel="modulepreload" crossorigin href="/assets/mobile-bottom-sheet-C3TniEP-.js">
|
|
35
35
|
<link rel="modulepreload" crossorigin href="/assets/scroll-area-BzeiOd-B.js">
|
|
36
36
|
<link rel="modulepreload" crossorigin href="/assets/use-is-mobile-TkcwP1Gx.js">
|
|
37
|
-
<link rel="modulepreload" crossorigin href="/assets/project-framework-store-
|
|
38
|
-
<link rel="modulepreload" crossorigin href="/assets/file-icons-
|
|
39
|
-
<link rel="modulepreload" crossorigin href="/assets/git-repo-store-
|
|
40
|
-
<link rel="modulepreload" crossorigin href="/assets/project-store-
|
|
41
|
-
<link rel="modulepreload" crossorigin href="/assets/ws-auth-
|
|
37
|
+
<link rel="modulepreload" crossorigin href="/assets/project-framework-store-ViZgce6y.js">
|
|
38
|
+
<link rel="modulepreload" crossorigin href="/assets/file-icons-wS-OmEVu.js">
|
|
39
|
+
<link rel="modulepreload" crossorigin href="/assets/git-repo-store-BCEPfUGT.js">
|
|
40
|
+
<link rel="modulepreload" crossorigin href="/assets/project-store-hNvwfqX3.js">
|
|
41
|
+
<link rel="modulepreload" crossorigin href="/assets/ws-auth-BG-cdrQ8.js">
|
|
42
42
|
<link rel="modulepreload" crossorigin href="/assets/streaming-store-BYukdB56.js">
|
|
43
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-store-
|
|
43
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-store-krAuHQ6_.js">
|
|
44
44
|
<link rel="modulepreload" crossorigin href="/assets/apply-theme-CbR31K6I.js">
|
|
45
45
|
<link rel="modulepreload" crossorigin href="/assets/resolve-theme-B_ukrg_8.js">
|
|
46
46
|
<link rel="stylesheet" crossorigin href="/assets/index-BH99TIE0.css">
|
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))}var B=`-precache-`,V=async(e,t=B)=>{let n=(await self.caches.keys()).filter(n=>n.includes(t)&&n.includes(self.registration.scope)&&n!==e);return await Promise.all(n.map(e=>self.caches.delete(e))),n};function H(){self.addEventListener(`activate`,(e=>{let t=a.getPrecacheName();e.waitUntil(V(t).then(e=>{}))}))}function U(e){O().precache(e)}function W(e,t){U(e),z(t)}var G=class extends w{async _handle(e,n){let r=await n.cacheMatch(e),i;if(!r)try{r=await n.fetchAndCachePut(e)}catch(e){e instanceof Error&&(i=e)}if(!r)throw new t(`no-response`,{url:e.url,error:i});return r}};W([{"revision":"e7df0dd1bfe9b16560e99adb2afd00f8","url":"index.html"},{"revision":"26dccd02a2ef7522892015154f5e3680","url":"manifest.webmanifest"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":null,"url":"assets/index-CEZVxM4G.js"},{"revision":null,"url":"assets/index-BH99TIE0.css"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"26dccd02a2ef7522892015154f5e3680","url":"manifest.webmanifest"}]),H();var K=e=>(e.headers.get(`content-type`)??``).startsWith(`text/html`);F(({url:e})=>e.pathname.startsWith(`/assets/`),new G({cacheName:`ppm-assets`,plugins:[{cacheWillUpdate:async({response:e})=>K(e)?null:e,cachedResponseWillBeUsed:async({cachedResponse:e})=>e&&K(e)?null:e}]})),self.skipWaiting(),self.addEventListener(`activate`,()=>{self.clients.claim()});
|
|
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))}var B=`-precache-`,V=async(e,t=B)=>{let n=(await self.caches.keys()).filter(n=>n.includes(t)&&n.includes(self.registration.scope)&&n!==e);return await Promise.all(n.map(e=>self.caches.delete(e))),n};function H(){self.addEventListener(`activate`,(e=>{let t=a.getPrecacheName();e.waitUntil(V(t).then(e=>{}))}))}function U(e){O().precache(e)}function W(e,t){U(e),z(t)}var G=class extends w{async _handle(e,n){let r=await n.cacheMatch(e),i;if(!r)try{r=await n.fetchAndCachePut(e)}catch(e){e instanceof Error&&(i=e)}if(!r)throw new t(`no-response`,{url:e.url,error:i});return r}};W([{"revision":"206312c0035b4551edbf7f8f5cf4d80f","url":"index.html"},{"revision":"26dccd02a2ef7522892015154f5e3680","url":"manifest.webmanifest"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":null,"url":"assets/index-CN0G8uYY.js"},{"revision":null,"url":"assets/index-BH99TIE0.css"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"26dccd02a2ef7522892015154f5e3680","url":"manifest.webmanifest"}]),H();var K=e=>(e.headers.get(`content-type`)??``).startsWith(`text/html`);F(({url:e})=>e.pathname.startsWith(`/assets/`),new G({cacheName:`ppm-assets`,plugins:[{cacheWillUpdate:async({response:e})=>K(e)?null:e,cachedResponseWillBeUsed:async({cachedResponse:e})=>e&&K(e)?null:e}]})),self.skipWaiting(),self.addEventListener(`activate`,()=>{self.clients.claim()});
|
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
> Part of the [PPM system architecture](../system-architecture.md).
|
|
4
4
|
|
|
5
|
+
## New Chat Provider
|
|
6
|
+
|
|
7
|
+
Settings → AI offers `Always use default provider` and `Follow last focused chat`.
|
|
8
|
+
`ai.default_provider` is the fixed choice or the fallback when the current project has
|
|
9
|
+
no focused chat. Fresh installations use follow-focus; existing configurations without
|
|
10
|
+
`ai.new_chat_provider_mode` retain default mode.
|
|
11
|
+
|
|
12
|
+
Focus memory is per project and browser session, across panels. Editors, terminals and
|
|
13
|
+
panel chrome do not replace it. New tabs snapshot the source at creation and resolve
|
|
14
|
+
settings before mounting chat or claiming an account. An unavailable provider prompts
|
|
15
|
+
for an available choice. Existing tabs, resumed sessions and explicit fork/clear
|
|
16
|
+
providers are preserved; changing the setting only affects new tabs.
|
|
17
|
+
|
|
5
18
|
## File Service & Filtering (Lazy-Load Tree, Palette Index)
|
|
6
19
|
|
|
7
20
|
**Component:** FileFilterService + API endpoints `/files/list`, `/files/index`, settings endpoints
|
package/package.json
CHANGED
package/src/cli/commands/init.ts
CHANGED
|
@@ -155,6 +155,7 @@ export async function initProject(options: InitOptions = {}) {
|
|
|
155
155
|
configService.set("auth", { enabled: authEnabled, token: authToken });
|
|
156
156
|
configService.set("ai", {
|
|
157
157
|
default_provider: "claude",
|
|
158
|
+
new_chat_provider_mode: configService.get("ai").new_chat_provider_mode,
|
|
158
159
|
providers: {
|
|
159
160
|
claude: {
|
|
160
161
|
type: "agent-sdk",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ChatMessage, ChatEvent, SessionInfo } from "../provider.interface.ts";
|
|
2
2
|
import { stripSharedContext } from "../../shared/provider-context.ts";
|
|
3
|
-
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { readdirSync, readFileSync, statSync, realpathSync } from "node:fs";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
|
+
import { getPpmDir } from "../../services/ppm-dir.ts";
|
|
6
7
|
import { redactTruncate } from "./codex-redact.ts";
|
|
7
8
|
import { parseApplyPatch, changeToToolUse } from "./codex-patch.ts";
|
|
8
9
|
import { mapRolloutItem } from "./codex-rollout-items.ts";
|
|
@@ -449,14 +450,27 @@ export function getRolloutMessages(sessionsDir: string, threadId: string, reques
|
|
|
449
450
|
|
|
450
451
|
/** True when a path points at a codex rollout in the ambient or a PPM account home. */
|
|
451
452
|
export function isCodexRolloutPath(p: string): boolean {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
453
|
+
return withinCodexSessions(p, false);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function withinCodexSessions(p: string, canonical: boolean): boolean {
|
|
457
|
+
const normalize = (value: string) => process.platform === "win32" ? normPath(value).replace(/\\/g, "/") : normPath(value);
|
|
458
|
+
const n = normalize(p);
|
|
459
|
+
if (!n.endsWith(".jsonl")) return false;
|
|
460
|
+
const rootPath = (value: string) => {
|
|
461
|
+
if (canonical) { try { return normalize(realpathSync(value)); } catch { return null; } }
|
|
462
|
+
return normalize(value);
|
|
463
|
+
};
|
|
464
|
+
const ambientRoots = [join(homedir(), ".codex", "sessions")];
|
|
465
|
+
if (process.env.CODEX_HOME) ambientRoots.push(join(process.env.CODEX_HOME, "sessions"));
|
|
466
|
+
if (ambientRoots.some((value) => { const root = rootPath(value); return root && n.startsWith(root + "/"); })) return true;
|
|
467
|
+
const managed = rootPath(join(getPpmDir(), "codex-accounts"));
|
|
468
|
+
return !!managed && n.startsWith(managed + "/") && /^[^/]+\/sessions\/.+/.test(n.slice(managed.length + 1));
|
|
456
469
|
}
|
|
457
470
|
|
|
458
471
|
/**
|
|
459
|
-
* One pre-compact segment for the "load more" feature. Jails to
|
|
472
|
+
* One pre-compact segment for the "load more" feature. Jails to ambient,
|
|
473
|
+
* CODEX_HOME, or PPM managed-account session directories via real paths;
|
|
460
474
|
* fail-closed on cwd.
|
|
461
475
|
*
|
|
462
476
|
* One segment per request rather than everything before the first boundary, which is
|
|
@@ -468,7 +482,12 @@ export function isCodexRolloutPath(p: string): boolean {
|
|
|
468
482
|
*/
|
|
469
483
|
export function getCodexPreCompactMessages(file: string, requestedCwd?: string, beforeId?: string): ChatMessage[] {
|
|
470
484
|
if (!isCodexRolloutPath(file)) throw new Error("Access denied: not a codex rollout");
|
|
471
|
-
|
|
485
|
+
let resolved: string;
|
|
486
|
+
try { resolved = realpathSync(resolve(file)); } catch { throw new Error("File not found"); }
|
|
487
|
+
if (!withinCodexSessions(resolved, true)) throw new Error("Access denied: transcript outside Codex sessions");
|
|
488
|
+
const info = statSync(resolved);
|
|
489
|
+
if (!info.isFile()) throw new Error("Not a regular file");
|
|
490
|
+
if (info.size > 256 * 1024 * 1024) throw new Error("Transcript too large");
|
|
472
491
|
let text: string;
|
|
473
492
|
try { text = readFileSync(resolved, "utf-8"); } catch { throw new Error("File not found"); }
|
|
474
493
|
// Read once and reused below. `readSessionMeta` opens and reads the whole rollout again, and
|
|
@@ -1147,12 +1147,14 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
1147
1147
|
}
|
|
1148
1148
|
|
|
1149
1149
|
/** Read the session's account without advancing the account-selection strategy. */
|
|
1150
|
-
async getUsage(sessionId?: string): Promise<UsageInfo> {
|
|
1150
|
+
async getUsage(sessionId?: string, pickedAccountId?: string): Promise<UsageInfo> {
|
|
1151
1151
|
// Idempotent, and needed because a caller can reach the provider before the
|
|
1152
1152
|
// server has started background polling — an unregistered source would make
|
|
1153
1153
|
// the shared layer answer {} instead of reading codex.
|
|
1154
1154
|
registerUsageSource(codexUsageSource);
|
|
1155
|
-
|
|
1155
|
+
// An unopened chat has a claimed account but no session binding yet.
|
|
1156
|
+
// Read that exact account without advancing the selection strategy.
|
|
1157
|
+
const accountId = sessionId ? getSessionCodexAccount(sessionId) : pickedAccountId ?? null;
|
|
1156
1158
|
const bound = accountId ? getCodexAccount(accountId) : null;
|
|
1157
1159
|
if (bound) {
|
|
1158
1160
|
// Through the shared layer, so this answers from the cache or the stored
|
|
@@ -1166,12 +1168,12 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
1166
1168
|
};
|
|
1167
1169
|
}
|
|
1168
1170
|
|
|
1169
|
-
//
|
|
1171
|
+
// No binding or explicit tab claim — a session binds on its first send. Name the account
|
|
1170
1172
|
// that will serve it, but do NOT read its quota: that spawns an app-server
|
|
1171
1173
|
// against a login which is not yet this session's, and which a round-robin
|
|
1172
1174
|
// or lowest-usage pick may never hand it. So the toolbar can say WHO will
|
|
1173
1175
|
// answer without PPM touching that account on a session's behalf before
|
|
1174
|
-
// the session owns it.
|
|
1176
|
+
// the session owns it. Quota is read once a tab claims it or a session binds it.
|
|
1175
1177
|
//
|
|
1176
1178
|
// Skipped when the session names an account that no longer exists: naming
|
|
1177
1179
|
// a different one there would be a lie about a binding that already failed.
|
|
@@ -135,7 +135,7 @@ chatRoutes.get("/usage", async (c) => {
|
|
|
135
135
|
const { invalidateUsage } = await import("../../services/provider-usage/usage-registry.ts");
|
|
136
136
|
invalidateUsage(providerId);
|
|
137
137
|
}
|
|
138
|
-
try { return c.json(ok(await provider.getUsage(c.req.query("session")))); } catch { return c.json(ok({})); }
|
|
138
|
+
try { return c.json(ok(await provider.getUsage(c.req.query("session"), c.req.query("accountId")))); } catch { return c.json(ok({})); }
|
|
139
139
|
}
|
|
140
140
|
return c.json(ok({}));
|
|
141
141
|
}
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
validateAIProviderConfig,
|
|
6
6
|
validateCodexContextConfig,
|
|
7
7
|
validateDefaultProvider,
|
|
8
|
-
VALID_PROVIDERS,
|
|
9
8
|
DEFAULT_CONFIG,
|
|
10
9
|
type AIProviderConfig,
|
|
10
|
+
type NewChatProviderMode,
|
|
11
11
|
type TelegramConfig,
|
|
12
12
|
type PPMBotConfig,
|
|
13
13
|
type ThemeConfig,
|
|
@@ -184,12 +184,20 @@ settingsRoutes.put("/ai", async (c) => {
|
|
|
184
184
|
try {
|
|
185
185
|
const body = await c.req.json<{
|
|
186
186
|
default_provider?: string;
|
|
187
|
+
new_chat_provider_mode?: NewChatProviderMode;
|
|
187
188
|
share_provider_context?: boolean;
|
|
188
189
|
providers?: Record<string, Partial<AIProviderConfig>>;
|
|
189
190
|
}>();
|
|
190
191
|
|
|
191
192
|
const currentAi = configService.get("ai");
|
|
192
193
|
|
|
194
|
+
if ("new_chat_provider_mode" in body && body.new_chat_provider_mode !== "default" && body.new_chat_provider_mode !== "follow-focus") {
|
|
195
|
+
return c.json(err("new_chat_provider_mode must be one of: default, follow-focus"), 400);
|
|
196
|
+
}
|
|
197
|
+
if ("default_provider" in body && (typeof body.default_provider !== "string" || !body.default_provider)) {
|
|
198
|
+
return c.json(err("default_provider must be a non-empty string"), 400);
|
|
199
|
+
}
|
|
200
|
+
|
|
193
201
|
if ("share_provider_context" in body && typeof body.share_provider_context !== "boolean") {
|
|
194
202
|
return c.json(err("share_provider_context must be a boolean"), 400);
|
|
195
203
|
}
|
|
@@ -207,6 +215,7 @@ settingsRoutes.put("/ai", async (c) => {
|
|
|
207
215
|
// Merge: body overrides current values (shallow merge per provider)
|
|
208
216
|
const updated = {
|
|
209
217
|
...currentAi,
|
|
218
|
+
new_chat_provider_mode: body.new_chat_provider_mode ?? currentAi.new_chat_provider_mode ?? "default",
|
|
210
219
|
share_provider_context: body.share_provider_context ?? currentAi.share_provider_context ?? true,
|
|
211
220
|
...(body.default_provider && { default_provider: body.default_provider }),
|
|
212
221
|
};
|
|
@@ -231,11 +240,8 @@ settingsRoutes.put("/ai", async (c) => {
|
|
|
231
240
|
}
|
|
232
241
|
}
|
|
233
242
|
|
|
234
|
-
//
|
|
243
|
+
// Configured providers include runtime integrations such as Codex.
|
|
235
244
|
if (body.default_provider) {
|
|
236
|
-
if (!VALID_PROVIDERS.includes(body.default_provider as any)) {
|
|
237
|
-
return c.json(err(`default_provider must be one of: ${VALID_PROVIDERS.join(", ")}`), 400);
|
|
238
|
-
}
|
|
239
245
|
const dpErr = validateDefaultProvider(updated.default_provider, updated.providers);
|
|
240
246
|
if (dpErr) return c.json(err(dpErr), 400);
|
|
241
247
|
}
|
|
@@ -167,6 +167,8 @@ class ConfigService {
|
|
|
167
167
|
dbProjects: { path: string; name: string; color: string | null }[],
|
|
168
168
|
): PpmConfig {
|
|
169
169
|
const config = structuredClone(DEFAULT_CONFIG);
|
|
170
|
+
// Existing installs without an AI row must also retain the old tab behavior.
|
|
171
|
+
config.ai.new_chat_provider_mode = "default";
|
|
170
172
|
for (const [key, jsonValue] of Object.entries(dbRows)) {
|
|
171
173
|
if (key in config && key !== "projects") {
|
|
172
174
|
try {
|
package/src/types/chat.ts
CHANGED
|
@@ -70,7 +70,7 @@ export interface AIProvider {
|
|
|
70
70
|
/** Drop runtime skill discovery results after a user requests a refresh. */
|
|
71
71
|
invalidateSkillsCache?(): void;
|
|
72
72
|
/** Provider-specific usage/quota (rate limits). Used by GET /chat/usage. */
|
|
73
|
-
getUsage?(sessionId?: string): Promise<UsageInfo>;
|
|
73
|
+
getUsage?(sessionId?: string, pickedAccountId?: string): Promise<UsageInfo>;
|
|
74
74
|
/** True when a live streaming subprocess exists for this session */
|
|
75
75
|
hasStreamingSession?(sessionId: string): boolean;
|
|
76
76
|
/** Prompt-cache lifetime for this session, in ms — how long holding its subprocess pays. */
|
package/src/types/config.ts
CHANGED
|
@@ -74,8 +74,12 @@ export interface ProjectConfig {
|
|
|
74
74
|
image?: string;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
export type NewChatProviderMode = "default" | "follow-focus";
|
|
78
|
+
|
|
77
79
|
export interface AIConfig {
|
|
78
80
|
default_provider: string;
|
|
81
|
+
/** Missing in legacy settings: use the configured default provider. */
|
|
82
|
+
new_chat_provider_mode?: NewChatProviderMode;
|
|
79
83
|
/** Share project rules and memory between providers. Unset defaults to true. */
|
|
80
84
|
share_provider_context?: boolean;
|
|
81
85
|
providers: Record<string, AIProviderConfig>;
|
|
@@ -140,6 +144,7 @@ export const DEFAULT_CONFIG: PpmConfig = {
|
|
|
140
144
|
projects: [],
|
|
141
145
|
ai: {
|
|
142
146
|
default_provider: "claude",
|
|
147
|
+
new_chat_provider_mode: "follow-focus",
|
|
143
148
|
share_provider_context: true,
|
|
144
149
|
providers: {
|
|
145
150
|
claude: {
|
|
@@ -280,7 +285,7 @@ export function validateCodexContextConfig(config: Partial<AIProviderConfig>): s
|
|
|
280
285
|
|
|
281
286
|
/** Validate default_provider references an existing provider key */
|
|
282
287
|
export function validateDefaultProvider(defaultProvider: string, providers: Record<string, unknown>): string | null {
|
|
283
|
-
if (!providers
|
|
288
|
+
if (!Object.hasOwn(providers, defaultProvider)) {
|
|
284
289
|
return `default_provider "${defaultProvider}" not found in providers`;
|
|
285
290
|
}
|
|
286
291
|
return null;
|
|
@@ -293,6 +298,12 @@ export function validateDefaultProvider(defaultProvider: string, providers: Reco
|
|
|
293
298
|
export function sanitizeConfig(config: PpmConfig): boolean {
|
|
294
299
|
let dirty = false;
|
|
295
300
|
|
|
301
|
+
// Preserve legacy behavior on upgrade; only fresh configs opt into following focus.
|
|
302
|
+
if (config.ai.new_chat_provider_mode !== "default" && config.ai.new_chat_provider_mode !== "follow-focus") {
|
|
303
|
+
config.ai.new_chat_provider_mode = "default";
|
|
304
|
+
dirty = true;
|
|
305
|
+
}
|
|
306
|
+
|
|
296
307
|
if (typeof config.ai.share_provider_context !== "boolean") {
|
|
297
308
|
config.ai.share_provider_context = true;
|
|
298
309
|
dirty = true;
|