prreviewbuddy 0.25.13 → 0.29.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prreviewbuddy",
3
- "version": "0.25.13",
3
+ "version": "0.29.1",
4
4
  "description": "Review a branch or pull request in an isolated checkout, from your terminal, with the coding agent you already have installed.",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://prreviewbuddy.com",
package/static/reviews.js CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./chunk-CIsM3PMS.js";import{n as t,t as n}from"./chunk-gBDI1-Cy.js";var r=[`all`,`in-progress`,`complete`];function i(e,t){let n=`${e} review${e===1?``:`s`}`;return e===t?n:`${n} · ${t} branch${t===1?``:`es`}`}function a(e,t){let n=Math.max(1,Math.ceil(e/15)),r=Math.min(Math.max(1,Math.floor(t)||1),n),i=(r-1)*15;return{page:r,pages:n,from:i,to:Math.min(i+15,e)}}function o(e){let t=new URLSearchParams(e.replace(/^#/,``)),n=t.get(`f`)??``,i=Number(t.get(`page`)??``);return{query:t.get(`q`)??``,filter:r.includes(n)?n:`all`,page:Number.isInteger(i)&&i>=1?i:1}}function s(e){let t=new URLSearchParams;e.query!==``&&t.set(`q`,e.query),e.filter!==`all`&&t.set(`f`,e.filter),e.page>1&&t.set(`page`,String(e.page));let n=t.toString();return n===``?``:`#${n}`}function c(e){return e===`complete`?`Reviewed`:e===`in-progress`?`In progress`:`New`}function l(e,t){if(e===0)return`Nothing selected`;let n=`${e} selected`;return t>0?`${n} · ${t} not shown`:n}function u(e){return e===0?`Delete`:`Delete ${e} branch${e===1?``:`es`}`}function d(e,t){let n=`${u(e)}?`;return t===e?n:`${n} This removes all ${t} reviews on ${e===1?`it`:`them`}.`}function f(e,t,n){return e===``||t===``||t===e?`wait`:n?`hold`:`reload`}var p=[...document.querySelectorAll(`[data-card]`)],m=document.querySelector(`.prb-index`),h=document.querySelector(`[data-search]`),g=document.querySelector(`[data-no-matches]`),_=document.querySelector(`[data-count]`),v=document.querySelector(`[data-pager]`),y=document.querySelector(`[data-pages]`),b=document.querySelector(`[data-bulk]`),x=document.querySelector(`[data-bulk-count]`),S=document.querySelector(`[data-bulk-delete]`),C=document.querySelector(`[data-bulk-question]`),w=document.querySelector(`[data-bulk-confirm]`),T=document.querySelector(`[data-bulk-actions]`),E=document.querySelector(`[data-bulk-error]`),D=o(window.location.hash),O=new Set,k=!1;function A(){let e=D.query.trim().toLowerCase(),t=p.filter(t=>{let n=D.filter===`all`||t.dataset.status===D.filter,r=!e||(t.dataset.searchText??``).includes(e);return n&&r}),n=a(t.length,D.page);D.page=n.page;let r=new Set(t.slice(n.from,n.to));for(let e of p)e.hidden=!r.has(e);h&&h.value!==D.query&&(h.value=D.query);for(let e of document.querySelectorAll(`[data-filter]`))e.setAttribute(`aria-pressed`,String(e.dataset.filter===D.filter));_&&(_.textContent=i(t.reduce((e,t)=>e+Number(t.dataset.reviews??1),0),t.length)),g&&(g.hidden=t.length>0||p.length===0),j(n),B(t)}function j(e){if(!(!v||!y)&&(v.hidden=e.pages<2,y.textContent=``,!v.hidden)){for(let t=1;t<=e.pages;t+=1){let n=document.createElement(`button`);n.type=`button`,n.className=`prb-index-page`,n.dataset.page=String(t),n.textContent=String(t),n.setAttribute(`aria-label`,`Page ${t}`),t===e.page&&n.setAttribute(`aria-current`,`page`),y.append(n)}for(let t of v.querySelectorAll(`[data-page-step]`)){let n=e.page+Number(t.dataset.pageStep);t.disabled=n<1||n>e.pages}}}function M(e,t){D={...D,...e},A();let n=`${window.location.pathname}${window.location.search}${s(D)}`;t===`push`?window.history.pushState(null,``,n):window.history.replaceState(null,``,n)}function N(){document.documentElement.scrollTop=0,document.body.scrollTop=0}h?.addEventListener(`input`,()=>M({query:h.value,page:1},`replace`)),h?.addEventListener(`keydown`,e=>{e.key===`Escape`&&h.value!==``&&(e.preventDefault(),M({query:``,page:1},`replace`))});for(let e of document.querySelectorAll(`[data-filter]`))e.addEventListener(`click`,()=>{M({filter:e.dataset.filter??`all`,page:1},`push`)});v?.addEventListener(`click`,e=>{let t=e.target,n=t.closest(`[data-page]`),r=t.closest(`[data-page-step]`);!n&&!r||(M({page:n?Number(n.dataset.page):D.page+Number(r?.dataset.pageStep??0)},`push`),N())});for(let e of[`popstate`,`hashchange`])window.addEventListener(e,()=>{D=o(window.location.hash),A()});document.addEventListener(`click`,e=>{let t=e.target.closest(`[data-pin]`);if(!t?.dataset.pin)return;e.preventDefault(),e.stopPropagation();let n=t.getAttribute(`aria-pressed`)!==`true`;t.setAttribute(`aria-pressed`,String(n)),t.innerHTML=n?`&#9733;`:`&#9734;`,t.setAttribute(`aria-label`,`${n?`Unpin`:`Pin`} this review`),t.title=n?`Unpin`:`Pin to the top`;let r=t.closest(`[data-card]`);r&&(r.dataset.pinned=String(n)),fetch(`/pin`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.dataset.pin,pinned:n})}).catch(()=>{})}),document.addEventListener(`click`,e=>{let t=e.target.closest(`[data-history-toggle]`);if(!t)return;e.preventDefault(),e.stopPropagation();let n=t.parentElement?.querySelector(`[data-history-list]`);if(!n)return;let r=n.hidden;n.hidden=!r,t.setAttribute(`aria-expanded`,String(r))}),A();function P(e){for(let t of document.querySelectorAll(`[data-menu]`)){if(t===e)continue;let n=t.querySelector(`[data-menu-panel]`),r=t.querySelector(`[data-menu-trigger]`);n&&(n.hidden=!0),r?.setAttribute(`aria-expanded`,`false`),F(t)}}function F(e){let t=e.querySelector(`[data-menu-items]`),n=e.querySelector(`[data-menu-confirm]`);t&&(t.hidden=!1),n&&(n.hidden=!0),e.querySelector(`[data-menu-error]`)?.remove(),e.querySelector(`[data-id-field]`)?.remove()}document.addEventListener(`keydown`,e=>{e.key===`Escape`&&P()}),document.addEventListener(`click`,e=>{let n=e.target,r=n.closest(`[data-menu]`);if(!r)return void P();let i=n.closest(`[data-menu-trigger]`);if(i){e.preventDefault(),e.stopPropagation();let t=r.querySelector(`[data-menu-panel]`);if(!t)return;let n=t.hidden;P(r),F(r),t.hidden=!n,i.setAttribute(`aria-expanded`,String(n));return}let a=n.closest(`[data-copy-id]`);if(a?.dataset.copyId){e.preventDefault(),e.stopPropagation(),t(a,a.dataset.copyId);return}if(n.closest(`[data-delete]`)){e.preventDefault(),e.stopPropagation();let t=r.querySelector(`[data-menu-items]`),n=r.querySelector(`[data-menu-confirm]`);t&&(t.hidden=!0),n&&(n.hidden=!1);return}if(n.closest(`[data-cancel-delete]`)){e.preventDefault(),e.stopPropagation(),F(r);return}if(n.closest(`[data-confirm-delete]`)){e.preventDefault(),e.stopPropagation(),I(r);return}e.preventDefault(),e.stopPropagation()});async function I(e){let t=e.querySelector(`[data-delete]`),n=t?.dataset.delete;if(!n)return;let r=e.querySelector(`[data-menu-confirm]`),i=e.querySelector(`[data-confirm-delete]`);i&&(i.disabled=!0,i.textContent=`Deleting`);try{let r=await fetch(`/delete`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:n,scope:t?.dataset.scope??`review`})});if(r.ok)return void window.location.reload();L(e,(await r.json().catch(()=>null))?.error??`That could not be deleted.`)}catch{L(e,`The workspace server did not answer. It may have stopped.`)}i&&(i.disabled=!1,i.textContent=`Delete`),r&&(r.hidden=!0);let a=e.querySelector(`[data-menu-items]`);a&&(a.hidden=!1)}function L(e,t){e.querySelector(`[data-menu-error]`)?.remove();let n=document.createElement(`p`);n.className=`prb-menu-error`,n.setAttribute(`data-menu-error`,``),n.textContent=t,e.querySelector(`[data-menu-panel]`)?.append(n)}function R(e){k=e,e||O.clear(),m&&(e?m.dataset.selecting=``:delete m.dataset.selecting),document.querySelector(`[data-select-mode]`)?.setAttribute(`aria-pressed`,String(e));for(let t of document.querySelectorAll(`.prb-card-link`))e?t.setAttribute(`aria-disabled`,`true`):t.removeAttribute(`aria-disabled`);z(),A()}function z(){w&&(w.hidden=!0),T&&(T.hidden=!1),E&&(E.hidden=!0,E.textContent=``)}function B(e){for(let e of p){let t=O.has(e.dataset.id??``),n=e.querySelector(`[data-select]`);n&&(n.checked=t),t?e.dataset.selected=``:delete e.dataset.selected}if(!b||(b.hidden=!k,!k))return;let t=new Set(e.map(e=>e.dataset.id)),n=[...O].filter(e=>!t.has(e)).length;x&&(x.textContent=l(O.size,n)),S&&(S.textContent=u(O.size));for(let e of b.querySelectorAll(`[data-bulk-mark], [data-bulk-delete]`))e.disabled=O.size===0}document.querySelector(`[data-select-mode]`)?.addEventListener(`click`,()=>{R(!k)});function V(e){O.has(e)?O.delete(e):O.add(e),z(),A()}document.addEventListener(`change`,e=>{let t=e.target.closest(`[data-select]`);t?.dataset.select&&V(t.dataset.select)}),document.addEventListener(`click`,e=>{if(!k)return;let t=e.target,n=t.closest(`[data-card]`);n?.dataset.id&&(t.closest(`[data-select], [data-pin], [data-menu], [data-history-toggle]`)||(e.preventDefault(),V(n.dataset.id)))}),document.addEventListener(`keydown`,e=>{if(!k||e.key!==`Enter`)return;let t=e.target.closest(`.prb-card-link`)?.closest(`[data-card]`);t?.dataset.id&&(e.preventDefault(),V(t.dataset.id))});function H(){return p.filter(e=>O.has(e.dataset.id??``))}function U(e){E&&(E.textContent=e,E.hidden=!1)}function W(e){for(let t of b?.querySelectorAll(`button`)??[])t.disabled=e}async function G(e){let t=[...O];if(t.length===0)return;W(!0);try{if(!(await fetch(`/status`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({ids:t,complete:e})})).ok)return W(!1),U(`That could not be saved. The workspace server refused it.`)}catch{return W(!1),U(`The workspace server did not answer. It may have stopped.`)}let n=e?`complete`:`in-progress`;for(let e of H()){e.dataset.status=n;let t=e.querySelector(`.prb-card-status`);t&&(t.dataset.status=n,t.textContent=c(n))}W(!1),R(!1)}async function K(){let e=[...O];if(e.length===0)return;W(!0);let t=null;try{let n=await fetch(`/delete`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({ids:e})});if(t=n.ok?await n.json().catch(()=>null):null,!t)return W(!1),z(),U(`Nothing was deleted. The workspace server refused it.`)}catch{return W(!1),z(),U(`The workspace server did not answer. It may have stopped.`)}let n=t.blocked??[],r=new Set(n.map(e=>e.id));for(let e of H())r.has(e.dataset.id??``)||e.remove();p=p.filter(e=>e.isConnected),O.clear();for(let e of r)O.add(e);if(W(!1),z(),n.length===0)return R(!1);A(),U([...new Set(n.map(e=>e.error))].join(` `))}b?.addEventListener(`click`,e=>{let t=e.target,n=t.closest(`[data-bulk-mark]`);if(n)return void G(n.dataset.bulkMark===`complete`);if(t.closest(`[data-bulk-delete]`)){let e=H().reduce((e,t)=>e+Number(t.dataset.reviews??1),0);C&&(C.textContent=d(O.size,e)),T&&(T.hidden=!0),w&&(w.hidden=!1);return}if(t.closest(`[data-bulk-confirm-delete]`))return void K();if(t.closest(`[data-bulk-cancel-delete]`))return z();if(t.closest(`[data-bulk-cancel]`))return R(!1)}),e(window,()=>window.location.reload());var q=document.body.dataset.indexRevision??``,J=document.body.dataset.live===`true`?Date.now():0,Y=!1;function X(){return O.size>0||document.activeElement===h}function Z(){Y&&!X()&&window.location.reload()}async function Q(){try{let e=await fetch(`/revision`);if(e.ok){let t=await e.json();t.live&&J===0&&(J=Date.now()),t.live||(J=0);let n=f(q,t.revision??``,X());if(n===`reload`)return void window.location.reload();n===`hold`&&(Y=!0)}}catch{}window.setTimeout(()=>void Q(),n(J===0?2**53-1:Date.now()-J))}Q(),h?.addEventListener(`blur`,Z),document.addEventListener(`click`,()=>window.setTimeout(Z,0));
1
+ import{t as e}from"./chunk-CIsM3PMS.js";import{n as t,t as n}from"./chunk-gBDI1-Cy.js";function r(e,t){t.forEach((t,n)=>{e.children[n]!==t&&e.insertBefore(t,e.children[n]??null)})}var i=[`all`,`queue`,`saved`,`in-progress`,`complete`];function a(e,t){let n=`${e} review${e===1?``:`s`}`;return e===t?n:`${n} · ${t} branch${t===1?``:`es`}`}function o(e,t){let n=Math.max(1,Math.ceil(e/15)),r=Math.min(Math.max(1,Math.floor(t)||1),n),i=(r-1)*15;return{page:r,pages:n,from:i,to:Math.min(i+15,e)}}function s(e){let t=new URLSearchParams(e.replace(/^#/,``)),n=t.get(`f`)??``,r=Number(t.get(`page`)??``);return{query:t.get(`q`)??``,filter:i.includes(n)?n:`all`,author:t.get(`by`)??``,page:Number.isInteger(r)&&r>=1?r:1}}function c(e){let t=new URLSearchParams;e.query!==``&&t.set(`q`,e.query),e.filter!==`all`&&t.set(`f`,e.filter),e.author!==``&&t.set(`by`,e.author),e.page>1&&t.set(`page`,String(e.page));let n=t.toString();return n===``?``:`#${n}`}function l(e,t){return t===`all`||t===`queue`?!0:t===`saved`?e.pinned===!0:e.status===t}function ee(e,t){return t===``||e===t}function u(e){return e===`complete`?`Mark reviewed`:`Mark in progress`}function te(e,t){return t===`queue`?e.filter(e=>e.queue!==void 0).sort((e,t)=>(e.queue??0)-(t.queue??0)):e}function d(e){return e===0?`Queue`:`Queue ${e}`}function ne(e){return e===`complete`?`Reviewed`:e===`in-progress`?`In progress`:`New`}function re(e,t){if(e===0)return`Nothing selected`;let n=`${e} selected`;return t>0?`${n} · ${t} not shown`:n}function f(e){return e===0?`Delete`:`Delete ${e} review${e===1?``:`s`}`}function ie(e){return`${f(e)}?`}function ae(e,t,n){return e===``||t===``||t===e?`wait`:n?`hold`:`reload`}var p=[...document.querySelectorAll(`[data-card]`)],m=document.querySelector(`[data-cards]`),h=document.querySelector(`.prb-index`);function g(e){return{id:e.dataset.id??``,queue:e.dataset.queue===void 0?void 0:Number(e.dataset.queue),status:e.dataset.status??`new`,pinned:e.dataset.pinned===`true`}}var _=document.querySelector(`[data-search]`),v=document.querySelector(`[data-author-filter]`),y=document.querySelector(`[data-no-matches]`),b=document.querySelector(`[data-count]`),x=document.querySelector(`[data-pager]`),S=document.querySelector(`[data-pages]`),C=document.querySelector(`[data-bulk]`),w=document.querySelector(`[data-bulk-count]`),T=document.querySelector(`[data-bulk-delete]`),E=document.querySelector(`[data-bulk-question]`),D=document.querySelector(`[data-bulk-confirm]`),O=document.querySelector(`[data-bulk-actions]`),k=document.querySelector(`[data-bulk-error]`),A=s(window.location.hash),j=new Set,M=!1;function N(){let e=A.query.trim().toLowerCase();A.author!==``&&![...v?.options??[]].some(e=>e.value===A.author)&&(A.author=``);let t=te(p.filter(t=>(!e||(t.dataset.searchText??``).includes(e))&&l(g(t),A.filter)&&ee(t.dataset.author,A.author)).map(e=>({...g(e),card:e})),A.filter).map(e=>e.card),n=o(t.length,A.page);A.page=n.page;let i=t.slice(n.from,n.to),s=new Set(i);for(let e of p)e.hidden=!s.has(e);m&&r(m,i),_&&_.value!==A.query&&(_.value=A.query),v&&(v.value=A.author,A.author===``?delete v.dataset.active:v.dataset.active=``);for(let e of document.querySelectorAll(`[data-filter]`))e.setAttribute(`aria-pressed`,String(e.dataset.filter===A.filter));b&&(b.textContent=a(t.reduce((e,t)=>e+Number(t.dataset.reviews??1),0),t.length)),y&&(y.hidden=t.length>0||p.length===0),P(n),V(t)}function P(e){if(!(!x||!S)&&(x.hidden=e.pages<2,S.textContent=``,!x.hidden)){for(let t=1;t<=e.pages;t+=1){let n=document.createElement(`button`);n.type=`button`,n.className=`prb-index-page`,n.dataset.page=String(t),n.textContent=String(t),n.setAttribute(`aria-label`,`Page ${t}`),t===e.page&&n.setAttribute(`aria-current`,`page`),S.append(n)}for(let t of x.querySelectorAll(`[data-page-step]`)){let n=e.page+Number(t.dataset.pageStep);t.disabled=n<1||n>e.pages}}}function F(e,t){A={...A,...e},N();let n=`${window.location.pathname}${window.location.search}${c(A)}`;t===`push`?window.history.pushState(null,``,n):window.history.replaceState(null,``,n)}function oe(){document.documentElement.scrollTop=0,document.body.scrollTop=0}_?.addEventListener(`input`,()=>F({query:_.value,page:1},`replace`)),_?.addEventListener(`keydown`,e=>{e.key===`Escape`&&_.value!==``&&(e.preventDefault(),F({query:``,page:1},`replace`))});for(let e of document.querySelectorAll(`[data-filter]`))e.addEventListener(`click`,()=>{F({filter:e.dataset.filter??`all`,page:1},`push`)});v?.addEventListener(`change`,()=>{F({author:v.value,page:1},`push`)}),x?.addEventListener(`click`,e=>{let t=e.target,n=t.closest(`[data-page]`),r=t.closest(`[data-page-step]`);!n&&!r||(F({page:n?Number(n.dataset.page):A.page+Number(r?.dataset.pageStep??0)},`push`),oe())});for(let e of[`popstate`,`hashchange`])window.addEventListener(e,()=>{A=s(window.location.hash),N()});document.addEventListener(`click`,e=>{let t=e.target.closest(`[data-pin]`);if(!t?.dataset.pin)return;e.preventDefault(),e.stopPropagation();let n=t.getAttribute(`aria-pressed`)!==`true`;t.setAttribute(`aria-pressed`,String(n)),t.innerHTML=n?`&#9733;`:`&#9734;`,t.setAttribute(`aria-label`,`${n?`Unsave`:`Save`} this review`);let r=t.closest(`[data-card]`);r&&(r.dataset.pinned=String(n)),fetch(`/pin`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.dataset.pin,pinned:n})}).catch(()=>{})});async function se(e,t,n){let r;try{let e=await fetch(`/queue`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t,action:n})});if(!e.ok)return;r=(await e.json()).queue}catch{return}let i=new Map(r.map((e,t)=>[e,t]));for(let e of p){let t=i.get(e.dataset.id??``);t===void 0?delete e.dataset.queue:e.dataset.queue=String(t)}let a=i.has(t);e.dataset.queueAction=a?`remove`:`add`,e.textContent=a?`Remove from review queue`:`Add to review queue`;let o=document.querySelector(`[data-queue-pill]`);o&&(o.textContent=d(r.length)),N()}document.addEventListener(`click`,e=>{let t=e.target.closest(`[data-history-toggle]`);if(!t)return;e.preventDefault(),e.stopPropagation();let n=t.parentElement?.querySelector(`[data-history-list]`);if(!n)return;let r=n.hidden;n.hidden=!r,t.setAttribute(`aria-expanded`,String(r))}),N();function I(e){for(let t of document.querySelectorAll(`[data-menu]`)){if(t===e)continue;let n=t.querySelector(`[data-menu-panel]`),r=t.querySelector(`[data-menu-trigger]`);n&&(n.hidden=!0),r?.setAttribute(`aria-expanded`,`false`),L(t)}}function L(e){let t=e.querySelector(`[data-menu-items]`),n=e.querySelector(`[data-menu-confirm]`);t&&(t.hidden=!1),n&&(n.hidden=!0),e.querySelector(`[data-menu-error]`)?.remove(),e.querySelector(`[data-id-field]`)?.remove()}document.addEventListener(`keydown`,e=>{e.key===`Escape`&&I()}),document.addEventListener(`click`,e=>{let n=e.target,r=n.closest(`[data-menu]`);if(!r)return void I();let i=n.closest(`[data-menu-trigger]`);if(i){e.preventDefault(),e.stopPropagation();let t=r.querySelector(`[data-menu-panel]`);if(!t)return;let n=t.hidden;I(r),L(r),t.hidden=!n,i.setAttribute(`aria-expanded`,String(n));return}let a=n.closest(`[data-copy-id]`);if(a?.dataset.copyId){e.preventDefault(),e.stopPropagation(),t(a,a.dataset.copyId);return}let o=n.closest(`[data-mark-status]`);if(o?.dataset.markId){e.preventDefault(),e.stopPropagation(),I(),ue(o.dataset.markId,o.dataset.markStatus===`complete`);return}let s=n.closest(`[data-queue-action]`);if(s?.dataset.queueId){e.preventDefault(),e.stopPropagation(),I(),se(s,s.dataset.queueId,s.dataset.queueAction===`remove`?`remove`:`add`);return}if(n.closest(`[data-delete]`)){e.preventDefault(),e.stopPropagation();let t=r.querySelector(`[data-menu-items]`),n=r.querySelector(`[data-menu-confirm]`);t&&(t.hidden=!0),n&&(n.hidden=!1);return}if(n.closest(`[data-cancel-delete]`)){e.preventDefault(),e.stopPropagation(),L(r);return}if(n.closest(`[data-confirm-delete]`)){e.preventDefault(),e.stopPropagation(),ce(r);return}e.preventDefault(),e.stopPropagation()});async function ce(e){let t=e.querySelector(`[data-delete]`),n=t?.dataset.delete;if(!n)return;let r=e.querySelector(`[data-menu-confirm]`),i=e.querySelector(`[data-confirm-delete]`);i&&(i.disabled=!0,i.textContent=`Deleting`);try{let r=await fetch(`/delete`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:n,scope:t?.dataset.scope??`review`})});if(r.ok)return void window.location.reload();R(e,(await r.json().catch(()=>null))?.error??`That could not be deleted.`)}catch{R(e,`The workspace server did not answer. It may have stopped.`)}i&&(i.disabled=!1,i.textContent=`Delete`),r&&(r.hidden=!0);let a=e.querySelector(`[data-menu-items]`);a&&(a.hidden=!1)}function R(e,t){e.querySelector(`[data-menu-error]`)?.remove();let n=document.createElement(`p`);n.className=`prb-menu-error`,n.setAttribute(`data-menu-error`,``),n.textContent=t,e.querySelector(`[data-menu-panel]`)?.append(n)}function z(e){M=e,e||j.clear(),h&&(e?h.dataset.selecting=``:delete h.dataset.selecting),document.querySelector(`[data-select-mode]`)?.setAttribute(`aria-pressed`,String(e));for(let t of document.querySelectorAll(`.prb-card-link`))e?t.setAttribute(`aria-disabled`,`true`):t.removeAttribute(`aria-disabled`);B(),N()}function B(){D&&(D.hidden=!0),O&&(O.hidden=!1),k&&(k.hidden=!0,k.textContent=``)}function V(e){for(let e of p){let t=j.has(e.dataset.id??``),n=e.querySelector(`[data-select]`);n&&(n.checked=t),t?e.dataset.selected=``:delete e.dataset.selected}if(!C||(C.hidden=!M,!M))return;let t=new Set(e.map(e=>e.dataset.id)),n=[...j].filter(e=>!t.has(e)).length;w&&(w.textContent=re(j.size,n)),T&&(T.textContent=f(W()));for(let e of C.querySelectorAll(`[data-bulk-mark], [data-bulk-delete]`))e.disabled=j.size===0}document.querySelector(`[data-select-mode]`)?.addEventListener(`click`,()=>{z(!M)});function H(e){j.has(e)?j.delete(e):j.add(e),B(),N()}document.addEventListener(`change`,e=>{let t=e.target.closest(`[data-select]`);t?.dataset.select&&H(t.dataset.select)}),document.addEventListener(`click`,e=>{if(!M)return;let t=e.target,n=t.closest(`[data-card]`);n?.dataset.id&&(t.closest(`[data-select], [data-pin], [data-menu], [data-history-toggle]`)||(e.preventDefault(),H(n.dataset.id)))}),document.addEventListener(`keydown`,e=>{if(!M||e.key!==`Enter`)return;let t=e.target.closest(`.prb-card-link`)?.closest(`[data-card]`);t?.dataset.id&&(e.preventDefault(),H(t.dataset.id))});function U(){return p.filter(e=>j.has(e.dataset.id??``))}function W(){return U().reduce((e,t)=>e+Number(t.dataset.reviews??1),0)}function G(e){k&&(k.textContent=e,k.hidden=!1)}function K(e){for(let t of C?.querySelectorAll(`button`)??[])t.disabled=e}async function le(e){let t=[...j];if(t.length!==0){K(!0);try{if(!(await fetch(`/status`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({ids:t,complete:e})})).ok)return K(!1),G(`That could not be saved. The workspace server refused it.`)}catch{return K(!1),G(`The workspace server did not answer. It may have stopped.`)}q(U(),e),K(!1),z(!1)}}function q(e,t){let n=t?`complete`:`in-progress`,r=t?`in-progress`:`complete`;for(let t of e){t.dataset.status=n;let e=t.querySelector(`.prb-card-status`);e&&(e.dataset.status=n,e.textContent=ne(n));let i=t.querySelector(`[data-mark-status]`);i&&(i.dataset.markStatus=r,i.textContent=u(r))}}async function ue(e,t){try{if(!(await fetch(`/status`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({ids:[e],complete:t})})).ok)return}catch{return}q(p.filter(t=>t.dataset.id===e),t),N()}async function J(){let e=[...j];if(e.length===0)return;K(!0);let t=null;try{let n=await fetch(`/delete`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({ids:e})});if(t=n.ok?await n.json().catch(()=>null):null,!t)return K(!1),B(),G(`Nothing was deleted. The workspace server refused it.`)}catch{return K(!1),B(),G(`The workspace server did not answer. It may have stopped.`)}let n=t.blocked??[],r=new Set(n.map(e=>e.id));for(let e of U())r.has(e.dataset.id??``)||e.remove();p=p.filter(e=>e.isConnected),j.clear();for(let e of r)j.add(e);if(K(!1),B(),n.length===0)return z(!1);N(),G([...new Set(n.map(e=>e.error))].join(` `))}C?.addEventListener(`click`,e=>{let t=e.target,n=t.closest(`[data-bulk-mark]`);if(n)return void le(n.dataset.bulkMark===`complete`);if(t.closest(`[data-bulk-delete]`)){E&&(E.textContent=ie(W())),O&&(O.hidden=!0),D&&(D.hidden=!1);return}if(t.closest(`[data-bulk-confirm-delete]`))return void J();if(t.closest(`[data-bulk-cancel-delete]`))return B();if(t.closest(`[data-bulk-cancel]`))return z(!1)}),e(window,()=>window.location.reload());var de=document.body.dataset.indexRevision??``,Y=document.body.dataset.live===`true`?Date.now():0,X=!1;function Z(){return j.size>0||document.activeElement===_}function Q(){X&&!Z()&&window.location.reload()}async function $(){try{let e=await fetch(`/revision`);if(e.ok){let t=await e.json();t.live&&Y===0&&(Y=Date.now()),t.live||(Y=0);let n=ae(de,t.revision??``,Z());if(n===`reload`)return void window.location.reload();n===`hold`&&(X=!0)}}catch{}window.setTimeout(()=>void $(),n(Y===0?2**53-1:Date.now()-Y))}$(),_?.addEventListener(`blur`,Q),document.addEventListener(`click`,()=>window.setTimeout(Q,0));
package/static/shell.css CHANGED
@@ -579,6 +579,12 @@ a.prb-rail-item { text-decoration: none; }
579
579
  color: var(--text-primary);
580
580
  }
581
581
  .prb-rail-item:focus-visible { outline: 2px solid var(--brand-hover); outline-offset: -2px; }
582
+ /* The pages under a review type (Issues, Questions, Files, PR context) and the links at the foot
583
+ share the group rows' white, so the grey themes in the review path read as their own list.
584
+ Weight still separates these from the group rows above them. Must come after `.prb-rail-item`:
585
+ the two are one class each, so whichever is later wins. One class, so Stop server's two-class
586
+ danger hover still wins over it. */
587
+ .prb-rail-link { color: var(--text-primary); }
582
588
 
583
589
  .prb-rail-order {
584
590
  flex: none;
@@ -589,6 +595,19 @@ a.prb-rail-item { text-decoration: none; }
589
595
  font-variant-numeric: tabular-nums;
590
596
  }
591
597
  .prb-rail-item[aria-current='true'] .prb-rail-order { color: var(--wordmark-accent); }
598
+ /* The same 18px column as the theme numbers, so every label in the rail starts at one edge. Centred
599
+ rather than on the baseline: an svg's baseline is its bottom edge, which sits it above the text. */
600
+ .prb-rail-icon {
601
+ flex: none;
602
+ display: flex;
603
+ align-self: center;
604
+ width: 18px;
605
+ height: 18px;
606
+ color: var(--text-muted);
607
+ }
608
+ .prb-rail-icon svg { width: 18px; height: 18px; }
609
+ .prb-rail-item:hover .prb-rail-icon,
610
+ .prb-rail-item[aria-current='true'] .prb-rail-icon { color: inherit; }
592
611
 
593
612
  .prb-rail-label { flex: 1; min-width: 0; line-height: 1.35; }
594
613
  .prb-rail-title { display: block; }
@@ -1058,8 +1077,12 @@ a.prb-rail-item { text-decoration: none; }
1058
1077
  text-align: left;
1059
1078
  cursor: pointer;
1060
1079
  }
1061
- .prb-suggestion:hover { border-color: var(--brand); color: var(--text-primary); }
1080
+ .prb-suggestion:hover:not(:disabled) { border-color: var(--brand); color: var(--text-primary); }
1062
1081
  .prb-suggestion:focus-visible { outline: 2px solid var(--brand-hover); outline-offset: 2px; }
1082
+ /* Buddy AI answers one question at a time; these wait for the one in flight. */
1083
+ .prb-suggestion:disabled,
1084
+ .pr-helper-explain-simply-button:disabled { opacity: 0.55; cursor: default; }
1085
+ .pr-helper-explain-simply-button:disabled:hover { background: transparent; }
1063
1086
 
1064
1087
  /* ── The reviewer's own prompts ──
1065
1088
  A strip between the assistant's header and its conversation: reachable without scrolling the
@@ -1996,6 +2019,7 @@ a.prb-rail-item { text-decoration: none; }
1996
2019
  .prb-progress-mark::before { content: '○'; }
1997
2020
  .prb-progress-step[data-state='complete'] .prb-progress-mark::before { content: '✓'; color: #1a7f37; }
1998
2021
  .prb-progress-step[data-state='failed'] .prb-progress-mark::before { content: '✕'; color: #cf222e; }
2022
+ .prb-progress-step[data-state='stopped'] .prb-progress-mark::before { content: '–'; color: #8c959f; }
1999
2023
  .prb-progress-step[data-state='active'] .prb-progress-mark::before { content: '●'; color: #9333ea; }
2000
2024
  .prb-progress-step[data-state='pending'] { color: #8c959f; }
2001
2025
  .prb-progress-step[data-state='pending'] .prb-progress-mark::before { color: #d0d7de; }
@@ -2285,6 +2309,38 @@ a.prb-rail-item { text-decoration: none; }
2285
2309
  color: var(--text-tertiary, var(--text-secondary));
2286
2310
  }
2287
2311
 
2312
+ /* The way back into the batch. A bordered row rather than a bare link, because it is the one
2313
+ destination on this page that changes as the reviewer works, and it has to be findable at a
2314
+ glance on every return. The label and the title are separate lines of weight so the eye lands
2315
+ on which review it will open. */
2316
+ .prb-index-continue {
2317
+ display: flex;
2318
+ align-items: baseline;
2319
+ gap: 10px;
2320
+ margin: 0 0 14px;
2321
+ padding: 10px 14px;
2322
+ border: 1px solid var(--border);
2323
+ border-left: 3px solid var(--brand);
2324
+ border-radius: 8px;
2325
+ color: var(--text-primary);
2326
+ text-decoration: none;
2327
+ }
2328
+ .prb-index-continue:hover { border-color: var(--brand); }
2329
+ .prb-index-continue:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
2330
+ .prb-index-continue-label {
2331
+ flex: none;
2332
+ font-size: 12px;
2333
+ font-weight: 600;
2334
+ color: var(--brand);
2335
+ }
2336
+ .prb-index-continue-title {
2337
+ min-width: 0;
2338
+ overflow: hidden;
2339
+ font-size: 13px;
2340
+ white-space: nowrap;
2341
+ text-overflow: ellipsis;
2342
+ }
2343
+
2288
2344
  /* Between the controls and the list, quiet, because it describes the list rather than announcing
2289
2345
  anything. It is rewritten in the browser as a filter narrows the set. */
2290
2346
  .prb-index-summary {
@@ -2318,14 +2374,18 @@ a.prb-rail-item { text-decoration: none; }
2318
2374
  color: #ffffff;
2319
2375
  }
2320
2376
 
2377
+ /* Wraps, so a narrow window gives the search its own line and puts the filters beneath it rather
2378
+ than crushing the field to a few letters beside five pills. The search's basis is what makes the
2379
+ wrap happen: with a basis of zero it would shrink to nothing before the row ever broke. */
2321
2380
  .prb-index-controls {
2322
2381
  display: flex;
2382
+ flex-wrap: wrap;
2323
2383
  gap: 12px;
2324
2384
  align-items: center;
2325
2385
  margin-bottom: 18px;
2326
2386
  }
2327
2387
  .prb-index-search {
2328
- flex: 1;
2388
+ flex: 1 1 240px;
2329
2389
  min-width: 0;
2330
2390
  padding: 9px 12px;
2331
2391
  border: 1px solid var(--border);
@@ -2337,6 +2397,22 @@ a.prb-rail-item { text-decoration: none; }
2337
2397
  }
2338
2398
  .prb-index-search:focus { outline: none; border-color: var(--brand); }
2339
2399
  .prb-index-filters { display: flex; gap: 4px; flex: none; }
2400
+ .prb-index-author {
2401
+ flex: none;
2402
+ max-width: 200px;
2403
+ padding: 7px 10px;
2404
+ border: 1px solid var(--border);
2405
+ border-radius: 8px;
2406
+ background: var(--surface-2);
2407
+ color: var(--text-primary);
2408
+ font: inherit;
2409
+ font-size: 12.5px;
2410
+ cursor: pointer;
2411
+ }
2412
+ .prb-index-author:hover { border-color: var(--brand); }
2413
+ .prb-index-author:focus-visible { outline: none; border-color: var(--brand); }
2414
+ /* Filled like a pressed pill once it narrows the list, so a filtered view is never mistaken for all of it. */
2415
+ .prb-index-author[data-active] { border-color: var(--brand); background: var(--brand); color: #ffffff; }
2340
2416
  .prb-index-filters button {
2341
2417
  padding: 7px 12px;
2342
2418
  border: 1px solid var(--border);
@@ -2685,7 +2761,8 @@ a.prb-rail-item { text-decoration: none; }
2685
2761
  background: currentColor;
2686
2762
  animation: prb-pulse 1.2s ease-in-out infinite;
2687
2763
  }
2688
- .prb-card-analysis[data-analysis='stopped'] { color: var(--text-muted); }
2764
+ .prb-card-analysis[data-analysis='stopped'],
2765
+ .prb-card-analysis[data-analysis='failed'] { color: var(--text-muted); }
2689
2766
  @media (prefers-reduced-motion: reduce) {
2690
2767
  .prb-card-analysis i { animation: none; opacity: 0.7; }
2691
2768
  }