@hienlh/ppm 0.10.5 → 0.11.1
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 +35 -0
- package/dist/web/assets/ai-settings-section-D2vqiydT.js +1 -0
- package/dist/web/assets/{api-settings-C__hxGX2.js → api-settings-2eTz4SgY.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-BRW4VwMk.js +1 -0
- package/dist/web/assets/chat-tab-DYf6U6UF.js +10 -0
- package/dist/web/assets/code-editor-BPxBeu0S.js +8 -0
- package/dist/web/assets/{conflict-editor-Bxq4QiW1.js → conflict-editor-BCkYHDUy.js} +1 -1
- package/dist/web/assets/{csv-preview-BizIVMyb.js → csv-preview-D37K2LRd.js} +1 -1
- package/dist/web/assets/{database-viewer-CvQc1PZH.js → database-viewer-CCe8qa1Q.js} +2 -2
- package/dist/web/assets/{diff-viewer-x7kjfVYW.js → diff-viewer-DIjzWvaG.js} +1 -1
- package/dist/web/assets/{esm-K1XIK4vc.js → esm-B99v94EE.js} +1 -1
- package/dist/web/assets/{extension-store-3yZYn07W.js → extension-store-CkyOvGbF.js} +1 -1
- package/dist/web/assets/extension-webview-HY8XueLo.js +3 -0
- package/dist/web/assets/gitGraph-HDMCJU4V-Bt68dqWT.js +1 -0
- package/dist/web/assets/index-DpRxWGjM.js +26 -0
- package/dist/web/assets/index-iZHWllzQ.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-ySD5z855.js +1 -0
- package/dist/web/assets/{input-ClhO__YM.js → input-CHRMley8.js} +1 -1
- package/dist/web/assets/{keybindings-store-C9KsBH7z.js → keybindings-store-CpP5_miA.js} +1 -1
- package/dist/web/assets/keybindings-store-qfYScgY0.js +1 -0
- package/dist/web/assets/{markdown-renderer-CKmmrUuy.js → markdown-renderer-BQV0AIm5.js} +3 -3
- package/dist/web/assets/packet-RMMSAZCW-CLxaXgIf.js +1 -0
- package/dist/web/assets/pie-UPGHQEXC-C9wPZfkn.js +1 -0
- package/dist/web/assets/port-forwarding-tab-DPmTpfFX.js +1 -0
- package/dist/web/assets/{postgres-viewer-YkljtDWX.js → postgres-viewer-BUSNt_7x.js} +3 -3
- package/dist/web/assets/{project-store-BYmQ0fDC.js → project-store-CczGNZyf.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-DxEpzVN_.js +1 -0
- package/dist/web/assets/{scroll-area-DW7L4Gnc.js → scroll-area-DwWF9FpN.js} +1 -1
- package/dist/web/assets/settings-store-CuYjM0FF.js +2 -0
- package/dist/web/assets/settings-tab-DHBG5O0C.js +1 -0
- package/dist/web/assets/{sql-query-editor-CM_qEhaX.js → sql-query-editor-CVEi0jLM.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-f6ZJHIzh.js → sqlite-viewer-B7WnFN29.js} +1 -1
- package/dist/web/assets/{tab-store-B3M9hjho.js → tab-store-Jvy1eZGM.js} +1 -1
- package/dist/web/assets/{terminal-tab-CVdfvDSK.js → terminal-tab-1K4ijyNe.js} +1 -1
- package/dist/web/assets/treemap-KZPCXAKY-yelcZZqO.js +1 -0
- package/dist/web/assets/{use-monaco-theme-CvV5vy_F.js → use-monaco-theme-kjiAwvOp.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-CwOSbfhN.js → vendor-mermaid-CylkVm4U.js} +3 -3
- package/dist/web/index.html +16 -16
- package/dist/web/sw.js +1 -1
- package/docs/codebase-summary.md +29 -5
- package/docs/project-changelog.md +31 -1
- package/docs/system-architecture.md +106 -1
- package/package.json +1 -1
- package/packages/ext-git-graph/src/webview-html.ts +8 -7
- package/src/cli/commands/jira-cmd.ts +92 -0
- package/src/cli/commands/jira-watcher-cmd.ts +149 -0
- package/src/index.ts +3 -0
- package/src/server/index.ts +19 -0
- package/src/server/routes/files.ts +15 -0
- package/src/server/routes/fs-browse.ts +40 -1
- package/src/server/routes/jira-config-routes.ts +74 -0
- package/src/server/routes/jira-watcher-routes.ts +316 -0
- package/src/server/routes/jira.ts +7 -0
- package/src/server/ws/chat.ts +21 -0
- package/src/services/db.service.ts +65 -1
- package/src/services/file.service.ts +42 -0
- package/src/services/jira-api-client.ts +216 -0
- package/src/services/jira-config.service.ts +83 -0
- package/src/services/jira-debug-session.service.ts +240 -0
- package/src/services/jira-watcher-db.service.ts +195 -0
- package/src/services/jira-watcher.service.ts +159 -0
- package/src/services/notification.service.ts +6 -0
- package/src/types/jira.ts +128 -0
- package/src/web/app.tsx +15 -12
- package/src/web/components/chat/chat-tab.tsx +32 -1
- package/src/web/components/chat/message-input.tsx +56 -5
- package/src/web/components/explorer/file-tree.tsx +70 -19
- package/src/web/components/extensions/extension-webview.tsx +24 -10
- package/src/web/components/jira/jira-config-form.tsx +109 -0
- package/src/web/components/jira/jira-debug-prompt-dialog.tsx +58 -0
- package/src/web/components/jira/jira-filter-builder.tsx +197 -0
- package/src/web/components/jira/jira-panel.tsx +201 -0
- package/src/web/components/jira/jira-results-panel.tsx +184 -0
- package/src/web/components/jira/jira-settings-section.tsx +58 -0
- package/src/web/components/jira/jira-status-badge.tsx +18 -0
- package/src/web/components/jira/jira-ticket-card.tsx +144 -0
- package/src/web/components/jira/jira-ticket-detail.tsx +153 -0
- package/src/web/components/jira/jira-watcher-form.tsx +154 -0
- package/src/web/components/jira/jira-watcher-list.tsx +98 -0
- package/src/web/components/layout/mobile-drawer.tsx +18 -5
- package/src/web/components/layout/sidebar.tsx +20 -3
- package/src/web/components/settings/settings-tab.tsx +20 -3
- package/src/web/components/shared/markdown-code-block.tsx +5 -3
- package/src/web/components/ui/file-browser-picker.tsx +88 -1
- package/src/web/hooks/use-chat.ts +6 -0
- package/src/web/lib/ws-client.ts +10 -3
- package/src/web/stores/jira-store.ts +198 -0
- package/src/web/stores/settings-store.ts +17 -2
- package/src/web/styles/globals.css +7 -0
- package/vite.config.ts +5 -66
- package/bun.lock +0 -2062
- package/bunfig.toml +0 -2
- package/dist/web/assets/ai-settings-section-D2rONDPd.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-DmL1WyG-.js +0 -1
- package/dist/web/assets/chat-tab-Dki1pz84.js +0 -10
- package/dist/web/assets/code-editor-D3AAT8nI.js +0 -8
- package/dist/web/assets/extension-webview-BFd0USXC.js +0 -3
- package/dist/web/assets/gitGraph-HDMCJU4V-D8vKfkjC.js +0 -1
- package/dist/web/assets/index-DPnjO2FY.css +0 -2
- package/dist/web/assets/index-DuEUN2Eg.js +0 -26
- package/dist/web/assets/info-3K5VOQVL-VG29MIoT.js +0 -1
- package/dist/web/assets/keybindings-store-BkZjvU9J.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-Bl_WpvPc.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-BVpLpAIy.js +0 -1
- package/dist/web/assets/port-forwarding-tab-BUH9aImG.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-CJGco43I.js +0 -1
- package/dist/web/assets/settings-store-D9CflsKU.js +0 -2
- package/dist/web/assets/settings-tab-DfPjX9uY.js +0 -1
- package/dist/web/assets/square-nsMa3iMk.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-BsOrObtE.js +0 -1
- /package/dist/web/assets/{api-client-Bn-Pi9k5.js → api-client-C3tXCh0r.js} +0 -0
- /package/dist/web/assets/{csv-parser--2WJNgS7.js → csv-parser-BAa56Nnn.js} +0 -0
- /package/dist/web/assets/{dist-im4ynINo.js → dist-On3hz9_g.js} +0 -0
- /package/dist/web/assets/{katex-CKoArbIw.js → katex-Bbu770d9.js} +0 -0
- /package/dist/web/assets/{lib-D_kRA9p6.js → lib-BqkcKGFq.js} +0 -0
- /package/dist/web/assets/{react-GqWghJ-L.js → react-BkWDCPD7.js} +0 -0
- /package/dist/web/assets/{sql-completion-provider-C3cq9j99.js → sql-completion-provider-D3acAhav.js} +0 -0
- /package/dist/web/assets/{table-Dq575bPF.js → table-DbSviOmw.js} +0 -0
- /package/dist/web/assets/{text-wrap-Cn6BNQfq.js → text-wrap-DzvCTq_i.js} +0 -0
- /package/dist/web/assets/{trash-2-CJYoLw7Q.js → trash-2-BgDIBl6f.js} +0 -0
- /package/dist/web/assets/{utils-CTg5uAYR.js → utils-ChWX7pZv.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-ejLe7-tK.js → vendor-xterm-B9BUAFKA.js} +0 -0
package/dist/web/index.html
CHANGED
|
@@ -39,32 +39,32 @@
|
|
|
39
39
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
40
40
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
41
41
|
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600;700&family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
42
|
-
<script type="module" crossorigin src="/assets/index-
|
|
42
|
+
<script type="module" crossorigin src="/assets/index-DpRxWGjM.js"></script>
|
|
43
43
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-FhOqtrmT.js">
|
|
44
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-mermaid-
|
|
44
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-mermaid-CylkVm4U.js">
|
|
45
45
|
<link rel="modulepreload" crossorigin href="/assets/vendor-markdown-0Mxgxy0L.js">
|
|
46
46
|
<link rel="modulepreload" crossorigin href="/assets/vendor-ui-B-T_damt.js">
|
|
47
|
-
<link rel="modulepreload" crossorigin href="/assets/utils-
|
|
47
|
+
<link rel="modulepreload" crossorigin href="/assets/utils-ChWX7pZv.js">
|
|
48
48
|
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-BjHrJDVb.js">
|
|
49
49
|
<link rel="modulepreload" crossorigin href="/assets/x-DlFGzN8d.js">
|
|
50
|
-
<link rel="modulepreload" crossorigin href="/assets/input-
|
|
51
|
-
<link rel="modulepreload" crossorigin href="/assets/scroll-area-
|
|
50
|
+
<link rel="modulepreload" crossorigin href="/assets/input-CHRMley8.js">
|
|
51
|
+
<link rel="modulepreload" crossorigin href="/assets/scroll-area-DwWF9FpN.js">
|
|
52
52
|
<link rel="modulepreload" crossorigin href="/assets/dist-C5IgeqrV.js">
|
|
53
53
|
<link rel="modulepreload" crossorigin href="/assets/plus-51UQ45rf.js">
|
|
54
54
|
<link rel="modulepreload" crossorigin href="/assets/refresh-cw-CSFrDtiu.js">
|
|
55
|
-
<link rel="modulepreload" crossorigin href="/assets/trash-2-
|
|
56
|
-
<link rel="modulepreload" crossorigin href="/assets/api-client-
|
|
57
|
-
<link rel="modulepreload" crossorigin href="/assets/api-settings-
|
|
58
|
-
<link rel="modulepreload" crossorigin href="/assets/ai-settings-section-
|
|
55
|
+
<link rel="modulepreload" crossorigin href="/assets/trash-2-BgDIBl6f.js">
|
|
56
|
+
<link rel="modulepreload" crossorigin href="/assets/api-client-C3tXCh0r.js">
|
|
57
|
+
<link rel="modulepreload" crossorigin href="/assets/api-settings-2eTz4SgY.js">
|
|
58
|
+
<link rel="modulepreload" crossorigin href="/assets/ai-settings-section-D2vqiydT.js">
|
|
59
59
|
<link rel="modulepreload" crossorigin href="/assets/chevron-right-BzAdxJRG.js">
|
|
60
60
|
<link rel="modulepreload" crossorigin href="/assets/database-D4DIhgi-.js">
|
|
61
|
-
<link rel="modulepreload" crossorigin href="/assets/react-
|
|
62
|
-
<link rel="modulepreload" crossorigin href="/assets/extension-store-
|
|
63
|
-
<link rel="modulepreload" crossorigin href="/assets/keybindings-store-
|
|
64
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-store-
|
|
65
|
-
<link rel="modulepreload" crossorigin href="/assets/project-store-
|
|
66
|
-
<link rel="modulepreload" crossorigin href="/assets/settings-store-
|
|
67
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
61
|
+
<link rel="modulepreload" crossorigin href="/assets/react-BkWDCPD7.js">
|
|
62
|
+
<link rel="modulepreload" crossorigin href="/assets/extension-store-CkyOvGbF.js">
|
|
63
|
+
<link rel="modulepreload" crossorigin href="/assets/keybindings-store-CpP5_miA.js">
|
|
64
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-store-Jvy1eZGM.js">
|
|
65
|
+
<link rel="modulepreload" crossorigin href="/assets/project-store-CczGNZyf.js">
|
|
66
|
+
<link rel="modulepreload" crossorigin href="/assets/settings-store-CuYjM0FF.js">
|
|
67
|
+
<link rel="stylesheet" crossorigin href="/assets/index-iZHWllzQ.css">
|
|
68
68
|
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
|
69
69
|
<body class="bg-[#0f1419] text-[#e5e7eb] font-sans antialiased">
|
|
70
70
|
<div id="root"></div>
|
package/dist/web/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
try{self[`workbox:core:7.3.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.3.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.3.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.3.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&!(t.origin!==location.origin&&n.index!==0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}function B(e){O().precache(e)}function V(e,t){B(e),z(t)}V([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"8c83f3b66c8ea5cd77d7c5a79ccaa387","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"d0f94ce046cf8cf09605ee7664dac557","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"a424156a79b9c1b907db93aa3180585a","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"b3a7f967560c9816492a1567b3f7f0dc","url":"monacoeditorwork/css.worker.bundle.js"},{"revision":null,"url":"assets/x-DlFGzN8d.js"},{"revision":null,"url":"assets/vendor-xterm-ejLe7-tK.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/vendor-ui-B-T_damt.js"},{"revision":null,"url":"assets/vendor-mermaid-CwOSbfhN.js"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/utils-CTg5uAYR.js"},{"revision":null,"url":"assets/use-monaco-theme-CvV5vy_F.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-BsOrObtE.js"},{"revision":null,"url":"assets/trash-2-CJYoLw7Q.js"},{"revision":null,"url":"assets/text-wrap-Cn6BNQfq.js"},{"revision":null,"url":"assets/terminal-tab-CVdfvDSK.js"},{"revision":null,"url":"assets/table-Dq575bPF.js"},{"revision":null,"url":"assets/tab-store-B3M9hjho.js"},{"revision":null,"url":"assets/square-nsMa3iMk.js"},{"revision":null,"url":"assets/sqlite-viewer-f6ZJHIzh.js"},{"revision":null,"url":"assets/sql-query-editor-CM_qEhaX.js"},{"revision":null,"url":"assets/sql-completion-provider-C3cq9j99.js"},{"revision":null,"url":"assets/settings-tab-DfPjX9uY.js"},{"revision":null,"url":"assets/settings-store-D9CflsKU.js"},{"revision":null,"url":"assets/scroll-area-DW7L4Gnc.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/refresh-cw-CSFrDtiu.js"},{"revision":null,"url":"assets/react-GqWghJ-L.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-CJGco43I.js"},{"revision":null,"url":"assets/project-store-BYmQ0fDC.js"},{"revision":null,"url":"assets/postgres-viewer-YkljtDWX.js"},{"revision":null,"url":"assets/port-forwarding-tab-BUH9aImG.js"},{"revision":null,"url":"assets/plus-51UQ45rf.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-BVpLpAIy.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-Bl_WpvPc.js"},{"revision":null,"url":"assets/markdown-renderer-CKmmrUuy.js"},{"revision":null,"url":"assets/lib-D_kRA9p6.js"},{"revision":null,"url":"assets/keybindings-store-C9KsBH7z.js"},{"revision":null,"url":"assets/keybindings-store-BkZjvU9J.js"},{"revision":null,"url":"assets/katex-CKoArbIw.js"},{"revision":null,"url":"assets/input-ClhO__YM.js"},{"revision":null,"url":"assets/info-3K5VOQVL-VG29MIoT.js"},{"revision":null,"url":"assets/index-DuEUN2Eg.js"},{"revision":null,"url":"assets/index-DPnjO2FY.css"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-D8vKfkjC.js"},{"revision":null,"url":"assets/extension-webview-BFd0USXC.js"},{"revision":null,"url":"assets/extension-store-3yZYn07W.js"},{"revision":null,"url":"assets/esm-K1XIK4vc.js"},{"revision":null,"url":"assets/dist-im4ynINo.js"},{"revision":null,"url":"assets/dist-C5IgeqrV.js"},{"revision":null,"url":"assets/diff-viewer-x7kjfVYW.js"},{"revision":null,"url":"assets/database-viewer-CvQc1PZH.js"},{"revision":null,"url":"assets/database-D4DIhgi-.js"},{"revision":null,"url":"assets/csv-preview-BizIVMyb.js"},{"revision":null,"url":"assets/csv-parser--2WJNgS7.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/conflict-editor-Bxq4QiW1.js"},{"revision":null,"url":"assets/columns-2-4fQcE4PF.js"},{"revision":null,"url":"assets/code-editor-D3AAT8nI.js"},{"revision":null,"url":"assets/code-CuravVys.js"},{"revision":null,"url":"assets/chevron-right-BzAdxJRG.js"},{"revision":null,"url":"assets/chat-tab-Dki1pz84.js"},{"revision":null,"url":"assets/arrow-up-Dtrfv490.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-DmL1WyG-.js"},{"revision":null,"url":"assets/api-settings-C__hxGX2.js"},{"revision":null,"url":"assets/api-client-Bn-Pi9k5.js"},{"revision":null,"url":"assets/ai-settings-section-D2rONDPd.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/KaTeX_Script-Regular-D3wIWfF6.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"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":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"8a1e7ba38644bc468febaa7b2133eb3a","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":null,"url":"assets/lib-BqkcKGFq.js"},{"revision":null,"url":"assets/input-CHRMley8.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":null,"url":"assets/tab-store-Jvy1eZGM.js"},{"revision":null,"url":"assets/database-D4DIhgi-.js"},{"revision":null,"url":"assets/settings-tab-DHBG5O0C.js"},{"revision":null,"url":"assets/x-DlFGzN8d.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-Bt68dqWT.js"},{"revision":null,"url":"assets/extension-webview-HY8XueLo.js"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/sqlite-viewer-B7WnFN29.js"},{"revision":null,"url":"assets/ai-settings-section-D2vqiydT.js"},{"revision":null,"url":"assets/vendor-ui-B-T_damt.js"},{"revision":null,"url":"assets/markdown-renderer-BQV0AIm5.js"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/settings-store-CuYjM0FF.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-C9wPZfkn.js"},{"revision":null,"url":"assets/chevron-right-BzAdxJRG.js"},{"revision":null,"url":"assets/code-editor-BPxBeu0S.js"},{"revision":null,"url":"assets/sql-query-editor-CVEi0jLM.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-CLxaXgIf.js"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/trash-2-BgDIBl6f.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/dist-C5IgeqrV.js"},{"revision":null,"url":"assets/plus-51UQ45rf.js"},{"revision":null,"url":"assets/esm-B99v94EE.js"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/api-settings-2eTz4SgY.js"},{"revision":null,"url":"assets/arrow-up-Dtrfv490.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-DxEpzVN_.js"},{"revision":null,"url":"assets/refresh-cw-CSFrDtiu.js"},{"revision":null,"url":"assets/vendor-xterm-B9BUAFKA.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/api-client-C3tXCh0r.js"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/use-monaco-theme-kjiAwvOp.js"},{"revision":null,"url":"assets/database-viewer-CCe8qa1Q.js"},{"revision":null,"url":"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2"},{"revision":null,"url":"assets/KaTeX_Script-Regular-D3wIWfF6.woff2"},{"revision":null,"url":"assets/extension-store-CkyOvGbF.js"},{"revision":null,"url":"assets/info-3K5VOQVL-ySD5z855.js"},{"revision":null,"url":"assets/columns-2-4fQcE4PF.js"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/index-DpRxWGjM.js"},{"revision":null,"url":"assets/sql-completion-provider-D3acAhav.js"},{"revision":null,"url":"assets/react-BkWDCPD7.js"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/chat-tab-DYf6U6UF.js"},{"revision":null,"url":"assets/diff-viewer-DIjzWvaG.js"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/architecture-PBZL5I3N-BRW4VwMk.js"},{"revision":null,"url":"assets/postgres-viewer-BUSNt_7x.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-yelcZZqO.js"},{"revision":null,"url":"assets/conflict-editor-BCkYHDUy.js"},{"revision":null,"url":"assets/terminal-tab-1K4ijyNe.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/code-CuravVys.js"},{"revision":null,"url":"assets/csv-parser-BAa56Nnn.js"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/project-store-CczGNZyf.js"},{"revision":null,"url":"assets/port-forwarding-tab-DPmTpfFX.js"},{"revision":null,"url":"assets/katex-Bbu770d9.js"},{"revision":null,"url":"assets/keybindings-store-qfYScgY0.js"},{"revision":null,"url":"assets/utils-ChWX7pZv.js"},{"revision":null,"url":"assets/text-wrap-DzvCTq_i.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/scroll-area-DwWF9FpN.js"},{"revision":null,"url":"assets/index-iZHWllzQ.css"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":null,"url":"assets/keybindings-store-CpP5_miA.js"},{"revision":null,"url":"assets/csv-preview-D37K2LRd.js"},{"revision":null,"url":"assets/vendor-mermaid-CylkVm4U.js"},{"revision":null,"url":"assets/table-DbSviOmw.js"},{"revision":null,"url":"assets/dist-On3hz9_g.js"},{"revision":"d0f94ce046cf8cf09605ee7664dac557","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"a424156a79b9c1b907db93aa3180585a","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"b3a7f967560c9816492a1567b3f7f0dc","url":"monacoeditorwork/css.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.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/docs/codebase-summary.md
CHANGED
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
```
|
|
18
18
|
src/
|
|
19
19
|
├── cli/
|
|
20
|
-
│ ├── commands/ #
|
|
21
|
-
│ │
|
|
20
|
+
│ ├── commands/ # 16 CLI command groups (start, stop, init, config, chat, db, git, ext, jira, etc.)
|
|
21
|
+
│ │ ├── ext-cmd.ts # Extension CLI (install/remove/list/enable/disable/dev)
|
|
22
|
+
│ │ ├── jira-cmd.ts # Jira config commands (set, show, remove, test)
|
|
23
|
+
│ │ └── jira-watcher-cmd.ts # Jira watcher commands (add, list, enable, disable, remove, test, pull)
|
|
22
24
|
│ └── utils/
|
|
23
25
|
│ └── project-resolver.ts # Resolve project name -> path
|
|
24
26
|
├── server/
|
|
@@ -36,6 +38,9 @@ src/
|
|
|
36
38
|
│ │ ├── mcp.ts # MCP server CRUD + import (GET, POST, PUT, DELETE)
|
|
37
39
|
│ │ ├── extensions.ts # Extension install/remove/list/enable/disable, contributions
|
|
38
40
|
│ │ ├── upgrade.ts # Version checking, upgrade
|
|
41
|
+
│ │ ├── jira.ts # Jira routes barrel (config, watchers)
|
|
42
|
+
│ │ ├── jira-config-routes.ts # Jira config API (CRUD, test connection)
|
|
43
|
+
│ │ ├── jira-watcher-routes.ts # Jira watcher API (CRUD, poll, results, search, metadata)
|
|
39
44
|
│ │ └── static.ts # Serve frontend (dist/web)
|
|
40
45
|
│ ├── helpers/
|
|
41
46
|
│ │ └── resolve-project.ts # Resolve project from request params
|
|
@@ -92,7 +97,11 @@ src/
|
|
|
92
97
|
│ │ ├── sqlite-adapter.ts
|
|
93
98
|
│ │ ├── postgres-adapter.ts
|
|
94
99
|
│ │ └── readonly-check.ts # CTE-safe readonly validation
|
|
95
|
-
│
|
|
100
|
+
│ ├── jira-api-client.ts # Jira Cloud REST API v3 (search, getIssue, transitions)
|
|
101
|
+
│ ├── jira-config.service.ts # Jira config CRUD, AES-256 token encryption
|
|
102
|
+
│ ├── jira-watcher-db.service.ts # Watchers + results table queries
|
|
103
|
+
│ ├── jira-watcher.service.ts # Poll orchestrator, timer management, result sync
|
|
104
|
+
│ └── ... (16+ other services)
|
|
96
105
|
├── lib/
|
|
97
106
|
│ ├── account-crypto.ts # AES-256 encryption
|
|
98
107
|
│ └── network-utils.ts
|
|
@@ -105,11 +114,13 @@ src/
|
|
|
105
114
|
│ ├── mcp.ts # McpServerConfig, McpTransportType, validation
|
|
106
115
|
│ ├── extension.ts # ExtensionManifest, ExtensionInfo, RpcMessage, ExtensionContext
|
|
107
116
|
│ ├── ppmbot.ts # BotTask, TelegramUpdate, PPMBotCommand (coordinator types)
|
|
117
|
+
│ ├── jira.ts # JiraConfig, JiraWatcher, JiraWatchResult, JiraIssue, JiraCredentials
|
|
108
118
|
│ ├── project.ts
|
|
109
119
|
│ └── terminal.ts
|
|
110
120
|
└── web/ # React frontend (Vite + React 18)
|
|
111
121
|
├── app.tsx # Root component
|
|
112
|
-
├── stores/ # Zustand state (
|
|
122
|
+
├── stores/ # Zustand state (7 stores)
|
|
123
|
+
│ └── jira-store.ts # ADDED: Jira config, watchers, results, filters state
|
|
113
124
|
├── hooks/ # Custom hooks (9 hooks)
|
|
114
125
|
├── components/
|
|
115
126
|
│ ├── chat/
|
|
@@ -122,7 +133,15 @@ src/
|
|
|
122
133
|
│ ├── settings/
|
|
123
134
|
│ │ ├── ai-settings-section.tsx # UPDATED: Per-provider tabs, dynamic model dropdowns
|
|
124
135
|
│ │ ├── mcp-settings-section.tsx # ADDED: MCP servers tab (list, add, edit, delete)
|
|
125
|
-
│ │
|
|
136
|
+
│ │ ├── mcp-server-dialog.tsx # ADDED: Add/Edit MCP server dialog
|
|
137
|
+
│ │ ├── settings-tab.tsx # UPDATED: Added Jira Watcher tab
|
|
138
|
+
│ │ └── jira/ # ADDED: Jira Watcher components
|
|
139
|
+
│ │ ├── jira-settings-tab.tsx
|
|
140
|
+
│ │ ├── jira-config-form.tsx
|
|
141
|
+
│ │ ├── jira-filter-builder.tsx
|
|
142
|
+
│ │ ├── jira-watcher-list.tsx
|
|
143
|
+
│ │ ├── jira-results-panel.tsx
|
|
144
|
+
│ │ └── jira-ticket-detail.tsx
|
|
126
145
|
│ ├── database/
|
|
127
146
|
│ ├── editor/
|
|
128
147
|
│ ├── explorer/
|
|
@@ -222,11 +241,16 @@ src/
|
|
|
222
241
|
│ ├── test-setup.ts # Disable auth for tests
|
|
223
242
|
│ ├── unit/
|
|
224
243
|
│ │ ├── providers/ # Mock provider, SDK tests
|
|
244
|
+
│ │ ├── jira-watcher-poll.test.ts # ADDED: Jira watcher polling, rate limit backoff
|
|
225
245
|
│ │ └── services/ # Chat, config, db, session-log, push-notification tests
|
|
226
246
|
│ └── integration/
|
|
227
247
|
│ ├── claude-agent-sdk-integration.test.ts
|
|
228
248
|
│ ├── sqlite-migration.test.ts # SQLite migration validation
|
|
249
|
+
│ ├── jira-config.test.ts # ADDED: Jira config CRUD, token encryption
|
|
250
|
+
│ ├── jira-migration.test.ts # ADDED: Schema v18 migration validation
|
|
251
|
+
│ ├── jira-watcher-db.test.ts # ADDED: Watcher + result queries
|
|
229
252
|
│ ├── api/ # Chat route tests
|
|
253
|
+
│ ├── api/jira-routes.test.ts # ADDED: Jira API endpoints
|
|
230
254
|
│ └── ws/ # WebSocket tests
|
|
231
255
|
├── scripts/
|
|
232
256
|
│ ├── build.ts # Build CLI binary (bun build --compile)
|
|
@@ -6,9 +6,39 @@ All notable changes to PPM are documented here. Format follows [Keep a Changelog
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## [Unreleased] — Frontend Memory Optimization + Git-Graph Stash Management, Rebase, Conflict Resolution + Worktree CRUD
|
|
9
|
+
## [Unreleased] — Jira Debug Session Redesign + Frontend Memory Optimization + Git-Graph Stash Management, Rebase, Conflict Resolution + Worktree CRUD
|
|
10
10
|
|
|
11
11
|
### Added
|
|
12
|
+
- **Jira Debug Session Redesign** — Direct Claude session debug replacing bot_task flow with concurrency queue
|
|
13
|
+
- Replaced bot_task-based debug with direct `chatService.sendMessage()` calls (simpler, faster)
|
|
14
|
+
- Concurrency queue: max 2 concurrent sessions globally, max 1 per project (prevents resource exhaustion)
|
|
15
|
+
- Manual "Start Debug" button with editable prompt in results panel (override watcher template)
|
|
16
|
+
- Unread tracking: `read_at` column on `jira_watch_results`, unread badge count in UI
|
|
17
|
+
- WS toast notifications on debug completion (`jira:debug_complete` event)
|
|
18
|
+
- Prompt override support for custom debug instructions per result
|
|
19
|
+
- Result status flow: pending → queued → running → done/failed
|
|
20
|
+
- Timeout protection: 10-minute abort-on-timeout with graceful cleanup
|
|
21
|
+
- AI summary capture: last assistant text (max 500 chars) stored in result
|
|
22
|
+
- Database schema v19: added `read_at` (nullable timestamp), `triggered_by` ("auto"|"manual")
|
|
23
|
+
- New service: `JiraDebugSessionService` with queue management + concurrency limits
|
|
24
|
+
- New component: `JiraDebugPromptDialog` for manual prompt override UI
|
|
25
|
+
- API: `POST /api/jira/results/:id/debug` to trigger debug (with optional prompt)
|
|
26
|
+
|
|
27
|
+
- **Jira Watcher Auto-Debug (v0.9.86+)** — Poll Jira Cloud per-project, auto-debug matched tickets
|
|
28
|
+
- Jira Cloud REST API integration (search, get issue, transitions, metadata discovery)
|
|
29
|
+
- Per-project config (base URL, email, AES-256 token encryption)
|
|
30
|
+
- JQL-based watchers with two modes: debug (queue session) and notify-only (Telegram notification)
|
|
31
|
+
- Configurable poll intervals (30s–60m per watcher, interval clamping)
|
|
32
|
+
- Rate limit aware (tracks Jira API quota, auto-backoff 429 responses)
|
|
33
|
+
- Result tracking (pending/queued/running/done/failed status, AI summary persistence)
|
|
34
|
+
- Prompt templating ({issue_key}, {summary}, {description}, {status}, {priority} substitution)
|
|
35
|
+
- Soft deletes (preserve result history, don't lose tracking)
|
|
36
|
+
- Frontend filter builder UI (projects, issue types, priorities, statuses, custom JQL)
|
|
37
|
+
- CLI commands: `ppm jira config {set,show,remove,test}`, `ppm jira watch {add,list,enable,disable,remove,test,pull}`
|
|
38
|
+
- API routes: /api/jira/config/*, /api/jira/{watchers,results,search,ticket,metadata}
|
|
39
|
+
- 3 SQLite tables (v18): jira_config, jira_watchers, jira_watch_results
|
|
40
|
+
- 44 tests (integration + unit, JQL builder, result sync, credential encryption, rate limiting)
|
|
41
|
+
|
|
12
42
|
- **Frontend Memory & Performance Optimizations** — Reduce re-renders, lazy-load heavy components, code splitting
|
|
13
43
|
- **useShallow pattern:** All destructured Zustand store calls now use `useShallow` (36 usage sites) to prevent re-renders on object mutations
|
|
14
44
|
- **React.memo wrapping:** 10 heavy components memoized (CodeEditor, MessageBubble, ProjectBar, ProjectAvatar, TerminalTab, PanelLayout, Sidebar, StatusBar, StatusBarEntry, TabBar, TreeNode)
|
|
@@ -203,6 +203,10 @@ Tab IDs are deterministic: `{type}:{identifier}` (e.g., `editor:src/index.ts`, `
|
|
|
203
203
|
| **executeDelegation()** | Task execution in isolated session, result capture | (async function, manages ChatService + result storage) |
|
|
204
204
|
| **PPMBotFormatterService** | Markdown → Telegram HTML + chunking | formatMarkdown, chunkMessage |
|
|
205
205
|
| **PPMBotStreamerService** | ChatEvent → progressive Telegram edits | streamMessageEdits |
|
|
206
|
+
| **JiraConfigService** | Jira config CRUD, token encryption | getConfigByProjectId, upsertConfig, deleteConfig, getDecryptedCredentials |
|
|
207
|
+
| **JiraWatcherDbService** | Jira watchers + results queries | getAllEnabledWatchers, insertResult, updateResultStatus, getWatcherById |
|
|
208
|
+
| **JiraApiClient** | Jira Cloud REST API v3 integration | searchIssues, getIssue, updateIssue, testConnection, getProjects, getFieldOptions |
|
|
209
|
+
| **JiraWatcherService** | Poll orchestrator, timer management | startAll, startWatcher, pollWatcher, syncResultStatuses |
|
|
206
210
|
| **ClawBotService** | LEGACY Telegram bot (deprecated v0.9.11) | (direct-chat model, replaced by coordinator) |
|
|
207
211
|
| **ClawBotTelegramService** | LEGACY Telegram API | (deprecated v0.9.11) |
|
|
208
212
|
| **ClawBotSessionService** | LEGACY chatID mapping | (deprecated v0.9.11) |
|
|
@@ -441,6 +445,107 @@ Telegram → ClawBotTelegramService (polling) → ClawBotService (orchestrator)
|
|
|
441
445
|
|
|
442
446
|
---
|
|
443
447
|
|
|
448
|
+
### Jira Watcher Auto-Debug Service
|
|
449
|
+
**Component:** Jira Cloud REST API poller + direct Claude debug session orchestrator
|
|
450
|
+
|
|
451
|
+
**Responsibilities:**
|
|
452
|
+
- Poll Jira Cloud per-project on configurable interval (30s–60m)
|
|
453
|
+
- Match issues via JQL filters (status, project key, priority, etc.)
|
|
454
|
+
- Auto-queue or manually trigger direct Claude debug sessions (no bot_task middleman)
|
|
455
|
+
- Manage concurrency: max 2 concurrent, max 1 per project
|
|
456
|
+
- Track results (pending/queued/running/done/failed) with unread status
|
|
457
|
+
- Notify via WS toast + Telegram when analysis completes
|
|
458
|
+
- Rate-limit aware (tracks Jira API quota, auto-backoff 429 responses)
|
|
459
|
+
|
|
460
|
+
**Architecture:**
|
|
461
|
+
```
|
|
462
|
+
Jira Cloud API ← JiraWatcherService (poller, 30s–60m intervals per watcher)
|
|
463
|
+
├─ searchIssues(jql) → issue list
|
|
464
|
+
├─ insertResult() → SQLite jira_watch_results
|
|
465
|
+
└─ jiraDebugService.enqueue() → concurrency queue
|
|
466
|
+
|
|
467
|
+
JiraDebugSessionService (concurrency queue processor)
|
|
468
|
+
├─ enqueue(resultId, promptOverride?) → validate + queue
|
|
469
|
+
├─ processQueue() — respects MAX_CONCURRENT=2, MAX_PER_PROJECT=1
|
|
470
|
+
├─ runDebugSession()
|
|
471
|
+
│ ├─ chatService.createSession(projectPath) — new isolated session
|
|
472
|
+
│ ├─ chatService.sendMessage(prompt) — send with bypassPermissions
|
|
473
|
+
│ ├─ capture lastAssistantText (max 500 chars)
|
|
474
|
+
│ └─ updateResultStatus() + notificationService.broadcastWs("jira:debug_complete")
|
|
475
|
+
└─ cancelDebug(resultId) — abort running session
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
**Services (src/services/):**
|
|
479
|
+
- **JiraConfigService** — Config CRUD, AES-256 token encryption/decryption, per-project setup
|
|
480
|
+
- **JiraWatcherDbService** — Watchers + results table queries, enabled/disabled toggle, last polled tracking
|
|
481
|
+
- **JiraApiClient** — Jira Cloud REST v3 (search, getIssue, transitions, test connection), rate limit state, backoff logic
|
|
482
|
+
- **JiraWatcherService** — Main poller, timer management (startAll, startWatcher, stopWatcher, pollWatcher), prompt templating, session enqueueing
|
|
483
|
+
- **JiraDebugSessionService** — Concurrency queue, session lifecycle, timeout management, abort handling
|
|
484
|
+
|
|
485
|
+
**Database Schema (v19):**
|
|
486
|
+
- `jira_config` — id, project_id (FK), base_url, email, api_token_encrypted, created_at
|
|
487
|
+
- `jira_watchers` — id, jira_config_id (FK), name, jql, prompt_template, enabled, mode ("debug"|"notify"), interval_ms, last_polled_at, created_at
|
|
488
|
+
- `jira_watch_results` — id, watcher_id, issue_key, issue_summary, issue_updated, session_id (FK chat_sessions.id), status ("pending"|"queued"|"running"|"done"|"failed"), ai_summary, source ("watcher"|"manual"), triggered_by ("auto"|"manual"), read_at (nullable), deleted, created_at
|
|
489
|
+
|
|
490
|
+
**API Routes (src/server/routes/jira*.ts):**
|
|
491
|
+
```
|
|
492
|
+
POST /api/jira/config — Create/update config (baseUrl, email, token)
|
|
493
|
+
GET /api/jira/config — Get config for active project
|
|
494
|
+
DELETE /api/jira/config — Delete config
|
|
495
|
+
POST /api/jira/config/test — Test Jira connection
|
|
496
|
+
GET /api/jira/watchers — List watchers for config
|
|
497
|
+
POST /api/jira/watchers — Create watcher (name, jql, mode, interval)
|
|
498
|
+
PATCH /api/jira/watchers/:id — Update watcher
|
|
499
|
+
DELETE /api/jira/watchers/:id — Delete watcher (soft delete results)
|
|
500
|
+
POST /api/jira/watchers/:id/enable — Enable/disable watcher
|
|
501
|
+
POST /api/jira/watchers/:id/poll — Trigger poll now
|
|
502
|
+
GET /api/jira/results — List results (paginated, filterable)
|
|
503
|
+
POST /api/jira/results/:id/debug — Manually trigger debug for result (with optional prompt override)
|
|
504
|
+
POST /api/jira/results/:id/read — Mark result as read
|
|
505
|
+
DELETE /api/jira/results/:id — Delete result (soft delete)
|
|
506
|
+
GET /api/jira/search — Search Jira (for filter builder UI)
|
|
507
|
+
GET /api/jira/ticket/:key — Get full ticket details
|
|
508
|
+
GET /api/jira/metadata — Fetch projects, issue types, priorities, statuses
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**CLI Commands (src/cli/commands/jira*.ts):**
|
|
512
|
+
```
|
|
513
|
+
ppm jira config set <project> --url <url> --email <email> --token <token>
|
|
514
|
+
ppm jira config show <project>
|
|
515
|
+
ppm jira config remove <project>
|
|
516
|
+
ppm jira config test <project>
|
|
517
|
+
ppm jira watch add <project> <name> --jql <jql> [--mode debug|notify] [--interval 300000]
|
|
518
|
+
ppm jira watch list <project>
|
|
519
|
+
ppm jira watch enable/disable <project> <watcherId>
|
|
520
|
+
ppm jira watch remove <project> <watcherId>
|
|
521
|
+
ppm jira watch test <project> <watcherId>
|
|
522
|
+
ppm jira watch pull <project> <watcherId>
|
|
523
|
+
ppm jira results list <project> [--limit 50]
|
|
524
|
+
ppm jira results delete <project> <resultId>
|
|
525
|
+
ppm jira track <issue-key> — Manually track ticket (insert result, queue debug)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**Frontend (src/web/components/jira/):**
|
|
529
|
+
- **jira-settings-tab.tsx** — Config form, test button, token input
|
|
530
|
+
- **jira-filter-builder.tsx** — JQL builder UI (projects, issue types, priorities, statuses, custom JQL)
|
|
531
|
+
- **jira-watcher-list.tsx** — List watchers, enable/disable, edit, delete, poll now, interval controls
|
|
532
|
+
- **jira-results-panel.tsx** — Results table (issue key, status, summary, AI summary), unread badge, delete, manual debug button
|
|
533
|
+
- **jira-debug-prompt-dialog.tsx** — Modal for prompt override when manually triggering debug
|
|
534
|
+
- **jira-ticket-detail.tsx** — Modal with full ticket, AI analysis, debug status
|
|
535
|
+
- **jira-store.ts** — Zustand (configs, watchers, results, filters, settings, unread count)
|
|
536
|
+
|
|
537
|
+
**Key Design Decisions:**
|
|
538
|
+
1. **Direct Claude sessions** — Replaced bot_task flow with direct `chatService.sendMessage()` (simpler, faster, no task overhead)
|
|
539
|
+
2. **Concurrency queue** — Max 2 concurrent globally, max 1 per project (prevents resource starvation, respects project context)
|
|
540
|
+
3. **Manual debug trigger** — Users can override watcher prompt and manually queue debug for any pending result
|
|
541
|
+
4. **Unread tracking** — `read_at` column marks when user views result, UI shows unread badge count
|
|
542
|
+
5. **Prompt templating** — Support {issue_key}, {summary}, {description}, {status}, {priority} placeholders in watcher templates
|
|
543
|
+
6. **Timeout protection** — 10-minute timeout with AbortController graceful cleanup and error capture
|
|
544
|
+
7. **WS notifications** — `jira:debug_complete` event streamed to UI for instant toast feedback
|
|
545
|
+
8. **Soft deletes** — Results marked deleted=1 (preserve history, don't lose tracking)
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
444
549
|
### Data Access Layer (SQLite + Filesystem + Git)
|
|
445
550
|
**Components:** SQLite via bun:sqlite, direct filesystem access, simple-git wrapper
|
|
446
551
|
|
|
@@ -452,7 +557,7 @@ Telegram → ClawBotTelegramService (polling) → ClawBotService (orchestrator)
|
|
|
452
557
|
- Enforce security (no parent directory access)
|
|
453
558
|
|
|
454
559
|
**Key Patterns:**
|
|
455
|
-
- SQLite: WAL mode, foreign keys, lazy init, schema
|
|
560
|
+
- SQLite: WAL mode, foreign keys, lazy init, schema v19 (18 tables: config, connections, accounts, usage_history, session_logs, push_subscriptions, session_map, table_metadata, workspace_state, extension_storage, mcp_servers, clawbot_sessions, clawbot_memories, clawbot_paired_chats, jira_config, jira_watchers, jira_watch_results, bot_tasks)
|
|
456
561
|
- Path validation: `projectPath/relativePath` only, reject `..`
|
|
457
562
|
- Caching: Directory trees cached with TTL
|
|
458
563
|
- Error handling: Descriptive messages (file not found, permission denied)
|
package/package.json
CHANGED
|
@@ -242,7 +242,7 @@ button:active { background: var(--surface); }
|
|
|
242
242
|
|
|
243
243
|
/* Graph container */
|
|
244
244
|
#graph-container { flex: 1; overflow-y: auto; overflow-x: hidden; }
|
|
245
|
-
.commit-row { display: flex; align-items: center; cursor: pointer;
|
|
245
|
+
.commit-row { display: flex; align-items: center; cursor: pointer; height: 24px; padding: 0 6px; font-size: 12px; box-sizing: border-box; overflow: hidden; }
|
|
246
246
|
.commit-row:hover { background: var(--surface-hover); }
|
|
247
247
|
.commit-row.selected { background: var(--selected); }
|
|
248
248
|
.commit-row.header-row { background: var(--surface); cursor: default; font-weight: 600; font-size: 10px; color: var(--subtext); text-transform: uppercase; letter-spacing: 0.5px; position: sticky; top: 0; z-index: 2; border-bottom: 1px solid var(--border); min-height: 22px; }
|
|
@@ -385,7 +385,7 @@ button:active { background: var(--surface); }
|
|
|
385
385
|
|
|
386
386
|
/* Touch devices — compact mobile layout */
|
|
387
387
|
@media (pointer: coarse) {
|
|
388
|
-
.commit-row {
|
|
388
|
+
.commit-row { height: 32px; }
|
|
389
389
|
.ctx-item { padding: 8px 12px; min-height: 36px; }
|
|
390
390
|
button { min-width: 32px; min-height: 32px; padding: 2px 6px; }
|
|
391
391
|
#app { flex-direction: column; }
|
|
@@ -398,6 +398,7 @@ button:active { background: var(--surface); }
|
|
|
398
398
|
#commit-list-wrapper { min-width: 700px; }
|
|
399
399
|
#graph-header { min-width: 700px; }
|
|
400
400
|
.commit-row.header-row { min-height: 20px; }
|
|
401
|
+
.detail-panel { order: 8; max-height: 35vh; }
|
|
401
402
|
}
|
|
402
403
|
/* Column hiding on very narrow non-touch containers (e.g. narrow desktop panel) */
|
|
403
404
|
@media (max-width: 500px) and (pointer: fine) {
|
|
@@ -1331,11 +1332,11 @@ function graphRender(expandIdx) {
|
|
|
1331
1332
|
container.innerHTML = '';
|
|
1332
1333
|
if (gVertices.length === 0) { if (state.graphColWidth === null) document.documentElement.style.setProperty('--graph-col-w', '40px'); return; }
|
|
1333
1334
|
|
|
1334
|
-
//
|
|
1335
|
-
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1335
|
+
// Measure actual row height (may be fractional due to browser zoom)
|
|
1336
|
+
// and use it for SVG grid to prevent cumulative sub-pixel drift
|
|
1337
|
+
const firstRow = document.querySelector('#commit-list .commit-row');
|
|
1338
|
+
const rowH = firstRow ? firstRow.getBoundingClientRect().height : graphConfig.grid.y;
|
|
1339
|
+
const cfg = { ...graphConfig, grid: { ...graphConfig.grid, y: rowH, offsetY: rowH / 2 } };
|
|
1339
1340
|
|
|
1340
1341
|
const svg = document.createElementNS(SVG_NS, 'svg');
|
|
1341
1342
|
const group = document.createElementNS(SVG_NS, 'g');
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
|
|
3
|
+
const C = {
|
|
4
|
+
reset: "\x1b[0m", bold: "\x1b[1m", green: "\x1b[32m",
|
|
5
|
+
red: "\x1b[31m", yellow: "\x1b[33m", cyan: "\x1b[36m", dim: "\x1b[2m",
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export async function registerJiraCommands(program: Command): Promise<void> {
|
|
9
|
+
const jira = program.command("jira").description("Jira watcher utilities");
|
|
10
|
+
registerConfigCommands(jira);
|
|
11
|
+
await registerWatcherCommands(jira);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// ── Config commands ───────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
function registerConfigCommands(jira: Command): void {
|
|
17
|
+
const config = jira.command("config").description("Manage Jira configs");
|
|
18
|
+
|
|
19
|
+
config
|
|
20
|
+
.command("set <projectName>")
|
|
21
|
+
.description("Set Jira config for a project")
|
|
22
|
+
.requiredOption("--url <url>", "Jira base URL (https://...)")
|
|
23
|
+
.requiredOption("--email <email>", "Jira account email")
|
|
24
|
+
.requiredOption("--token <token>", "API token (⚠ visible in shell history)")
|
|
25
|
+
.action(async (projectName: string, opts: { url: string; email: string; token: string }) => {
|
|
26
|
+
try {
|
|
27
|
+
const { getDb } = await import("../../services/db.service.ts");
|
|
28
|
+
const project = getDb().query("SELECT id FROM projects WHERE name = ?").get(projectName) as { id: number } | null;
|
|
29
|
+
if (!project) { console.error(`${C.red}✗${C.reset} Project "${projectName}" not found`); process.exit(1); }
|
|
30
|
+
const { upsertConfig } = await import("../../services/jira-config.service.ts");
|
|
31
|
+
const cfg = upsertConfig(project.id, opts.url, opts.email, opts.token);
|
|
32
|
+
console.log(`${C.green}✓${C.reset} Jira config saved for "${projectName}" (id: ${cfg.id})`);
|
|
33
|
+
} catch (e: any) { console.error(`${C.red}✗${C.reset} ${e.message}`); process.exit(1); }
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
config
|
|
37
|
+
.command("show <projectName>")
|
|
38
|
+
.description("Show Jira config (token masked)")
|
|
39
|
+
.action(async (projectName: string) => {
|
|
40
|
+
try {
|
|
41
|
+
const { getDb } = await import("../../services/db.service.ts");
|
|
42
|
+
const project = getDb().query("SELECT id FROM projects WHERE name = ?").get(projectName) as { id: number } | null;
|
|
43
|
+
if (!project) { console.error(`${C.red}✗${C.reset} Project not found`); process.exit(1); }
|
|
44
|
+
const { getConfigByProjectId } = await import("../../services/jira-config.service.ts");
|
|
45
|
+
const cfg = getConfigByProjectId(project.id);
|
|
46
|
+
if (!cfg) { console.log(`${C.yellow}No Jira config for "${projectName}"${C.reset}`); return; }
|
|
47
|
+
console.log(` URL: ${cfg.baseUrl}`);
|
|
48
|
+
console.log(` Email: ${cfg.email}`);
|
|
49
|
+
console.log(` Token: ${cfg.hasToken ? "****" : "(none)"}`);
|
|
50
|
+
} catch (e: any) { console.error(`${C.red}✗${C.reset} ${e.message}`); process.exit(1); }
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
config
|
|
54
|
+
.command("remove <projectName>")
|
|
55
|
+
.description("Remove Jira config (cascades watchers + results)")
|
|
56
|
+
.action(async (projectName: string) => {
|
|
57
|
+
try {
|
|
58
|
+
const { getDb } = await import("../../services/db.service.ts");
|
|
59
|
+
const project = getDb().query("SELECT id FROM projects WHERE name = ?").get(projectName) as { id: number } | null;
|
|
60
|
+
if (!project) { console.error(`${C.red}✗${C.reset} Project not found`); process.exit(1); }
|
|
61
|
+
const { deleteConfig } = await import("../../services/jira-config.service.ts");
|
|
62
|
+
deleteConfig(project.id);
|
|
63
|
+
console.log(`${C.green}✓${C.reset} Config removed for "${projectName}"`);
|
|
64
|
+
} catch (e: any) { console.error(`${C.red}✗${C.reset} ${e.message}`); process.exit(1); }
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
config
|
|
68
|
+
.command("test <projectName>")
|
|
69
|
+
.description("Test Jira connection")
|
|
70
|
+
.action(async (projectName: string) => {
|
|
71
|
+
try {
|
|
72
|
+
const { getDb } = await import("../../services/db.service.ts");
|
|
73
|
+
const project = getDb().query("SELECT id FROM projects WHERE name = ?").get(projectName) as { id: number } | null;
|
|
74
|
+
if (!project) { console.error(`${C.red}✗${C.reset} Project not found`); process.exit(1); }
|
|
75
|
+
const { getConfigByProjectId, getDecryptedCredentials } = await import("../../services/jira-config.service.ts");
|
|
76
|
+
const cfg = getConfigByProjectId(project.id);
|
|
77
|
+
if (!cfg) { console.error(`${C.red}✗${C.reset} No config found`); process.exit(1); }
|
|
78
|
+
const creds = getDecryptedCredentials(cfg.id);
|
|
79
|
+
if (!creds) { console.error(`${C.red}✗${C.reset} Failed to decrypt token`); process.exit(1); }
|
|
80
|
+
const { testConnection } = await import("../../services/jira-api-client.ts");
|
|
81
|
+
await testConnection(creds);
|
|
82
|
+
console.log(`${C.green}✓${C.reset} Connection successful`);
|
|
83
|
+
} catch (e: any) { console.error(`${C.red}✗${C.reset} ${e.message}`); process.exit(1); }
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── Watcher + result + ticket commands ────────────────────────────────
|
|
88
|
+
|
|
89
|
+
async function registerWatcherCommands(jira: Command): Promise<void> {
|
|
90
|
+
const { registerJiraWatcherCommands } = await import("./jira-watcher-cmd.ts");
|
|
91
|
+
registerJiraWatcherCommands(jira);
|
|
92
|
+
}
|