@rigour-labs/cli 6.11.0-rc.2 → 6.11.0
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": "@rigour-labs/cli",
|
|
3
|
-
"version": "6.11.0
|
|
3
|
+
"version": "6.11.0",
|
|
4
4
|
"description": "Code review that happens while your agent writes: deterministic checks on the lines it changed, quiet unless it can prove a defect, and learning from your team's fixes and dismissals. Works with Claude Code, Cursor, Codex, Cline and Windsurf.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.13"
|
|
@@ -59,13 +59,13 @@
|
|
|
59
59
|
"inquirer": "9.2.16",
|
|
60
60
|
"ora": "^8.0.1",
|
|
61
61
|
"yaml": "^2.8.2",
|
|
62
|
-
"@rigour-labs/core": "6.11.0
|
|
62
|
+
"@rigour-labs/core": "6.11.0"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@types/fs-extra": "^11.0.4",
|
|
66
66
|
"@types/inquirer": "9.0.7",
|
|
67
67
|
"@types/node": "^25.0.3",
|
|
68
|
-
"@rigour-labs/studio": "6.11.0
|
|
68
|
+
"@rigour-labs/studio": "6.11.0"
|
|
69
69
|
},
|
|
70
70
|
"scripts": {
|
|
71
71
|
"build": "tsc && pnpm bundle-studio",
|
|
@@ -162,5 +162,5 @@ Error generating stack: `+l.message+`
|
|
|
162
162
|
*
|
|
163
163
|
* This source code is licensed under the ISC license.
|
|
164
164
|
* See the LICENSE file in the root directory of this source tree.
|
|
165
|
-
*/const Dc=q("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);class Ap extends oi.Component{constructor(){super(...arguments);bi(this,"state",{error:null})}static getDerivedStateFromError(n){return{error:n}}componentDidUpdate(n){n.resetKey!==this.props.resetKey&&this.state.error&&this.setState({error:null})}render(){return this.state.error?i.jsxs("div",{className:"empty-state glass-card",role:"alert",children:[i.jsx(Ip,{size:48}),i.jsx("h3",{children:"This view could not be displayed"}),i.jsx("p",{children:this.state.error.message||"Studio received data it could not render."}),i.jsxs("button",{className:"refresh-btn",type:"button",onClick:()=>this.setState({error:null}),children:[i.jsx(Fc,{size:16})," Retry view"]})]}):this.props.children}}function Wp({name:e,branch:t}){return i.jsxs("div",{className:"project-identity",children:[i.jsx(Ep,{size:14,className:"folder-icon"}),i.jsx("span",{className:"project-name",children:e}),t&&i.jsx("span",{className:"project-version-pill",title:"Current branch",children:t})]})}const da="rigour-readonly-note-hidden";function Up(){const[e,t]=_.useState(()=>{try{return sessionStorage.getItem(da)==="1"}catch{return!1}});if(e)return null;const n=()=>{try{sessionStorage.setItem(da,"1")}catch{}t(!0)};return i.jsxs("div",{className:"overview-banner readonly-note",role:"note",children:[i.jsx(Cs,{size:16}),i.jsxs("span",{children:["Read-only. Open the link ",i.jsx("code",{children:"rigour studio"})," printed in your terminal: it gives this tab edit rights."]}),i.jsx("button",{className:"readonly-note-close",onClick:n,type:"button","aria-label":"Hide this note",children:i.jsx(Dc,{size:14})})]})}function Dt({icon:e,label:t,status:n,detail:r}){const s=["ready","active","online","local"].includes(n)?"ready":["warming","idle","missing"].includes(n)?"warming":"degraded";return i.jsxs("div",{className:`health-item ${s}`,children:[i.jsx(e,{size:15,"aria-hidden":"true"}),i.jsxs("span",{children:[i.jsx("strong",{children:t}),i.jsx("small",{children:r})]}),i.jsx("span",{className:"health-state",children:n})]})}function Bp({data:e,loading:t,stale:n,onRetry:r}){var l,o,a,u,d,v,m,h,y,w,k,M,f,c,p,g,j;if(t&&!e)return i.jsxs("div",{className:"system-health loading",children:[i.jsx(ni,{size:16,className:"spinning"})," Checking system health…"]});if(!e||e.error)return i.jsxs("div",{className:"system-health unavailable",role:"alert",children:[i.jsx(ca,{size:16})," Health unavailable",i.jsxs("button",{type:"button",onClick:r,children:[i.jsx(Fc,{size:14})," Retry"]})]});const s=Object.values(((l=e.caches)==null?void 0:l.layers)??{}).filter(C=>C>0).length;return i.jsxs("section",{className:`system-health ${n?"stale":""}`,"aria-label":"System health",children:[i.jsx(Dt,{icon:Tp,label:"Index",status:((o=e.index)==null?void 0:o.status)??"missing",detail:`${((a=e.index)==null?void 0:a.patterns)??0} patterns · ${((u=e.index)==null?void 0:u.files)??0} files`}),i.jsx(Dt,{icon:Dp,label:"Graph",status:((d=e.graph)==null?void 0:d.status)??"missing",detail:`${((v=e.graph)==null?void 0:v.nodes)??0} nodes · ${((m=e.graph)==null?void 0:m.edges)??0} edges`}),i.jsx(Dt,{icon:Sp,label:"Semantic",status:((h=e.semantic)==null?void 0:h.status)??"disabled",detail:((y=e.semantic)==null?void 0:y.message)??"Background enrichment"}),i.jsx(Dt,{icon:Lp,label:"Cache",status:((w=e.caches)==null?void 0:w.status)??"warming",detail:`${s}/4 layers populated`}),i.jsx(Dt,{icon:ni,label:"Learning",status:((k=e.learning)==null?void 0:k.status)??"idle",detail:`${((M=e.learning)==null?void 0:M.observations)??0} interactions · ${((f=e.learning)==null?void 0:f.total)??0} lessons`}),i.jsx(Dt,{icon:ca,label:"Storage",status:((c=e.storage)==null?void 0:c.connectivity)??"local",detail:((p=e.storage)==null?void 0:p.connectivity)==="offline"?`${((g=e.storage)==null?void 0:g.queuedChanges)??0} queued`:((j=e.storage)==null?void 0:j.mode)??"local"})]})}const Hc="rigour-studio-key",Vp="x-rigour-studio-key";function Qp(){const e=window.location.hash.match(/(?:^#|&)key=([a-f0-9]+)/);if(e){try{sessionStorage.setItem(Hc,e[1])}catch{}window.history.replaceState(null,"",window.location.pathname+window.location.search)}}function Ts(){return Ac().length>0}function Ac(){try{return sessionStorage.getItem(Hc)??""}catch{return""}}function We(e,t,n,r="application/json"){const s={[Vp]:Ac()};return n!==void 0&&(s["Content-Type"]=r),fetch(e,{method:t,headers:s,body:n})}const Wc={edit:"while the agent was writing",review:"when the agent checked its work",stop:"before the agent said done",pr:"at the pull request"};function gt(e,t=Date.now()){const n=Math.round((t-Date.parse(e))/6e4);if(!Number.isFinite(n))return"";if(n<60)return`${Math.max(1,n)} min ago`;const r=Math.round(n/60);return r<48?`${r} h ago`:new Date(e).toLocaleDateString(void 0,{weekday:"short",month:"short",day:"numeric"})}function O(e,t,n=`${t}s`){return`${e} ${e===1?t:n}`}function ge(e){const[t,n]=_.useState(null),[r,s]=_.useState(null),l=_.useCallback(()=>{fetch(e).then(async o=>o.ok?n(await o.json()):s(`HTTP ${o.status}`)).catch(o=>s(o instanceof Error?o.message:String(o)))},[e]);return _.useEffect(l,[l]),{data:t,error:r,reload:l}}function fn(e){return e.split(/(`[^`]+`)/g).map((t,n)=>t.startsWith("`")&&t.endsWith("`")&&t.length>2?oi.createElement("code",{key:n,className:"st-mono st-inline-code"},t.slice(1,-1)):t)}function Kp(e){return e.replace(/(['"`])(?:(?!\1).)*\1/g,"…").replace(/\b\d+(?:\.\d+)?\b/g,"N").replace(/\s+/g," ").trim()}function Yp(e){const t=e.reduce((r,s)=>r+s.needs.length,0);if(t===0)return"Nothing needs you.";const n=`${O(t,"finding needs","findings need")} you`;return t===e.length?`${n}.`:`${n}, of ${O(e.length,"kind")}.`}function qp(e){const t=new Map,n=[...e].sort((r,s)=>Date.parse(s.openedAt)-Date.parse(r.openedAt));for(const r of n){const s=Kp(r.title),l=`${r.rule}\0${s}`,o=t.get(l)??{rule:r.rule,pattern:s,needs:[],files:0};o.needs.push(r),t.set(l,o)}for(const r of t.values())r.files=new Set(r.needs.map(s=>s.file)).size;return[...t.values()]}const Gp=({group:e,onDone:t})=>{const[n,r]=_.useState(!1);return e.needs.length===1?i.jsx(fa,{need:e.needs[0],onDone:t}):i.jsxs("div",{children:[i.jsxs("button",{className:"st-story",onClick:()=>r(!n),type:"button","aria-expanded":n,children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("span",{className:"st-chip warn",children:"open"}),i.jsxs("span",{className:"st-sub",children:["newest ",gt(e.needs[0].openedAt)]})]}),i.jsxs("div",{style:{fontSize:17,marginTop:10,lineHeight:1.5},children:[e.needs.length," × ",e.pattern,", in ",O(e.files,"file")]}),i.jsx("div",{className:"st-mono st-sub",style:{marginTop:6},children:e.rule})]}),n&&i.jsx("div",{className:"st-stack",style:{marginTop:10},children:e.needs.map(s=>i.jsx(fa,{need:s,onDone:t},`${s.rule}:${s.file}:${s.openedAt}`))})]})},fa=({need:e,onDone:t})=>{const[n,r]=_.useState("idle"),s=async()=>{const o=window.prompt("Why is this not a bug? Rigour keeps the reason with the dismissal.");if(!(o!=null&&o.trim())||!e.key)return;(await We("/api/dismiss","POST",JSON.stringify({key:e.key,reason:o}))).ok?t():r("failed")},l=async()=>{try{await navigator.clipboard.writeText(`Rigour found a problem you introduced: ${e.title} in ${e.file}. Fix it, then run rigour review.`),r("copied")}catch{r("failed")}};return i.jsxs("div",{className:"st-need",children:[i.jsxs("div",{className:"st-row",children:[i.jsx("span",{className:"st-chip warn",children:"open"}),i.jsxs("span",{className:"st-sub",children:["found ",e.stage?Wc[e.stage]:""," · ",gt(e.openedAt)]})]}),i.jsx("div",{style:{fontSize:17,marginTop:10,lineHeight:1.5},children:e.title}),i.jsx("div",{className:"st-mono st-sub",style:{marginTop:6},children:e.file}),i.jsxs("div",{className:"st-row",style:{marginTop:14,flexWrap:"wrap"},children:[i.jsx("button",{className:"st-btn primary",onClick:l,type:"button",children:n==="copied"?"Copied: paste it to your agent":"Copy for my agent"}),e.key&&i.jsx("button",{className:"st-btn",onClick:s,type:"button",children:"It's fine, not a bug"}),n==="failed"&&i.jsx("span",{className:"st-sub",children:"That didn't work. Open Studio from the link in your terminal and try again."})]})]})},pa="rigour-intro-hidden",Xp=({onNavigate:e})=>{const{data:t,error:n,reload:r}=ge("/api/week"),[s,l]=_.useState(null),[o,a]=_.useState(()=>{try{return localStorage.getItem(pa)!=="1"}catch{return!0}});if(n)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load this week: ",n,"."]})});if(!t)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const u=()=>{try{localStorage.setItem(pa,"1")}catch{}a(!1)},d=t.needs,v=qp(d);return i.jsxs("div",{className:"st-page",children:[o&&i.jsx(Jp,{onHide:u}),i.jsx("h1",{className:"st-h1",children:Yp(v)}),i.jsx("p",{className:"st-lead",children:t.stopped.total>0?`${O(t.stopped.total,"problem")} stopped and fixed before a pull request this week.`:t.recordingSince?"Nothing was stopped this week.":"Rigour has not recorded any agent work in this repository yet."}),d.length>0&&i.jsx(Zp,{onDone:r}),v.length>0&&i.jsx("div",{className:"st-stack",style:{marginTop:18},children:v.map(m=>i.jsx(Gp,{group:m,onDone:r},`${m.rule}:${m.pattern}`))}),i.jsxs("div",{className:"st-grid",children:[i.jsxs("section",{children:[i.jsx("h2",{style:{margin:"0 0 14px",fontSize:18,fontWeight:600},children:"What Rigour stopped this week"}),t.stories.length===0?i.jsx("div",{className:"st-empty",children:"When an agent fixes something Rigour caught, it appears here with the code change."}):i.jsx("div",{className:"st-stack",children:t.stories.map(m=>i.jsx(bp,{story:m,open:s===m.id,onToggle:()=>l(s===m.id?null:m.id)},m.id))})]}),i.jsxs("aside",{className:"st-side",children:[i.jsxs("div",{className:"st-card",children:[i.jsx("div",{className:"st-big",children:t.stopped.total}),i.jsx("div",{style:{fontSize:14,marginTop:6},children:"stopped before a PR"}),i.jsxs("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:[t.stopped.byStage.edit," while writing · ",t.stopped.byStage.review," on review · ",t.stopped.byStage.stop," before done"]}),i.jsx(eh,{data:t})]}),i.jsxs("div",{className:"st-card",children:[i.jsx("div",{style:{fontSize:15,fontWeight:600},children:"Is it noisy?"}),i.jsx("div",{style:{fontSize:14,marginTop:8,lineHeight:1.6},children:t.raised===0?"Nothing raised this week.":`Rigour raised ${O(t.raised,"problem")} this week. You overruled ${t.overruled}.`}),i.jsx("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:'Say "not a bug" once and Rigour stops raising it.'})]}),i.jsx("button",{className:"st-btn",onClick:()=>e("learns"),type:"button",children:"See how it learns"}),t.recordingSince&&i.jsxs("div",{className:"st-sub",children:["Recording since ",new Date(t.recordingSince).toLocaleDateString()]})]})]})]})},Jp=({onHide:e})=>i.jsxs("section",{className:"st-card",style:{marginBottom:28},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between",marginBottom:16},children:[i.jsx("strong",{children:"How Rigour works"}),i.jsx("button",{className:"st-btn",onClick:e,type:"button",children:"Got it"})]}),i.jsxs("div",{className:"st-steps",children:[i.jsxs("div",{className:"st-step",children:[i.jsx("span",{className:"st-num",children:"1"}),i.jsxs("div",{children:["Your AI agent writes code",i.jsx("div",{className:"st-sub",children:"Claude Code, Cursor, any agent."})]})]}),i.jsxs("div",{className:"st-step",children:[i.jsx("span",{className:"st-num",children:"2"}),i.jsxs("div",{children:["Rigour checks every change",i.jsx("div",{className:"st-sub",children:"It stops the agent only on problems it can prove; the agent fixes them."})]})]}),i.jsxs("div",{className:"st-step",children:[i.jsx("span",{className:"st-num",children:"3"}),i.jsxs("div",{children:["Your PR arrives clean",i.jsx("div",{className:"st-sub",children:"A short PR review catches the rest. Every fix teaches Rigour your code."})]})]})]})]}),Zp=({onDone:e})=>{const[t,n]=_.useState(null),r=async()=>{const s=await We("/api/recheck","POST","{}");if(!s.ok)return n("Could not check again.");const{closed:l,fixed:o}=await s.json(),a=[o?`${O(o,"fix")} by the agent recorded`:"",l?`${O(l,"finding")} no longer reported, closed (not counted as fixes)`:""].filter(Boolean).join("; ");n(a?`${a}.`:"Every one is still reported."),e()};return i.jsxs("div",{className:"st-row",style:{marginTop:10,gap:12},children:[i.jsx("button",{className:"st-btn",onClick:r,type:"button",children:"Check these again"}),t&&i.jsx("span",{className:"st-sub",children:t})]})},bp=({story:e,open:t,onToggle:n})=>i.jsxs("div",{children:[i.jsxs("button",{className:"st-story",onClick:n,type:"button","aria-expanded":t,children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("span",{className:"st-chip",children:Wc[e.stage]}),i.jsx("span",{className:"st-sub",children:gt(e.at)})]}),i.jsx("div",{style:{fontSize:16,lineHeight:1.55,marginTop:10},children:fn(e.title)}),i.jsxs("div",{className:"st-sub",style:{marginTop:6},children:[i.jsx("span",{className:"st-mono",children:e.file})," · fixed by the agent"]})]}),t&&i.jsxs("div",{className:"st-story-body",children:[e.diff.length>0&&i.jsx("div",{className:"st-code st-mono",children:e.diff.map((r,s)=>i.jsx("span",{className:`st-ln ${r[0]==="+"?"add":r[0]==="-"?"del":""}`,children:r},s))}),e.details&&e.details!==e.title&&i.jsxs("div",{style:{marginTop:e.diff.length?16:0},children:[i.jsx("strong",{style:{fontSize:13},children:e.stage==="review"&&e.rule==="review"?"What the agent fixed":"How Rigour knew"}),i.jsx("div",{className:"st-sub",style:{marginTop:6,lineHeight:1.6},children:fn(e.details)})]})]})]}),eh=({data:e})=>{const[t,n]=_.useState(!1);if(e.stopped.total===0)return null;const r=`Rigour stopped ${O(e.stopped.total,"problem")} before a pull request this week: ${e.stopped.byStage.edit} while the agent was writing, ${e.stopped.byStage.review} when it checked its work, ${e.stopped.byStage.stop} before it said done. ${e.overruled} of ${e.raised} overruled.`,s=async()=>{try{await navigator.clipboard.writeText(r),n(!0)}catch{}};return i.jsx("button",{className:"st-btn",onClick:s,type:"button",style:{marginTop:14,width:"100%"},children:t?"Copied":"Copy this week"})},th=e=>new Date(e).toLocaleDateString(void 0,{month:"short",day:"numeric"}),nl=(e,t)=>e.reduce((n,r)=>n+t(r),0),nh=()=>{var l;const{data:e,error:t}=ge("/api/progress");if(t)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load progress: ",t,"."]})});if(!e)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const n=e.weeks.slice(-4),r=e.weeks.slice(0,-4),s=((l=e.weeks[e.weeks.length-1])==null?void 0:l.lessons)??0;return i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"How Rigour is shaping this code"}),i.jsxs("p",{className:"st-lead",children:["Last 4 weeks: ",O(nl(n,o=>o.stopped),"problem")," stopped before a PR",r.length?` (${nl(r,o=>o.stopped)} in the 4 weeks before)`:"",", ",O(nl(n,o=>o.repeatsStopped),"repeat mistake")," caught,"," ",O(s,"lesson")," learned so far."]}),i.jsxs("div",{className:"st-stack",style:{marginTop:24},children:[i.jsx(Ht,{title:"Stopped before a PR",hint:"fixed by the agent after Rigour reported it",weeks:e.weeks,value:o=>o.stopped}),i.jsx(Ht,{title:"Repeat mistakes stopped",hint:"a mistake Rigour had already learned, caught again before a PR",weeks:e.weeks,value:o=>o.repeatsStopped}),i.jsx(Ht,{title:"Repeat mistakes that reached a PR",hint:"lower is better",weeks:e.weeks,value:o=>o.repeatsReachedPr,empty:"Shows once branch reviews run on this machine, for example rigour review --base main in a pre-push hook."}),i.jsx(Ht,{title:"Minutes from report to fix",hint:"median; lower is better",weeks:e.weeks,value:o=>o.minutesToFix}),i.jsx(Ht,{title:"Overruled",hint:"findings someone marked not a bug",weeks:e.weeks,value:o=>o.overruled}),i.jsx(Ht,{title:"Lessons learned",hint:"total by the end of each week",weeks:e.weeks,value:o=>o.lessons})]}),i.jsxs("div",{className:"st-grid",style:{gridTemplateColumns:"repeat(2, minmax(0, 1fr))"},children:[i.jsxs("section",{className:"st-card",children:[i.jsx("strong",{children:"Lessons that stopped the most repeats"}),e.topLessons.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:"None yet. A lesson ranks here once the mistake it describes is caught again and stopped."}):i.jsx("ol",{style:{margin:"12px 0 0",paddingLeft:20,lineHeight:1.6},children:e.topLessons.map(o=>i.jsxs("li",{style:{marginBottom:8},children:[fn(o.text),i.jsxs("div",{className:"st-sub",children:[O(o.stoppedInDevelopment??0,"repeat")," stopped · ",o.scope==="team"?"shared with team":o.scope]})]},o.id))})]}),i.jsxs("section",{className:"st-card",children:[i.jsx("strong",{children:"Checks your team acts on"}),e.checks.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:'Each fix and each "not a bug" scores the check that raised it. Scores appear after the first one.'}):i.jsx("div",{className:"st-stack",style:{marginTop:12,gap:8},children:e.checks.map(o=>i.jsxs("div",{className:"st-row",style:{gap:10},children:[i.jsxs("span",{style:{width:44,fontWeight:600},children:[Math.round(o.precision*100),"%"]}),i.jsx("span",{style:{flex:1,fontSize:14},children:o.check}),i.jsxs("span",{className:"st-sub",children:[o.fixed," fixed · ",o.dismissed," overruled"]}),o.muted&&i.jsx("span",{className:"st-chip",children:"quiet"})]},o.check))})]})]})]})},Ht=({title:e,hint:t,weeks:n,value:r,empty:s})=>{const l=n.map(r),o=l.filter(u=>u!==null),a=Math.max(1,...o);return i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:e}),i.jsx("span",{className:"st-sub",children:t})]}),o.length===0&&s?i.jsx("div",{className:"st-sub",style:{marginTop:10},children:s}):i.jsx("div",{className:"st-bars",style:{height:90,gap:12},children:n.map((u,d)=>i.jsxs("div",{className:"st-bar",children:[i.jsx("div",{style:{fontSize:12},children:l[d]??"—"}),i.jsx("span",{style:{height:`${l[d]===null?2:Math.max(2,l[d]/a*56)}px`,opacity:l[d]===null?.25:1}}),i.jsx("div",{className:"st-sub",style:{fontSize:11},children:th(u.from)})]},u.from))})]})},rh=()=>{const{data:e,error:t}=ge("/api/week"),n=ge("/api/setup").data,r=n==null?void 0:n.checks.some(l=>l.id==="stop"&&l.state!=="missing"&&l.state!=="broken");if(t)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load: ",t,"."]})});if(!e)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const s=e.stories.filter(l=>l.stage==="stop");return i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"What only Rigour caught"}),i.jsx("p",{className:"st-lead",children:"Counted only where Rigour can show it. A bug stopped before a PR never reached your other reviewers, so it is not counted against them."}),i.jsxs("section",{style:{marginTop:28},children:[i.jsx("h2",{style:{margin:0,fontSize:18,fontWeight:600},children:"Your agent tried to finish with a bug"}),i.jsx("p",{className:"st-lead",style:{fontSize:14},children:e.agentSaidDone===0&&n&&!r?"The stop hook is not set up in this repository, so Rigour cannot see an agent finish. Run rigour setup.":e.agentSaidDone===0?"This week no agent tried to finish with a problem Rigour could prove.":`This week an agent tried to finish with a problem Rigour proved ${O(e.agentSaidDone,"time")}. Each was fixed before the agent stopped.`}),i.jsx("div",{className:"st-stack",style:{marginTop:14},children:s.map(l=>i.jsxs("div",{className:"st-card st-row",children:[i.jsxs("div",{style:{flex:1},children:[i.jsx("div",{style:{fontSize:15,lineHeight:1.5},children:l.title}),i.jsxs("div",{className:"st-sub",style:{marginTop:4},children:[i.jsx("span",{className:"st-mono",children:l.file})," · ",gt(l.at)]})]}),i.jsx("span",{className:"st-chip ok",children:"fixed"})]},l.id))})]}),i.jsxs("section",{style:{marginTop:32},children:[i.jsx("h2",{style:{margin:0,fontSize:18,fontWeight:600},children:"Rigour and your other PR reviewers"}),i.jsxs("div",{className:"st-empty",style:{marginTop:14},children:[e.prCatches===null?"No branch reviews recorded on this machine yet.":`Branch reviews here reported ${O(e.prCatches,"problem")} this week.`," ","Side by side with teammates and review bots (both caught it, only Rigour, only them) needs the PR's review comments; it comes with the PR integration."]})]})]})},sh=()=>i.jsxs("p",{className:"st-lead",children:["Every mistake fixed in development or caught at a PR becomes a lesson. An agent gets the lessons when it asks for a brief (the ",i.jsx("code",{children:"rigour_brief"})," tool, or ",i.jsx("code",{children:"rigour brief"}),"). In Claude Code, ",i.jsx("code",{children:"rigour hooks init --brief"})," hands them over by itself: at a session's first prompt and on each file's first edit."]}),rl=(e,t=!0)=>t?e===null?"not recorded here":e===1?"1 time":`${e} times`:"—",lh=({lesson:e,onDecide:t,onDecideReview:n})=>i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between",alignItems:"flex-start"},children:[i.jsx("div",{style:{fontSize:17,lineHeight:1.5,flex:1},children:fn(e.text)}),i.jsx("span",{className:"st-chip",children:e.scope==="team"?"shared with team":e.scope})]}),i.jsxs("div",{className:"st-journey",children:[i.jsxs("div",{style:{background:"var(--bg-surface)"},children:[i.jsx("div",{className:"st-sub",children:"Learned"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:e.learnedFrom})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Agents told"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:rl(e.told)})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Stopped in development"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:rl(e.stoppedInDevelopment,e.origin==="development")})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Reached a PR again"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:rl(e.reachedPr,e.origin==="development")})]})]}),e.takenBack&&i.jsxs("div",{style:{marginTop:14},children:[i.jsxs("div",{children:[i.jsx("span",{className:"st-chip warn",children:"taken back"})," ",i.jsx("span",{className:"st-sub",children:e.takenBack.detail})]}),i.jsxs("div",{className:"st-row",style:{marginTop:10},children:[i.jsx("span",{className:"st-sub",children:"Later pull requests a review found repeating it merged and stayed fine. Keep telling agents anyway?"}),i.jsx("button",{className:"st-btn primary",onClick:()=>n==null?void 0:n(e.id,"accepted"),type:"button",children:"Promote again"}),i.jsx("button",{className:"st-btn",onClick:()=>n==null?void 0:n(e.id,"rejected"),type:"button",children:"Drop"})]})]}),e.reclassified&&i.jsxs("div",{style:{marginTop:14},children:[i.jsxs("div",{children:[i.jsx("span",{className:"st-chip warn",children:"back to candidate"})," ",i.jsx("span",{className:"st-sub",children:e.reclassified.detail})]}),e.reclassified.evidence.map(r=>i.jsx("div",{className:"st-sub",style:{marginTop:4},children:r},r)),i.jsxs("div",{className:"st-row",style:{marginTop:10},children:[i.jsx("span",{className:"st-sub",children:"A later fix on its lines used to make this a lesson by itself; now a person decides. Keep telling agents?"}),i.jsx("button",{className:"st-btn primary",onClick:()=>n==null?void 0:n(e.id,"accepted"),type:"button",children:"Promote"}),i.jsx("button",{className:"st-btn",onClick:()=>n==null?void 0:n(e.id,"dismissed"),type:"button",children:"Dismiss"})]})]}),e.suggested&&i.jsxs("div",{style:{marginTop:14},children:[i.jsxs("div",{children:[i.jsx("span",{className:"st-chip",children:"a later fix changed these lines"})," ",i.jsx("span",{className:"st-sub",children:e.suggested.detail})]}),i.jsxs("div",{className:"st-row",style:{marginTop:10},children:[i.jsxs("span",{className:"st-sub",children:["The pull request (#",e.suggested.pr,") left this point alone, and a later fix changed its lines. If that fix is about this point, the lesson was right."]}),i.jsx("button",{className:"st-btn primary",onClick:()=>n==null?void 0:n(e.id,"accepted"),type:"button",children:"Promote"}),i.jsx("button",{className:"st-btn",onClick:()=>n==null?void 0:n(e.id,"dismissed"),type:"button",children:"Dismiss"})]})]}),e.canDecide&&!e.takenBack&&!e.suggested&&!e.reclassified&&i.jsxs("div",{className:"st-row",style:{marginTop:14},children:[i.jsx("span",{className:"st-sub",children:e.scope==="team"?"Shared by a teammate. Give it to everyone's agents?":"Seen once. Keep it so your agents get told?"}),i.jsx("button",{className:"st-btn primary",onClick:()=>t(e.id,e.scope==="team"?"promoted":"validated"),type:"button",children:e.scope==="team"?"Share with team":"Keep"}),i.jsx("button",{className:"st-btn",onClick:()=>t(e.id,"rejected"),type:"button",children:"Drop"})]})]}),ih=({model:{share:e,costPerPr:t}})=>i.jsxs("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:["The model reviewer: ",e.model," of ",e.model+e.checks," findings at first review on ",e.prs," pull request",e.prs===1?"":"s",e.rate===null?"":` (${Math.round(e.rate*100)}%)`,", the rest from the free checks."," ","It cost $",t.totalUsd.toFixed(2)," over ",t.prs," pull request",t.prs===1?"":"s",t.medianUsd===null?"":`, $${t.medianUsd.toFixed(2)} each at the median`,".",t.prsEarlierBasis?` ${t.prsEarlierBasis} more reviewed before every run was counted, left out.`:""]}),ha=e=>`${e.count} of ${e.of}${e.rate===null?"":` (${Math.round(e.rate*100)}%)`}`,oh=({numbers:e})=>i.jsxs("section",{className:"st-card",style:{margin:"0 0 24px"},children:[i.jsx("strong",{children:"After the merge"}),i.jsxs("div",{className:"st-sub",style:{marginTop:4},children:[e.records.merged," merged pull requests read on this machine; ",e.records.settled," settled, ",e.records.unsettled," with the window still open."]}),i.jsxs("div",{className:"st-journey",style:{marginTop:10},children:[i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"CI regressed on the merge"}),i.jsxs("div",{style:{fontSize:14,marginTop:4},children:[ha(e.settled.ciRegressed),e.settled.ciUnknown?`, ${e.settled.ciUnknown} with no CI to read`:""]})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Reverted"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:ha(e.settled.reverted)})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Reviewed by Rigour"}),i.jsxs("div",{style:{fontSize:14,marginTop:4},children:[e.settled.reviewed.prs," pull requests, ",e.settled.reviewed.fixedLater.count," fixed later"]})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Not reviewed"}),i.jsxs("div",{style:{fontSize:14,marginTop:4},children:[e.settled.notReviewed.prs," pull requests, ",e.settled.notReviewed.fixedLater.count," fixed later"]})]})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:["Lessons: ",e.lessons.awaitingDecision," waiting on you, ",e.lessons.promotedFromEvidence," promoted from evidence, ",e.lessons.dismissed," dismissed, ",e.lessons.takenBack," taken back."," ","Teams choose which pull requests get reviewed, so the two groups differ: this is not a comparison."]}),e.model&&i.jsx(ih,{model:e.model})]}),ma=e=>`${e.fired} of ${e.n}${e.rate===null?"":` (${Math.round(e.rate*100)}%)`}`,ah=({checks:e,onDecide:t,onPropose:n})=>i.jsxs("section",{className:"st-card",style:{margin:"24px 0"},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:"Lessons compiled into checks"}),i.jsx("button",{className:"st-btn",type:"button",onClick:n,children:"Propose checks"})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.6},children:["A verified lesson that names its file and symbols becomes a check that runs on every review, for free; the model reviewer stops spending prompt on it. A proposed check runs only once you approve it. Who approved it, by git email, is committed with it in ",i.jsx("span",{className:"st-mono",children:".rigour/compiled-checks.json"}),"."]}),e.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10},children:"None yet. Propose checks once a lesson says never, avoid, instead of, always or must about a symbol in backticks."}):i.jsx("div",{className:"st-stack",style:{marginTop:12},children:e.map(r=>i.jsxs("div",{className:"st-need",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("span",{className:`st-chip ${r.suspended?"bad":r.state==="active"?"ok":r.state==="proposed"?"warn":""}`,children:r.suspended?"suspended":r.state}),i.jsx("span",{className:"st-sub st-mono",children:r.files})]}),i.jsx("div",{style:{marginTop:8},children:r.kind==="forbid"?i.jsxs(i.Fragment,{children:["Reports ",i.jsx("code",{children:r.symbol})," on a changed line."]}):i.jsxs(i.Fragment,{children:["Reports ",i.jsx("code",{children:r.symbol})," with no ",i.jsx("code",{children:r.with})," within three lines."]})}),i.jsxs("div",{className:"st-sub",style:{marginTop:4},children:[fn(r.message)," · lesson ",r.lessonId,r.by?` · ${r.state==="withdrawn"?"taken back":"approved"} by ${r.by}`:""]}),r.suspended&&i.jsx("div",{className:"st-sub",style:{marginTop:6},children:r.suspended}),r.backtest&&i.jsxs("div",{className:"st-sub",style:{marginTop:6,lineHeight:1.6},children:["On the last ",r.backtest.commits," merged changes to its files: fires on ",ma(r.backtest.repeating)," where a review found the lesson repeating, and on ",ma(r.backtest.other)," others (each a false fire, or a catch the review missed)."]}),i.jsxs("div",{className:"st-row",style:{marginTop:10,gap:8},children:[r.state!=="active"&&i.jsx("button",{className:"st-btn",type:"button",onClick:()=>t(r.id,"active"),children:"Approve"}),r.state==="active"&&i.jsx("button",{className:"st-btn",type:"button",onClick:()=>t(r.id,"withdrawn"),children:"Take back"})]})]},r.id))})]}),uh=()=>{const{data:e,error:t,reload:n}=ge("/api/learning");if(t)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load lessons: ",t,"."]})});if(!e)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const r=async(u,d)=>{(await We("/api/lessons","POST",JSON.stringify({id:u,state:d}))).ok&&n()},s=async(u,d)=>{(await We("/api/review-lessons","POST",JSON.stringify({id:u,decision:d}))).ok&&n()},l=async(u,d)=>{const v=await We("/api/compiled-checks","POST",JSON.stringify({id:u,state:d}));v.ok?n():window.alert((await v.json().catch(()=>({}))).error??"Could not record the decision.")},o=async()=>{(await We("/api/compiled-checks","POST",JSON.stringify({propose:!0}))).ok&&n()},a=Math.max(1,...e.weeks.map(u=>Math.max(u.stoppedInDevelopment,u.reachedPr??0)));return i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"How Rigour learns your codebase"}),i.jsx(sh,{}),i.jsxs("section",{className:"st-card",style:{margin:"24px 0"},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:"Repeat mistakes, by week"}),i.jsx("span",{className:"st-sub",children:"a mistake Rigour had already learned"})]}),i.jsx("div",{className:"st-bars",children:e.weeks.map(u=>i.jsxs("div",{className:"st-bar",children:[i.jsxs("div",{style:{fontSize:13},children:[u.stoppedInDevelopment," stopped",u.reachedPr===null?"":` · ${u.reachedPr} reached a PR`]}),i.jsx("span",{style:{height:`${Math.max(4,u.stoppedInDevelopment/a*80)}px`}}),i.jsxs("div",{className:"st-sub",children:["from ",new Date(u.from).toLocaleDateString(void 0,{month:"short",day:"numeric"})]})]},u.from))}),!e.prRecorded&&i.jsxs("div",{className:"st-sub",style:{marginTop:14},children:["Repeats that reached a PR show once branch reviews run on this machine (",i.jsx("span",{className:"st-mono",children:"rigour review --base main"}),", for example in a pre-push hook). Reviews in CI stay in CI."]})]}),e.outcomes&&i.jsx(oh,{numbers:e.outcomes}),i.jsx(ah,{checks:e.compiled??[],onDecide:l,onPropose:o}),e.lessons.length===0?i.jsx("div",{className:"st-empty",children:"No lessons yet. They form when an agent fixes something Rigour reported, when a PR comment leads to a fix, or when you tell your agent to remember something."}):i.jsx("div",{className:"st-stack",children:e.lessons.map(u=>i.jsx(lh,{lesson:u,onDecide:r,onDecideReview:s},u.id))}),i.jsx(ch,{})]})},ch=()=>{var r,s,l;const e=ge("/api/learned-rules").data??[],t=Object.entries(((r=ge("/api/memory").data)==null?void 0:r.memories)??{}),n=(l=(s=ge("/api/index-stats").data)==null?void 0:s.stats)==null?void 0:l.totalPatterns;return i.jsxs("div",{className:"st-grid",style:{gridTemplateColumns:"repeat(2, minmax(0, 1fr))"},children:[i.jsxs("section",{className:"st-card",children:[i.jsx("strong",{children:"Rules learned from fixes"}),i.jsx("div",{className:"st-sub",style:{marginTop:4},children:"Checked on every edit, like a built-in check."}),e.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:"None yet. rigour learn turns an agent's fixes into rules once they hold up."}):i.jsx("ul",{style:{margin:"10px 0 0",paddingLeft:18,lineHeight:1.6,fontSize:14},children:e.map(o=>i.jsxs("li",{children:[o.message,i.jsxs("div",{className:"st-sub",children:[o.requirement," · ",o.appliesTo]})]},o.id))})]}),i.jsxs("section",{className:"st-card",children:[i.jsx("strong",{children:"What your agents were told to remember"}),i.jsx("div",{className:"st-sub",style:{marginTop:4},children:"Facts saved with rigour_remember; agents recall them by meaning."}),t.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:"Nothing saved yet."}):i.jsx("ul",{style:{margin:"10px 0 0",paddingLeft:18,lineHeight:1.6,fontSize:14},children:t.slice(0,12).map(([o,a])=>i.jsxs("li",{children:[i.jsx("strong",{children:o.replace(/_/g," ")}),": ",a.value.length>220?`${a.value.slice(0,220)}…`:a.value]},o))}),t.length>12&&i.jsxs("div",{className:"st-sub",style:{marginTop:6},children:["and ",t.length-12," more"]})]}),typeof n=="number"&&n>0&&i.jsxs("section",{className:"st-card",style:{gridColumn:"1 / -1"},children:[i.jsxs("strong",{children:[n," functions indexed"]}),i.jsx("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.6},children:"Before an agent writes a new helper, Rigour checks whether one already exists and points to it, so the codebase doesn't fill with near-copies."})]})]})},va=e=>e>=1e3?`${Math.round(e/1e3)}k`:String(e),dh=()=>{const{data:e,error:t}=ge("/api/context");if(t)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load agent context: ",t,"."]})});if(!e)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const n=e.week,r=n.scopes+n.recalls+n.lessonsTold+n.reuse.length===0;return i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"What Rigour gave your agents"}),i.jsx("p",{className:"st-lead",children:"Before an agent writes, it can ask Rigour where to look, what this team already knows, and whether the thing it is about to write exists. Preventing a mistake is cheaper than catching it."}),r?i.jsx("div",{className:"st-empty",style:{marginTop:24},children:"No agent asked Rigour for context this week. Agents use it through the Rigour tools (rigour_context_scope, rigour_recall, rigour_check_pattern); Setup shows whether they are connected."}):i.jsxs("div",{className:"st-grid",style:{gridTemplateColumns:"repeat(2, minmax(0, 1fr))"},children:[i.jsx(ga,{title:"Where to look",value:n.scopes===0?"Not asked this week":`${O(n.filesReturned,"file")} instead of ${n.filesConsidered}`,detail:n.scopes===0?"Agents can ask for the files a task needs instead of reading broadly.":`${O(n.scopes,"request")}. About ${va(n.tokensReturned)} tokens returned out of ${va(n.tokensConsidered)} considered (Rigour's estimate).`}),i.jsx(ga,{title:"What this team knows",value:`${O(n.lessonsTold,"lesson")} told`,detail:`${O(n.recalls,"recall")} of saved facts and lessons. How it learns shows what each lesson stopped.`}),i.jsxs("section",{className:"st-card",style:{gridColumn:"1 / -1"},children:[i.jsx("strong",{children:"Pointed to code that already exists"}),n.reuse.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:"No duplicate was about to be written this week."}):i.jsx("div",{className:"st-stack",style:{marginTop:12},children:n.reuse.map(s=>i.jsxs("div",{className:"st-row",style:{alignItems:"flex-start"},children:[i.jsx("span",{className:`st-chip ${s.action==="BLOCK"?"warn":""}`,children:s.action==="BLOCK"?"reuse":"similar"}),i.jsxs("div",{style:{flex:1,fontSize:14,lineHeight:1.5},children:["About to write ",i.jsx("span",{className:"st-mono",children:s.planned}),"; told to use ",i.jsx("span",{className:"st-mono",children:s.existing})]}),i.jsx("span",{className:"st-sub",children:gt(s.at)})]},`${s.at}-${s.planned}`))})]})]}),i.jsx(fh,{weeks:e.weeks})]})},ga=({title:e,value:t,detail:n})=>i.jsxs("section",{className:"st-card",children:[i.jsx("div",{className:"st-sub",children:e}),i.jsx("div",{style:{fontSize:22,fontWeight:600,marginTop:6,color:"var(--text-primary)"},children:t}),i.jsx("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:n})]}),fh=({weeks:e})=>{const t=e.filter(n=>n.scopes+n.recalls+n.lessonsTold+n.reuse>0).reverse();return i.jsxs("section",{className:"st-card",style:{marginTop:24,padding:0,overflowX:"auto"},children:[i.jsx("div",{style:{padding:"16px 20px 8px"},children:i.jsx("strong",{children:"Last 8 weeks"})}),t.length===0?i.jsx("div",{className:"st-sub",style:{padding:"0 20px 18px"},children:"No context requests in the last 8 weeks."}):i.jsxs("table",{className:"st-table",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Week of"}),i.jsx("th",{children:"Focused file lists"}),i.jsx("th",{children:"Files given"}),i.jsx("th",{children:"Recalls"}),i.jsx("th",{children:"Lessons told"}),i.jsx("th",{children:"Duplicates avoided"})]})}),i.jsx("tbody",{children:t.map(n=>i.jsxs("tr",{children:[i.jsx("td",{children:new Date(n.from).toLocaleDateString(void 0,{month:"short",day:"numeric"})}),i.jsx("td",{children:n.scopes}),i.jsx("td",{children:n.scopes?`${n.filesReturned} of ${n.filesConsidered}`:"—"}),i.jsx("td",{children:n.recalls}),i.jsx("td",{children:n.lessonsTold}),i.jsx("td",{children:n.reuse})]},n.from))})]})]})},sl={single:"one judge",cross:"one judge from another vendor",full:"one judge per vendor, findings merged",panel:"a panel: only what a majority confirms blocks"},ph=e=>e.file?`${e.file}${e.line?`:${e.line}`:""}`:"",hh=({data:e,canWrite:t,onChange:n})=>{var s,l,o,a;const r=(s=e.status)==null?void 0:s.last;return i.jsxs("section",{style:{marginTop:24},children:[i.jsxs("h2",{style:{margin:"0 0 12px",fontSize:18,fontWeight:600},children:["The reviewer's verdict on ",e.branch]}),((l=e.status)==null?void 0:l.running)&&i.jsxs("div",{className:"st-sub",style:{marginBottom:8},children:["Reviewing ",e.status.running.head.slice(0,9)," now."]}),((o=e.status)==null?void 0:o.attempt)&&i.jsxs("div",{className:"st-card",style:{marginBottom:12},children:[i.jsx("span",{className:"st-chip warn",children:e.status.attempt.outcome==="skipped"?"skipped":"could not run"})," ",i.jsxs("span",{className:"st-sub",children:["The last review, of ",e.status.attempt.head.slice(0,9)," ",gt(e.status.attempt.at),": ",e.status.attempt.reason]})]}),r?i.jsxs("div",{className:"st-stack",children:[i.jsx("div",{className:"st-card st-row",style:{justifyContent:"space-between"},children:i.jsxs("span",{children:[i.jsx("span",{className:`st-chip ${r.open.length?"bad":"ok"}`,children:r.open.length?`${O(r.open.length,"finding")} to fix`:"nothing to fix"})," ",i.jsxs("span",{className:"st-sub",children:[r.ran?`${sl[r.ran.ran]??r.ran.ran}, `:"",r.mode==="delta"?"new commits":"the whole branch"," at ",r.head.slice(0,9),", ",gt(r.at)]})]})}),r.ran&&(r.ran.degraded||r.ran.escalation||r.ran.asked!==r.ran.ran)&&i.jsxs("div",{className:"st-sub",children:["Asked for ",sl[r.ran.asked]??r.ran.asked," (",r.ran.source,"); ran ",sl[r.ran.ran]??r.ran.ran,". ",[r.ran.degraded,r.ran.escalation].filter(Boolean).join("; ")]}),r.open.map(u=>i.jsx(ya,{item:u,canWrite:t&&e.effective.dismissals,onChange:n},u.id)),r.disputed.length>0&&i.jsx("div",{className:"st-sub",style:{marginTop:8},children:"No majority, so these never block:"}),r.disputed.map(u=>i.jsx(ya,{item:u,disputed:!0,canWrite:!1,onChange:n},u.id))]}):!((a=e.status)!=null&&a.attempt)&&i.jsxs("div",{className:"st-empty",children:["No verdict yet. Run ",i.jsx("span",{className:"st-mono",children:"rigour review --reviewer"}),", or push with the reviewer on."]})]})},ya=({item:e,disputed:t,canWrite:n,onChange:r})=>{const[s,l]=_.useState(""),[o,a]=_.useState(!1),[u,d]=_.useState(null),v=async()=>{const m=await We("/api/reviewer/dismiss","POST",JSON.stringify({id:e.id,reason:s}));m.ok?r():d((await m.json().catch(()=>({}))).error??`HTTP ${m.status}`)};return i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between",gap:12},children:[i.jsx("strong",{style:{fontSize:14},children:e.issue}),i.jsx("span",{className:"st-mono st-sub",children:ph(e)})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:6},children:[t?i.jsx("span",{className:"st-chip warn",children:"disputed"}):i.jsx("span",{className:"st-chip",children:e.class}),e.reviewer&&i.jsxs(i.Fragment,{children:[" found by ",e.reviewer.split("+").join(" and ")]})]}),e.consequence&&i.jsxs("div",{style:{marginTop:8,fontSize:14},children:["What goes wrong: ",e.consequence]}),e.evidence&&i.jsx("div",{className:"st-mono st-sub",style:{marginTop:6},children:e.evidence}),n&&e.kind!=="prior"&&(o?i.jsxs("div",{className:"st-row",style:{marginTop:10,gap:8},children:[i.jsx("input",{"aria-label":"Why it is not a bug",value:s,onChange:m=>l(m.target.value),placeholder:"Why it is not a bug",style:{flex:1,minHeight:36,padding:"0 10px",borderRadius:8,border:"1px solid var(--text-dim)",background:"var(--bg-card)",color:"var(--text-primary)"}}),i.jsx("button",{className:"st-btn",disabled:s.trim().length<5,onClick:v,children:"Dismiss"})]}):i.jsx("button",{className:"st-btn",style:{marginTop:10},onClick:()=>a(!0),children:"Not a bug"})),u&&i.jsxs("div",{className:"st-sub",style:{marginTop:6},children:[i.jsx("span",{className:"st-chip bad",children:"not dismissed"})," ",u]})]})},as=({label:e,value:t,options:n,disabled:r,withTeam:s,onChange:l})=>{const o=s?[{value:null,label:"Team"},...n]:n,a=t===void 0?null:t;return i.jsx("div",{className:"st-seg",role:"radiogroup","aria-label":e,children:o.map(u=>{const d=JSON.stringify(u.value)===JSON.stringify(a);return i.jsx("button",{type:"button",role:"radio","aria-checked":d,className:d?"on":"",disabled:r,onClick:()=>!d&&l(u.value),children:u.label},u.label)})})},mh={flag:"this run",env:"environment",user:"yours",team:"team"};function vh(e,t){return e.key==="mode"?t.source.mode:e.key==="panel"?t.source.panel:e.key==="escalate"&&(t.required.panel||t.required.mode)?"team":e.user&&e.user.value!==void 0?"user":"team"}const ll=[{value:!0,label:"on"},{value:!1,label:"off"}],xa=[{value:"single",label:"one judge"},{value:"cross",label:"one, another vendor"},{value:"full",label:"one per vendor"}],gh=({data:e,canWrite:t,saving:n,onSave:r,onSaveTeam:s})=>{const[l,o]=_.useState(!1),a=e.effective,u=e.team,d=a.required.panel||a.required.mode,v=[{key:"enabled",label:"Review at push",help:"Ask the reviewer when you push a branch that has an open pull request.",effective:a.enabled?"on":"off",user:{value:e.user.enabled,options:ll},team:{value:u.enabled??!1,options:ll}},{key:"mode",label:"Mode",help:"One judge; one from a vendor that did not write the code; or one judge per vendor (up to Judges), findings merged.",effective:a.mode,user:{value:e.user.mode,options:xa},team:{value:u.mode??"single",options:xa},locked:a.required.mode?"your team requires at least this":void 0},{key:"mode_required",label:"Required for everyone",help:"No person or run may review with fewer judges than the team's, in CI or anywhere.",effective:a.required.mode?"yes":"no",team:{value:u.mode_required??!1,options:[{value:!0,label:"yes"},{value:!1,label:"no"}]}},{key:"panel",label:"Panel",help:"Judges cross-examine what only one of them found; only what a majority confirms blocks. Required: no one may turn it off.",effective:a.panel?"on":"off",user:{value:e.user.panel,options:ll},team:{value:u.panel??"off",options:[{value:"off",label:"off"},{value:"on",label:"on"},{value:"required",label:"required"}]},locked:a.required.panel?"your team requires the panel":void 0},{key:"dismissals",label:"Dismissals",help:'Whether people may mark a reviewer finding "not a bug". Off: a wrong finding is fixed by improving the reviewer, a right one by fixing the code.',effective:a.dismissals?"allowed":"off",team:{value:u.dismissals??!1,options:[{value:!0,label:"allowed"},{value:!1,label:"off"}]}},{key:"judges",label:"Judges",help:"How many judges a full or panel review uses, each from a different vendor. Three give a real majority.",effective:String(a.judges),user:{value:e.user.judges,options:[{value:2,label:"2"},{value:3,label:"3"}]},team:{value:u.judges??2,options:[{value:2,label:"2"},{value:3,label:"3"}]}},{key:"escalate",label:"When to add judges",help:"Always, or only for a risky change or one a person has reviewed. The backtest shows whether that loses anything.",effective:a.escalate,user:{value:e.user.escalate,options:[{value:"always",label:"always"},{value:"risk",label:"when risky"}]},team:{value:u.escalate??"always",options:[{value:"always",label:"always"},{value:"risk",label:"when risky"}]},locked:d?"your team requires every review to be full":void 0}],m=t&&(e.teamFile||l);return i.jsxs(i.Fragment,{children:[i.jsxs("p",{className:"st-sub",style:{margin:"0 0 12px",lineHeight:1.6},children:[i.jsx("strong",{children:"Yours"})," applies to your own runs, in every repository on this machine, and wins over the team's except where the team set a floor. ",i.jsx("strong",{children:"Team"})," is"," ",e.teamFile?i.jsxs(i.Fragment,{children:["in ",i.jsx("span",{className:"st-mono",children:"rigour.yml"}),": a change here edits the file, and you commit it"]}):i.jsxs(i.Fragment,{children:["Rigour's defaults: this repository has no ",i.jsx("span",{className:"st-mono",children:"rigour.yml"})]}),".",!t&&" Open Studio from the link the terminal printed to change settings here."]}),t&&!e.teamFile&&!l&&i.jsxs("div",{className:"st-card st-row",style:{justifyContent:"space-between",marginBottom:12},children:[i.jsxs("span",{className:"st-sub",children:["Setting team defaults creates a ",i.jsx("span",{className:"st-mono",children:"rigour.yml"}),": from then on this repository uses the team setup."]}),i.jsx("button",{className:"st-btn",onClick:()=>o(!0),children:"Set team defaults"})]}),i.jsx("div",{className:"st-stack",children:v.map(h=>i.jsxs("div",{className:"st-card st-setting",children:[i.jsxs("div",{children:[i.jsx("div",{style:{fontSize:15},children:h.label}),i.jsx("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.5},children:h.help})]}),i.jsxs("div",{className:"st-setting-controls",children:[i.jsx("span",{className:"st-sub",children:"Runs"}),i.jsxs("span",{children:[i.jsx("span",{className:"st-mono",children:h.effective})," ",i.jsxs("span",{className:"st-sub",children:["· ",mh[vh(h,a)]]}),h.locked&&i.jsxs("span",{title:h.locked,"aria-label":h.locked,children:[" ",i.jsx(Cs,{size:12})]})]}),i.jsx("span",{className:"st-sub",children:"Yours"}),h.user?i.jsx(as,{label:`Your ${h.label}`,withTeam:!0,disabled:!t||n!==null,value:h.user.value,options:h.user.options,onChange:y=>r({[h.key]:y})}):i.jsx("span",{className:"st-sub",children:"set by the team only"}),i.jsx("span",{className:"st-sub",children:"Team"}),i.jsx(as,{label:`Team ${h.label}`,disabled:!m||n!==null,value:h.team.value,options:h.team.options,onChange:y=>s({[h.key]:y},!e.teamFile)})]})]},h.key))}),i.jsx(yh,{data:e}),a.refused.length>0&&i.jsx("div",{className:"st-stack",style:{marginTop:12},children:a.refused.map(h=>i.jsxs("div",{className:"st-sub",children:[i.jsx("span",{className:"st-chip warn",children:"not applied"})," ",h]},h))})]})},Uc=({diff:e})=>i.jsxs("div",{className:"st-card",style:{marginTop:12},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{style:{fontSize:14},children:"rigour.yml changed"}),i.jsx("span",{className:"st-sub",children:"Commit it so the change reaches your team."})]}),i.jsx("pre",{className:"st-code",style:{marginTop:8},children:e.split(`
|
|
166
|
-
`).map((t,n)=>i.jsx("div",{className:`st-ln ${t.startsWith("+")?"add":t.startsWith("-")?"del":""}`,children:t},n))})]}),yh=({data:e})=>{var s;const t=((s=e.status)==null?void 0:s.today)??{runs:0,usd:0},{max_runs_per_day:n,max_usd_per_day:r}=e.effective;return i.jsxs("div",{className:"st-card",style:{marginTop:12},children:[i.jsx("div",{style:{fontSize:15},children:"Today in this repository"}),i.jsxs("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.6},children:[O(t.runs,"agent run"),n!==void 0?` of ${n} allowed`:"",t.usd||r!==void 0?`, $${t.usd.toFixed(2)} reported${r!==void 0?` of $${r.toFixed(2)}`:""}`:"","."," ",n===void 0&&r===void 0?i.jsxs(i.Fragment,{children:["No daily cap: set ",i.jsx("span",{className:"st-mono",children:"max_runs_per_day"})," or ",i.jsx("span",{className:"st-mono",children:"max_usd_per_day"})," in ",i.jsx("span",{className:"st-mono",children:"rigour.yml"}),"."]}):"Past a cap, reviews are skipped until tomorrow (or cannot run, where your team requires the reviewer)."]})]})},xh=({data:e})=>{const t=new Set(e.available.filter(r=>r.installed&&e.effective.reviewers.includes(r.name)).map(r=>r.vendor)).size,n=e.effective.required.panel||e.effective.required.mode;return i.jsxs("section",{style:{marginTop:20},children:[i.jsx("h3",{style:{margin:"0 0 6px",fontSize:15,fontWeight:600},children:"Agent CLIs on this machine"}),i.jsxs("p",{className:"st-sub",style:{margin:"0 0 12px"},children:["The reviewer uses their own logins: no API key. ",t>=3?"Enough vendors for three judges.":t===2?"Enough for two judges; a third vendor, listed in the reviewers, allows three.":n?"Your team requires two judges from different vendors: with one, the review cannot run until another is installed.":"Two judges need two vendors; with one, the review runs with one judge and says so."]}),i.jsx("div",{className:"st-row",style:{flexWrap:"wrap",gap:8},children:e.available.map(r=>i.jsxs("span",{className:`st-chip ${r.installed?"ok":""}`,children:[r.binary,r.installed?` ${r.version??""}`:": not installed"]},r.name))})]})};function Bc(){return ge("/api/reviewer")}const wh=()=>{const{data:e,error:t,reload:n}=Bc();return t?i.jsxs("div",{className:"st-empty",children:["Couldn't load the reviewer's verdict: ",t,"."]}):e?i.jsx(hh,{data:e,canWrite:Ts(),onChange:n}):i.jsx("div",{className:"st-sub",children:"Loading…"})},kh=()=>{const{data:e,error:t,reload:n}=Bc(),[r,s]=_.useState(null),[l,o]=_.useState(null),[a,u]=_.useState(null);if(t)return i.jsxs("div",{className:"st-empty",children:["Couldn't load the reviewer's settings: ",t,"."]});if(!e)return i.jsx("div",{className:"st-sub",children:"Loading…"});const d=async(v,m,h)=>{s(h),o(null);const y=await We(v,"POST",JSON.stringify(m)),w=await y.json().catch(()=>({}));y.ok?v.endsWith("/team")&&u(w.diff??null):o(w.error??`HTTP ${y.status}`),s(null),n()};return i.jsxs("section",{style:{marginTop:32},children:[i.jsx("h2",{style:{margin:"0 0 6px",fontSize:18,fontWeight:600},children:"The reviewer"}),i.jsx("p",{className:"st-sub",style:{margin:"0 0 12px",lineHeight:1.6},children:"A second opinion from other AI models, before a person reviews. Off until your team or you turn it on. With two or three judges from different vendors, a finding blocks only when most of them agree and it names what goes wrong."}),i.jsx(gh,{data:e,canWrite:Ts(),saving:r,onSave:v=>d("/api/reviewer/settings",v,Object.keys(v)[0]),onSaveTeam:(v,m)=>d("/api/reviewer/team",{patch:v,create:m},`team:${Object.keys(v)[0]}`)}),l&&i.jsxs("div",{className:"st-card",style:{marginTop:12},children:[i.jsx("span",{className:"st-chip bad",children:"not saved"})," ",i.jsx("span",{className:"st-sub",children:l})]}),a&&i.jsx(Uc,{diff:a}),i.jsx(xh,{data:e})]})},jh=e=>e==="agent"?"your agent":e==="human"?"you":e.replace(/^byok:/,""),Nh=()=>{const{data:e,error:t}=ge("/api/pre-pr-review");return t?i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load reviews: ",t,"."]})}):e?i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"Review before the PR"}),i.jsx("p",{className:"st-lead",children:"What still stands between this branch and a person's review: the reviewer's verdict, then the risky functions your agent checked."}),i.jsx(wh,{}),i.jsx("h2",{style:{margin:"32px 0 6px",fontSize:18,fontWeight:600},children:"Risky functions your agent checks"}),i.jsxs("p",{className:"st-sub",style:{margin:0,lineHeight:1.6},children:["Rigour picks the riskiest changed functions and asks specific questions about them. Your agent answers with its own model, or you do.",e.reviewed.total>0&&` So far: ${O(e.reviewed.total,"function")} reviewed, ${e.reviewed.fixed} fixed, ${e.reviewed.noIssue} with no issue.`]}),i.jsxs("section",{style:{marginTop:24},children:[i.jsx("h3",{style:{margin:"0 0 12px",fontSize:15,fontWeight:600},children:"Waiting"}),e.pending.length===0?i.jsx("div",{className:"st-empty",children:"No risky function in the current changes is waiting."}):i.jsx("div",{className:"st-stack",children:e.pending.map(n=>i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{className:"st-mono",style:{fontSize:14},children:n.function}),i.jsxs("span",{className:"st-mono st-sub",children:[n.file,":",n.start]})]}),i.jsx("ul",{style:{margin:"10px 0 0",paddingLeft:18,lineHeight:1.6,fontSize:14},children:n.questions.map(r=>i.jsx("li",{children:r},r))})]},`${n.file}:${n.function}`))})]}),i.jsxs("section",{style:{marginTop:28},children:[i.jsx("h3",{style:{margin:"0 0 12px",fontSize:15,fontWeight:600},children:"Checked"}),e.recent.length===0?i.jsx("div",{className:"st-empty",children:"Nothing reviewed yet. Agents review through rigour_review; you can run rigour review-task."}):i.jsx("div",{className:"st-stack",children:e.recent.map(n=>i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsxs("span",{children:[i.jsx("span",{className:`st-chip ${n.verdict==="fixed"?"ok":""}`,children:n.verdict==="fixed"?"fixed":n.verdict==="no_issue"?"no issue":n.verdict})," ",i.jsx("strong",{className:"st-mono",style:{fontSize:14,marginLeft:8},children:n.function})]}),i.jsxs("span",{className:"st-sub",children:[jh(n.reviewer)," · ",gt(n.at)]})]}),i.jsx("div",{className:"st-mono st-sub",style:{marginTop:6},children:n.file}),n.note&&i.jsx("div",{style:{marginTop:10,fontSize:14,lineHeight:1.6},children:n.note})]},`${n.file}:${n.function}:${n.at}`))})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:24},children:["Model reviews with your own key: ",e.spend.runs===0?"none run here":`${O(e.spend.runs,"run")}, ${Sh(e.spend)}${e.lastModel?`, last with ${e.lastModel}`:""}`,"."]})]}):i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})})};function Sh(e){return e.runs-e.unpricedRuns===0?"cost not reported by the provider":`$${e.costUsd.toFixed(2)} observed${e.unpricedRuns?` (${e.unpricedRuns} without a reported cost)`:""}`}const wa={stopped:{label:"blocked",cls:"warn"},reported:{label:"reported",cls:"warn"},fixed:{label:"fixed",cls:"ok"},checked:{label:"checked",cls:""},reviewed:{label:"reviewed",cls:""},taught:{label:"told",cls:""},pr:{label:"PR",cls:"warn"}},il=e=>new Date(e).toLocaleTimeString(void 0,{hour:"numeric",minute:"2-digit"}),Ch=e=>new Date(e).toLocaleDateString(void 0,{weekday:"long",month:"short",day:"numeric"}),Th=()=>{const{data:e,error:t}=ge("/api/activity");return t?i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load activity: ",t,"."]})}):e?i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"Activity"}),i.jsx("p",{className:"st-lead",children:"Each block is one stretch of agent work. What Rigour blocked, reported or got fixed is listed; routine checks fold away."}),e.sessions.length===0?i.jsx("div",{className:"st-empty",style:{marginTop:24},children:"Nothing yet. Activity appears as agents edit code, ask for reviews and finish their work."}):i.jsx("div",{className:"st-stack",style:{marginTop:24,gap:16},children:e.sessions.map(n=>i.jsx(Eh,{session:n},n.start))})]}):i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})})},Eh=({session:e})=>{const[t,n]=_.useState(!1),r=e.counts,s=r.fixed+r.reviewedFixed,l=[s&&`${O(s,"problem")} fixed`,r.stopped&&`${O(r.stopped,"edit")} blocked`,r.reported&&`${O(r.reported,"edit")} reported on`,r.pr&&`${O(r.pr,"branch review")} with findings`,r.reviewed&&`${O(r.reviewed,"risky function")} reviewed${r.reviewed-r.reviewedFixed?` (${r.reviewed-r.reviewedFixed} fine)`:""}`,r.checked&&`${O(r.checked,"edit")} checked clean`,r.taught&&`lessons given ${O(r.taught,"time")}`].filter(Boolean).join(" · ");return i.jsxs("section",{className:"st-card",style:{padding:0},children:[i.jsxs("div",{style:{padding:"16px 20px",borderBottom:e.highlights.length||t?"1px solid var(--border-dim)":0},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsxs("strong",{children:[Ch(e.start),", ",il(e.start),e.start!==e.end?`–${il(e.end)}`:""]}),e.rest.length>0&&i.jsx("button",{className:"st-btn",onClick:()=>n(!t),type:"button",style:{minHeight:32},children:t?"Hide routine":`Show ${O(e.rest.length,"routine item")}`})]}),i.jsx("div",{className:"st-sub",style:{marginTop:6},children:l})]}),[...e.highlights,...t?e.rest:[]].map((o,a)=>i.jsxs("div",{className:"st-row",style:{padding:"12px 20px",borderTop:a?"1px solid var(--border-dim)":0,alignItems:"flex-start"},children:[i.jsx("span",{className:`st-chip ${o.kind==="reviewed"&&o.text.startsWith("Fixed ")?"ok":wa[o.kind].cls}`,style:{minWidth:70,textAlign:"center"},children:o.kind==="reviewed"&&o.text.startsWith("Fixed ")?"fixed":wa[o.kind].label}),i.jsxs("div",{style:{flex:1,minWidth:0},children:[i.jsx("div",{style:{fontSize:14,lineHeight:1.5},children:fn(o.text)}),o.detail&&i.jsx("div",{className:"st-sub",style:{marginTop:3,lineHeight:1.5},children:o.detail})]}),i.jsx("span",{className:"st-sub",style:{whiteSpace:"nowrap"},children:il(o.at)})]},`${o.at}-${a}`))]})},_h={flag:"this run",env:"environment",user:"yours",team:"team"},zh=({text:e,data:t,canWrite:n,saving:r,problem:s,diff:l,onSave:o})=>{const a=t.effective,u=a.required?`your team requires the ${e.name}`:void 0;return i.jsxs("section",{style:{marginTop:32},children:[i.jsx("h2",{style:{margin:"0 0 6px",fontSize:18,fontWeight:600},children:e.title}),i.jsxs("p",{className:"st-sub",style:{margin:"0 0 12px",lineHeight:1.6},children:[e.lead,!n&&" Open Studio from the link the terminal printed to change it here."]}),i.jsxs("div",{className:"st-card st-setting",children:[i.jsxs("div",{children:[i.jsx("div",{style:{fontSize:15},children:e.row}),i.jsx("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.5},children:e.rowHelp})]}),i.jsxs("div",{className:"st-setting-controls",children:[i.jsx("span",{className:"st-sub",children:"Runs"}),i.jsxs("span",{children:[i.jsx("span",{className:"st-mono",children:a.enabled?"on":"off"})," ",i.jsxs("span",{className:"st-sub",children:["· ",_h[a.source]]}),u&&i.jsxs("span",{title:u,"aria-label":u,children:[" ",i.jsx(Cs,{size:12})]})]}),i.jsx("span",{className:"st-sub",children:"Yours"}),i.jsx(as,{label:`Your ${e.name}`,withTeam:!0,disabled:!n||r,value:t.user??void 0,options:[{value:!0,label:"on"},{value:!1,label:"off"}],onChange:d=>o({user:d})}),i.jsx("span",{className:"st-sub",children:"Team"}),i.jsx(as,{label:`Team ${e.name}`,disabled:!n||r,value:t.team,options:[{value:"off",label:"off"},{value:"on",label:"on"},{value:"required",label:"required"}],onChange:d=>o({team:d,create:!t.teamFile})})]})]}),!t.teamFile&&n&&i.jsxs("div",{className:"st-sub",style:{marginTop:8},children:["This repository has no ",i.jsx("span",{className:"st-mono",children:"rigour.yml"}),": setting the team's value creates one, and from then on it uses the team setup."]}),a.refused.length>0&&i.jsx("div",{className:"st-stack",style:{marginTop:12},children:a.refused.map(d=>i.jsxs("div",{className:"st-sub",children:[i.jsx("span",{className:"st-chip warn",children:"not applied"})," ",d]},d))}),s&&i.jsxs("div",{className:"st-card",style:{marginTop:12},children:[i.jsx("span",{className:"st-chip bad",children:"not saved"})," ",i.jsx("span",{className:"st-sub",children:s})]}),l&&i.jsx(Uc,{diff:l})]})},ka={goal:{title:"The goal check",lead:i.jsxs(i.Fragment,{children:["Checks a change against what its pull request says it is for: files outside its ",i.jsx("span",{className:"st-mono",children:"Scope"})," or inside ",i.jsx("span",{className:"st-mono",children:"Out of scope"}),", and"," ",i.jsx("span",{className:"st-mono",children:"Done when"})," items naming a file it never touched, block. No model; a description without these sections is never checked."]}),row:"Check the goal",rowHelp:i.jsxs(i.Fragment,{children:["Required: no person, environment variable or flag may turn it off. ",i.jsx("span",{className:"st-mono",children:"--goal"})," and ",i.jsx("span",{className:"st-mono",children:"--no-goal"})," choose for one run."]}),name:"goal check"},outcomes:{title:"The outcome loop",lead:i.jsxs(i.Fragment,{children:["What happened after each pull request merged: CI on its merge commit, later commits and fixes on its files, a revert. Read with"," ",i.jsx("span",{className:"st-mono",children:"rigour outcomes"}),", one GitHub call per merged pull request until its window closes, then never again."]}),row:"Read outcomes",rowHelp:i.jsxs(i.Fragment,{children:["Required: no person, environment variable or flag may turn it off. ",i.jsx("span",{className:"st-mono",children:"--outcomes"})," and ",i.jsx("span",{className:"st-mono",children:"--no-outcomes"})," choose for one run."]}),name:"outcome loop"},orchestrator:{title:"The review orchestrator",lead:i.jsxs(i.Fragment,{children:["Experimental. Triage, without a model, picks which parts of a review each change needs (earlier human points, correctness, production cost, what the change leaves behind, rules, lessons and the goal), and the judge does only those, in one pass: the same runs as one judge. A change over the judge's limit is split only with what the router has already saved over its last 20 reviews, so on average it never costs more than one judge. A change with nothing for a model to review gets no run. Under required, every part returns or there is no verdict. The daily caps (",i.jsx("span",{className:"st-mono",children:"max_runs_per_day"}),", ",i.jsx("span",{className:"st-mono",children:"max_usd_per_day"}),") count every pass. What blocks is unchanged."]}),row:"Use the orchestrator",rowHelp:i.jsxs(i.Fragment,{children:["Required: no person, environment variable or flag may turn it off. ",i.jsx("span",{className:"st-mono",children:"--orchestrator"})," and ",i.jsx("span",{className:"st-mono",children:"--no-orchestrator"})," choose for one run."]}),name:"review orchestrator"}},ol=({name:e})=>{const t=`/api/switches/${e}`,{data:n,error:r,reload:s}=ge(t),[l,o]=_.useState(!1),[a,u]=_.useState(null),[d,v]=_.useState(null);if(r)return i.jsxs("div",{className:"st-empty",children:["Couldn't load the ",ka[e].name,": ",r,"."]});if(!n)return i.jsx("div",{className:"st-sub",children:"Loading…"});const m=async h=>{o(!0),u(null);const y=await We(t,"POST",JSON.stringify(h)),w=await y.json().catch(()=>({}));y.ok?"team"in h&&v(w.diff??null):u(w.error??`HTTP ${y.status}`),o(!1),s()};return i.jsx(zh,{text:ka[e],data:n,canWrite:Ts(),saving:l,problem:a,diff:d,onSave:m})},Ph={working:"ok","set up":"",broken:"bad",missing:"warn"},Rh=()=>{const{data:e,error:t}=ge("/api/setup");return t?i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't check setup: ",t,"."]})}):e?i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"Setup"}),i.jsxs("p",{className:"st-lead",children:["What runs in this repository, and whether Rigour saw it work this week. The same checks run with ",i.jsx("span",{className:"st-mono",children:"rigour doctor"}),"."]}),i.jsx("div",{className:"st-stack",style:{marginTop:24},children:e.checks.map(n=>i.jsxs("div",{className:"st-card st-row",children:[i.jsx("span",{className:`st-chip ${Ph[n.state]}`,style:{minWidth:72,textAlign:"center"},children:n.state}),i.jsxs("div",{style:{flex:1},children:[i.jsx("div",{style:{fontSize:15},children:n.name}),i.jsx("div",{className:"st-sub",style:{marginTop:4},children:n.detail})]}),n.fix&&n.state!=="working"&&i.jsx("span",{className:"st-mono st-sub",children:n.fix})]},n.id))}),i.jsx(ol,{name:"goal"}),i.jsx(ol,{name:"outcomes"}),i.jsx(ol,{name:"orchestrator"}),i.jsx(kh,{}),i.jsx("h2",{style:{margin:"32px 0 6px",fontSize:18,fontWeight:600},children:"Who double-checks risky code"}),i.jsxs("div",{className:"st-grid",style:{gridTemplateColumns:"repeat(2, minmax(0, 1fr))",marginTop:12},children:[i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:"Your agent's own model"}),i.jsx("span",{children:"Free"})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:["Your agent calls ",i.jsx("span",{className:"st-mono",children:"rigour_review"})," and answers Rigour's questions with the model you already pay for. No key."]})]}),i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:"Your own API key"}),i.jsx("span",{children:"Pay per use"})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:["For code written without an agent, and for PR reviews. ",i.jsx("span",{className:"st-mono",children:"rigour settings set-key"}),"; keys are never shown here."]})]})]})]}):i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Checking…"})})},ja=60,Lh=({request:e,onClose:t})=>{const[n,r]=_.useState(ja),[s,l]=_.useState(null);_.useEffect(()=>{const a=e.timestamp?Date.parse(e.timestamp):Date.now(),u=()=>r(Math.max(0,ja-Math.floor((Date.now()-a)/1e3)));u();const d=window.setInterval(u,1e3);return()=>window.clearInterval(d)},[e.timestamp]);const o=async a=>{const u=await We("/api/arbitrate","POST",JSON.stringify({requestId:e.requestId||e.id,decision:a}));u.ok?t():l(u.status===403?"Studio was opened without the link from your terminal, or the request expired.":`That didn't go through (HTTP ${u.status}).`)};return i.jsx("div",{role:"dialog","aria-modal":"true","aria-label":"Approve a command",style:{position:"fixed",inset:0,background:"rgba(15, 17, 22, 0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:50},children:i.jsxs("div",{className:"st-card",style:{width:"min(560px, calc(100vw - 32px))",padding:24},children:[i.jsx("strong",{style:{fontSize:18},children:"Your agent wants to run a command"}),i.jsx("pre",{className:"st-code st-mono",style:{padding:"12px 14px",marginTop:14,whiteSpace:"pre-wrap"},children:e.command}),e.firewallDecision&&e.firewallDecision!=="allow"&&i.jsxs("div",{className:"st-sub",style:{marginTop:10},children:["Rigour's pre-check: ",e.firewallDecision,e.firewallReason?`: ${e.firewallReason}`:""]}),i.jsx("div",{className:"st-sub",style:{marginTop:10},children:n>0?`Denied automatically in ${n}s if nobody answers.`:"Time ran out: the request was denied."}),s&&i.jsx("div",{className:"st-sub",style:{marginTop:10,color:"var(--status-error)"},children:s}),i.jsxs("div",{className:"st-row",style:{marginTop:18,justifyContent:"flex-end"},children:[i.jsx("button",{className:"st-btn",onClick:t,type:"button",children:"Close"}),i.jsx("button",{className:"st-btn",onClick:()=>o("reject"),type:"button",disabled:n===0,children:"Deny"}),i.jsx("button",{className:"st-btn primary",onClick:()=>o("approve"),type:"button",disabled:n===0,children:"Allow"})]})]})})},Na="rigour-theme-v2",al=[{id:"week",label:"This week",icon:zp,page:e=>i.jsx(Xp,{onNavigate:e})},{id:"progress",label:"Progress",icon:Op,page:()=>i.jsx(nh,{})},{id:"only",label:"Only Rigour",icon:Fp,page:()=>i.jsx(rh,{})},{id:"learns",label:"How it learns",icon:_p,page:()=>i.jsx(uh,{})},{id:"context",label:"Agent context",icon:Cp,page:()=>i.jsx(dh,{})},{id:"reviews",label:"Review",icon:Pp,page:()=>i.jsx(Nh,{})},{id:"activity",label:"Activity",icon:ni,page:()=>i.jsx(Th,{})},{id:"setup",label:"Setup",icon:Hp,page:()=>i.jsx(Rh,{})}],$h=6e4;function Mh(){const[e,t]=_.useState(()=>{try{return localStorage.getItem(Na)||"light"}catch{return"light"}}),[n,r]=_.useState("week"),[s,l]=_.useState(null),[o,a]=_.useState("connecting"),[u,d]=_.useState(null),[v,m]=_.useState(null),[h,y]=_.useState(!0),[w,k]=_.useState(!1),M=_.useCallback(async()=>{y(!0);try{const c=await fetch("/api/health"),p=await c.json();m(c.ok?p:{error:p.error||`HTTP ${c.status}`})}catch(c){m({error:c instanceof Error?c.message:String(c)})}finally{y(!1)}},[]);_.useEffect(()=>{const c=new EventSource("/api/events");return c.onopen=()=>a("live"),c.onerror=()=>a("offline"),c.onmessage=p=>{try{const g=JSON.parse(p.data),j=!g.timestamp||Date.now()-Date.parse(g.timestamp)<$h;g.type==="interception_requested"&&j&&d(g)}catch{}},fetch("/api/info").then(p=>p.json()).then(l).catch(()=>l(null)),()=>c.close()},[]),_.useEffect(()=>{document.documentElement.setAttribute("data-theme",e);try{localStorage.setItem(Na,e)}catch{}},[e]);const f=al.find(c=>c.id===n)??al[0];return i.jsxs("div",{className:"studio",children:[i.jsxs("aside",{className:"sidebar glass-shell",children:[i.jsxs("div",{className:"brand",children:[i.jsx("div",{className:"logo-icon",children:i.jsx($p,{size:18})}),i.jsx("span",{children:"Rigour"}),(s==null?void 0:s.studioVersion)&&i.jsxs("div",{className:"version-pill",children:["v",s.studioVersion]})]}),i.jsx("nav",{children:al.map(c=>i.jsxs("button",{className:`nav-item ${c.id===f.id?"active":""}`,onClick:()=>r(c.id),type:"button",children:[i.jsx(c.icon,{size:18}),i.jsx("span",{children:c.label})]},c.id))}),s&&i.jsx("div",{className:"sidebar-footer",children:i.jsxs("div",{className:"trust-indicator",title:s.teamSync?"Lessons your team promotes are shared through your team store":"Nothing leaves this machine",children:[i.jsx(Cs,{size:14}),i.jsx("span",{children:s.teamSync?"Synced with your team":"Stored on this machine"})]})})]}),i.jsxs("main",{className:"main-content",children:[i.jsxs("header",{className:"glass-shell",children:[i.jsx("div",{className:"header-left",children:s&&i.jsx(Wp,{name:s.projectName,branch:s.branch})}),i.jsxs("div",{className:"header-right",children:[i.jsx("button",{type:"button",className:"connection-status",onClick:()=>{k(c=>!c),M()},"aria-expanded":w,title:"Studio receives Rigour's events live",children:i.jsxs("div",{className:`status-indicator ${o}`,children:[i.jsx("div",{className:"pulse-emitter"}),i.jsx("span",{children:o==="live"?"Live":o==="offline"?"Offline":"Connecting"})]})}),i.jsx("button",{className:"theme-toggle",onClick:()=>t(c=>c==="dark"?"light":"dark"),"aria-label":"Toggle theme",type:"button",children:e==="dark"?i.jsx(Mp,{size:18}):i.jsx(Rp,{size:18})})]})]}),w&&i.jsxs("div",{className:"health-popover",children:[i.jsxs("div",{className:"health-popover-title",children:[i.jsx("strong",{children:"Rigour system health"}),i.jsx("button",{type:"button",onClick:()=>k(!1),"aria-label":"Close health",children:i.jsx(Dc,{size:15})})]}),i.jsx(Bp,{data:v,loading:h,stale:!1,onRetry:M})]}),i.jsxs("div",{className:"view-container",children:[!Ts()&&i.jsx(Up,{}),i.jsx(Ap,{resetKey:f.id,children:i.jsx("div",{className:"full-view",children:f.page(r)})})]})]}),u&&i.jsx(Lh,{request:u,onClose:()=>d(null)})]})}Qp();ul.createRoot(document.getElementById("root")).render(i.jsx(oi.StrictMode,{children:i.jsx(Mh,{})}));
|
|
165
|
+
*/const Dc=q("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);class Ap extends oi.Component{constructor(){super(...arguments);bi(this,"state",{error:null})}static getDerivedStateFromError(n){return{error:n}}componentDidUpdate(n){n.resetKey!==this.props.resetKey&&this.state.error&&this.setState({error:null})}render(){return this.state.error?i.jsxs("div",{className:"empty-state glass-card",role:"alert",children:[i.jsx(Ip,{size:48}),i.jsx("h3",{children:"This view could not be displayed"}),i.jsx("p",{children:this.state.error.message||"Studio received data it could not render."}),i.jsxs("button",{className:"refresh-btn",type:"button",onClick:()=>this.setState({error:null}),children:[i.jsx(Fc,{size:16})," Retry view"]})]}):this.props.children}}function Wp({name:e,branch:t}){return i.jsxs("div",{className:"project-identity",children:[i.jsx(Ep,{size:14,className:"folder-icon"}),i.jsx("span",{className:"project-name",children:e}),t&&i.jsx("span",{className:"project-version-pill",title:"Current branch",children:t})]})}const da="rigour-readonly-note-hidden";function Up(){const[e,t]=_.useState(()=>{try{return sessionStorage.getItem(da)==="1"}catch{return!1}});if(e)return null;const n=()=>{try{sessionStorage.setItem(da,"1")}catch{}t(!0)};return i.jsxs("div",{className:"overview-banner readonly-note",role:"note",children:[i.jsx(Cs,{size:16}),i.jsxs("span",{children:["Read-only. Open the link ",i.jsx("code",{children:"rigour studio"})," printed in your terminal: it gives this tab edit rights."]}),i.jsx("button",{className:"readonly-note-close",onClick:n,type:"button","aria-label":"Hide this note",children:i.jsx(Dc,{size:14})})]})}function Dt({icon:e,label:t,status:n,detail:r}){const s=["ready","active","online","local"].includes(n)?"ready":["warming","idle","missing"].includes(n)?"warming":"degraded";return i.jsxs("div",{className:`health-item ${s}`,children:[i.jsx(e,{size:15,"aria-hidden":"true"}),i.jsxs("span",{children:[i.jsx("strong",{children:t}),i.jsx("small",{children:r})]}),i.jsx("span",{className:"health-state",children:n})]})}function Bp({data:e,loading:t,stale:n,onRetry:r}){var l,o,a,u,d,v,m,h,y,w,k,M,f,c,p,g,j;if(t&&!e)return i.jsxs("div",{className:"system-health loading",children:[i.jsx(ni,{size:16,className:"spinning"})," Checking system health…"]});if(!e||e.error)return i.jsxs("div",{className:"system-health unavailable",role:"alert",children:[i.jsx(ca,{size:16})," Health unavailable",i.jsxs("button",{type:"button",onClick:r,children:[i.jsx(Fc,{size:14})," Retry"]})]});const s=Object.values(((l=e.caches)==null?void 0:l.layers)??{}).filter(C=>C>0).length;return i.jsxs("section",{className:`system-health ${n?"stale":""}`,"aria-label":"System health",children:[i.jsx(Dt,{icon:Tp,label:"Index",status:((o=e.index)==null?void 0:o.status)??"missing",detail:`${((a=e.index)==null?void 0:a.patterns)??0} patterns · ${((u=e.index)==null?void 0:u.files)??0} files`}),i.jsx(Dt,{icon:Dp,label:"Graph",status:((d=e.graph)==null?void 0:d.status)??"missing",detail:`${((v=e.graph)==null?void 0:v.nodes)??0} nodes · ${((m=e.graph)==null?void 0:m.edges)??0} edges`}),i.jsx(Dt,{icon:Sp,label:"Semantic",status:((h=e.semantic)==null?void 0:h.status)??"disabled",detail:((y=e.semantic)==null?void 0:y.message)??"Background enrichment"}),i.jsx(Dt,{icon:Lp,label:"Cache",status:((w=e.caches)==null?void 0:w.status)??"warming",detail:`${s}/4 layers populated`}),i.jsx(Dt,{icon:ni,label:"Learning",status:((k=e.learning)==null?void 0:k.status)??"idle",detail:`${((M=e.learning)==null?void 0:M.observations)??0} interactions · ${((f=e.learning)==null?void 0:f.total)??0} lessons`}),i.jsx(Dt,{icon:ca,label:"Storage",status:((c=e.storage)==null?void 0:c.connectivity)??"local",detail:((p=e.storage)==null?void 0:p.connectivity)==="offline"?`${((g=e.storage)==null?void 0:g.queuedChanges)??0} queued`:((j=e.storage)==null?void 0:j.mode)??"local"})]})}const Hc="rigour-studio-key",Vp="x-rigour-studio-key";function Qp(){const e=window.location.hash.match(/(?:^#|&)key=([a-f0-9]+)/);if(e){try{sessionStorage.setItem(Hc,e[1])}catch{}window.history.replaceState(null,"",window.location.pathname+window.location.search)}}function Ts(){return Ac().length>0}function Ac(){try{return sessionStorage.getItem(Hc)??""}catch{return""}}function We(e,t,n,r="application/json"){const s={[Vp]:Ac()};return n!==void 0&&(s["Content-Type"]=r),fetch(e,{method:t,headers:s,body:n})}const Kp=({onHide:e})=>i.jsxs("section",{className:"st-card",style:{marginBottom:28},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between",marginBottom:16},children:[i.jsx("strong",{children:"How Rigour works"}),i.jsx("button",{className:"st-btn",onClick:e,type:"button",children:"Got it"})]}),i.jsxs("div",{className:"st-steps",children:[i.jsxs("div",{className:"st-step",children:[i.jsx("span",{className:"st-num",children:"1"}),i.jsxs("div",{children:["Your agent writes code",i.jsx("div",{className:"st-sub",children:"Claude Code, Cursor, Cline or Windsurf are checked as they edit; any agent at push."})]})]}),i.jsxs("div",{className:"st-step",children:[i.jsx("span",{className:"st-num",children:"2"}),i.jsxs("div",{children:["Rigour checks the change",i.jsx("div",{className:"st-sub",children:"It stops the agent only on problems it can prove."})]})]}),i.jsxs("div",{className:"st-step",children:[i.jsx("span",{className:"st-num",children:"3"}),i.jsxs("div",{children:["Your PR arrives clean",i.jsx("div",{className:"st-sub",children:"A short review catches the rest; with learning on, fixes become lessons."})]})]})]})]}),Wc={edit:"while the agent was writing",review:"when the agent checked its work",stop:"before the agent said done",pr:"at the pull request"};function gt(e,t=Date.now()){const n=Math.round((t-Date.parse(e))/6e4);if(!Number.isFinite(n))return"";if(n<60)return`${Math.max(1,n)} min ago`;const r=Math.round(n/60);return r<48?`${r} h ago`:new Date(e).toLocaleDateString(void 0,{weekday:"short",month:"short",day:"numeric"})}function O(e,t,n=`${t}s`){return`${e} ${e===1?t:n}`}function ge(e){const[t,n]=_.useState(null),[r,s]=_.useState(null),l=_.useCallback(()=>{fetch(e).then(async o=>o.ok?n(await o.json()):s(`HTTP ${o.status}`)).catch(o=>s(o instanceof Error?o.message:String(o)))},[e]);return _.useEffect(l,[l]),{data:t,error:r,reload:l}}function fn(e){return e.split(/(`[^`]+`)/g).map((t,n)=>t.startsWith("`")&&t.endsWith("`")&&t.length>2?oi.createElement("code",{key:n,className:"st-mono st-inline-code"},t.slice(1,-1)):t)}function Yp(e){return e.replace(/(['"`])(?:(?!\1).)*\1/g,"…").replace(/\b\d+(?:\.\d+)?\b/g,"N").replace(/\s+/g," ").trim()}function qp(e){const t=e.reduce((r,s)=>r+s.needs.length,0);if(t===0)return"Nothing needs you.";const n=`${O(t,"finding needs","findings need")} you`;return t===e.length?`${n}.`:`${n}, of ${O(e.length,"kind")}.`}function Gp(e){const t=new Map,n=[...e].sort((r,s)=>Date.parse(s.openedAt)-Date.parse(r.openedAt));for(const r of n){const s=Yp(r.title),l=`${r.rule}\0${s}`,o=t.get(l)??{rule:r.rule,pattern:s,needs:[],files:0};o.needs.push(r),t.set(l,o)}for(const r of t.values())r.files=new Set(r.needs.map(s=>s.file)).size;return[...t.values()]}const Xp=({group:e,onDone:t})=>{const[n,r]=_.useState(!1);return e.needs.length===1?i.jsx(fa,{need:e.needs[0],onDone:t}):i.jsxs("div",{children:[i.jsxs("button",{className:"st-story",onClick:()=>r(!n),type:"button","aria-expanded":n,children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("span",{className:"st-chip warn",children:"open"}),i.jsxs("span",{className:"st-sub",children:["newest ",gt(e.needs[0].openedAt)]})]}),i.jsxs("div",{style:{fontSize:17,marginTop:10,lineHeight:1.5},children:[e.needs.length," × ",e.pattern,", in ",O(e.files,"file")]}),i.jsx("div",{className:"st-mono st-sub",style:{marginTop:6},children:e.rule})]}),n&&i.jsx("div",{className:"st-stack",style:{marginTop:10},children:e.needs.map(s=>i.jsx(fa,{need:s,onDone:t},`${s.rule}:${s.file}:${s.openedAt}`))})]})},fa=({need:e,onDone:t})=>{const[n,r]=_.useState("idle"),s=async()=>{const o=window.prompt("Why is this not a bug? Rigour keeps the reason with the dismissal.");if(!(o!=null&&o.trim())||!e.key)return;(await We("/api/dismiss","POST",JSON.stringify({key:e.key,reason:o}))).ok?t():r("failed")},l=async()=>{try{await navigator.clipboard.writeText(`Rigour found a problem you introduced: ${e.title} in ${e.file}. Fix it, then run rigour review.`),r("copied")}catch{r("failed")}};return i.jsxs("div",{className:"st-need",children:[i.jsxs("div",{className:"st-row",children:[i.jsx("span",{className:"st-chip warn",children:"open"}),i.jsxs("span",{className:"st-sub",children:["found ",e.stage?Wc[e.stage]:""," · ",gt(e.openedAt)]})]}),i.jsx("div",{style:{fontSize:17,marginTop:10,lineHeight:1.5},children:e.title}),i.jsx("div",{className:"st-mono st-sub",style:{marginTop:6},children:e.file}),i.jsxs("div",{className:"st-row",style:{marginTop:14,flexWrap:"wrap"},children:[i.jsx("button",{className:"st-btn primary",onClick:l,type:"button",children:n==="copied"?"Copied: paste it to your agent":"Copy for my agent"}),e.key&&i.jsx("button",{className:"st-btn",onClick:s,type:"button",children:"It's fine, not a bug"}),n==="failed"&&i.jsx("span",{className:"st-sub",children:"That didn't work. Open Studio from the link in your terminal and try again."})]})]})},pa="rigour-intro-hidden",Jp=({onNavigate:e})=>{const{data:t,error:n,reload:r}=ge("/api/week"),[s,l]=_.useState(null),[o,a]=_.useState(()=>{try{return localStorage.getItem(pa)!=="1"}catch{return!0}});if(n)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load this week: ",n,"."]})});if(!t)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const u=()=>{try{localStorage.setItem(pa,"1")}catch{}a(!1)},d=t.needs,v=Gp(d);return i.jsxs("div",{className:"st-page",children:[o&&i.jsx(Kp,{onHide:u}),i.jsx("h1",{className:"st-h1",children:qp(v)}),i.jsx("p",{className:"st-lead",children:t.stopped.total>0?`${O(t.stopped.total,"problem")} stopped and fixed before a pull request this week.`:t.recordingSince?"Nothing was stopped this week.":"Rigour has not recorded any agent work in this repository yet."}),d.length>0&&i.jsx(Zp,{onDone:r}),v.length>0&&i.jsx("div",{className:"st-stack",style:{marginTop:18},children:v.map(m=>i.jsx(Xp,{group:m,onDone:r},`${m.rule}:${m.pattern}`))}),i.jsxs("div",{className:"st-grid",children:[i.jsxs("section",{children:[i.jsx("h2",{style:{margin:"0 0 14px",fontSize:18,fontWeight:600},children:"What Rigour stopped this week"}),t.stories.length===0?i.jsx("div",{className:"st-empty",children:"When an agent fixes something Rigour caught, it appears here with the code change."}):i.jsx("div",{className:"st-stack",children:t.stories.map(m=>i.jsx(bp,{story:m,open:s===m.id,onToggle:()=>l(s===m.id?null:m.id)},m.id))})]}),i.jsxs("aside",{className:"st-side",children:[i.jsxs("div",{className:"st-card",children:[i.jsx("div",{className:"st-big",children:t.stopped.total}),i.jsx("div",{style:{fontSize:14,marginTop:6},children:"stopped before a PR"}),i.jsxs("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:[t.stopped.byStage.edit," while writing · ",t.stopped.byStage.review," on review · ",t.stopped.byStage.stop," before done"]}),i.jsx(eh,{data:t})]}),i.jsxs("div",{className:"st-card",children:[i.jsx("div",{style:{fontSize:15,fontWeight:600},children:"Is it noisy?"}),i.jsx("div",{style:{fontSize:14,marginTop:8,lineHeight:1.6},children:t.raised===0?"Nothing raised this week.":`Rigour raised ${O(t.raised,"problem")} this week. You overruled ${t.overruled}.`}),i.jsx("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:'Say "not a bug" once and Rigour stops raising it.'})]}),i.jsx("button",{className:"st-btn",onClick:()=>e("learns"),type:"button",children:"See how it learns"}),t.recordingSince&&i.jsxs("div",{className:"st-sub",children:["Recording since ",new Date(t.recordingSince).toLocaleDateString()]})]})]})]})},Zp=({onDone:e})=>{const[t,n]=_.useState(null),r=async()=>{const s=await We("/api/recheck","POST","{}");if(!s.ok)return n("Could not check again.");const{closed:l,fixed:o}=await s.json(),a=[o?`${O(o,"fix")} by the agent recorded`:"",l?`${O(l,"finding")} no longer reported, closed (not counted as fixes)`:""].filter(Boolean).join("; ");n(a?`${a}.`:"Every one is still reported."),e()};return i.jsxs("div",{className:"st-row",style:{marginTop:10,gap:12},children:[i.jsx("button",{className:"st-btn",onClick:r,type:"button",children:"Check these again"}),t&&i.jsx("span",{className:"st-sub",children:t})]})},bp=({story:e,open:t,onToggle:n})=>i.jsxs("div",{children:[i.jsxs("button",{className:"st-story",onClick:n,type:"button","aria-expanded":t,children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("span",{className:"st-chip",children:Wc[e.stage]}),i.jsx("span",{className:"st-sub",children:gt(e.at)})]}),i.jsx("div",{style:{fontSize:16,lineHeight:1.55,marginTop:10},children:fn(e.title)}),i.jsxs("div",{className:"st-sub",style:{marginTop:6},children:[i.jsx("span",{className:"st-mono",children:e.file})," · fixed by the agent"]})]}),t&&i.jsxs("div",{className:"st-story-body",children:[e.diff.length>0&&i.jsx("div",{className:"st-code st-mono",children:e.diff.map((r,s)=>i.jsx("span",{className:`st-ln ${r[0]==="+"?"add":r[0]==="-"?"del":""}`,children:r},s))}),e.details&&e.details!==e.title&&i.jsxs("div",{style:{marginTop:e.diff.length?16:0},children:[i.jsx("strong",{style:{fontSize:13},children:e.stage==="review"&&e.rule==="review"?"What the agent fixed":"How Rigour knew"}),i.jsx("div",{className:"st-sub",style:{marginTop:6,lineHeight:1.6},children:fn(e.details)})]})]})]}),eh=({data:e})=>{const[t,n]=_.useState(!1);if(e.stopped.total===0)return null;const r=`Rigour stopped ${O(e.stopped.total,"problem")} before a pull request this week: ${e.stopped.byStage.edit} while the agent was writing, ${e.stopped.byStage.review} when it checked its work, ${e.stopped.byStage.stop} before it said done. ${e.overruled} of ${e.raised} overruled.`,s=async()=>{try{await navigator.clipboard.writeText(r),n(!0)}catch{}};return i.jsx("button",{className:"st-btn",onClick:s,type:"button",style:{marginTop:14,width:"100%"},children:t?"Copied":"Copy this week"})},th=e=>new Date(e).toLocaleDateString(void 0,{month:"short",day:"numeric"}),nl=(e,t)=>e.reduce((n,r)=>n+t(r),0),nh=()=>{var l;const{data:e,error:t}=ge("/api/progress");if(t)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load progress: ",t,"."]})});if(!e)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const n=e.weeks.slice(-4),r=e.weeks.slice(0,-4),s=((l=e.weeks[e.weeks.length-1])==null?void 0:l.lessons)??0;return i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"How Rigour is shaping this code"}),i.jsxs("p",{className:"st-lead",children:["Last 4 weeks: ",O(nl(n,o=>o.stopped),"problem")," stopped before a PR",r.length?` (${nl(r,o=>o.stopped)} in the 4 weeks before)`:"",", ",O(nl(n,o=>o.repeatsStopped),"repeat mistake")," caught,"," ",O(s,"lesson")," learned so far."]}),i.jsxs("div",{className:"st-stack",style:{marginTop:24},children:[i.jsx(Ht,{title:"Stopped before a PR",hint:"fixed by the agent after Rigour reported it",weeks:e.weeks,value:o=>o.stopped}),i.jsx(Ht,{title:"Repeat mistakes stopped",hint:"a mistake Rigour had already learned, caught again before a PR",weeks:e.weeks,value:o=>o.repeatsStopped}),i.jsx(Ht,{title:"Repeat mistakes that reached a PR",hint:"lower is better",weeks:e.weeks,value:o=>o.repeatsReachedPr,empty:"Shows once branch reviews run on this machine, for example rigour review --base main in a pre-push hook."}),i.jsx(Ht,{title:"Minutes from report to fix",hint:"median; lower is better",weeks:e.weeks,value:o=>o.minutesToFix}),i.jsx(Ht,{title:"Overruled",hint:"findings someone marked not a bug",weeks:e.weeks,value:o=>o.overruled}),i.jsx(Ht,{title:"Lessons learned",hint:"total by the end of each week",weeks:e.weeks,value:o=>o.lessons})]}),i.jsxs("div",{className:"st-grid",style:{gridTemplateColumns:"repeat(2, minmax(0, 1fr))"},children:[i.jsxs("section",{className:"st-card",children:[i.jsx("strong",{children:"Lessons that stopped the most repeats"}),e.topLessons.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:"None yet. A lesson ranks here once the mistake it describes is caught again and stopped."}):i.jsx("ol",{style:{margin:"12px 0 0",paddingLeft:20,lineHeight:1.6},children:e.topLessons.map(o=>i.jsxs("li",{style:{marginBottom:8},children:[fn(o.text),i.jsxs("div",{className:"st-sub",children:[O(o.stoppedInDevelopment??0,"repeat")," stopped · ",o.scope==="team"?"shared with team":o.scope]})]},o.id))})]}),i.jsxs("section",{className:"st-card",children:[i.jsx("strong",{children:"Checks your team acts on"}),e.checks.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:'Each fix and each "not a bug" scores the check that raised it. Scores appear after the first one.'}):i.jsx("div",{className:"st-stack",style:{marginTop:12,gap:8},children:e.checks.map(o=>i.jsxs("div",{className:"st-row",style:{gap:10},children:[i.jsxs("span",{style:{width:44,fontWeight:600},children:[Math.round(o.precision*100),"%"]}),i.jsx("span",{style:{flex:1,fontSize:14},children:o.check}),i.jsxs("span",{className:"st-sub",children:[o.fixed," fixed · ",o.dismissed," overruled"]}),o.muted&&i.jsx("span",{className:"st-chip",children:"quiet"})]},o.check))})]})]})]})},Ht=({title:e,hint:t,weeks:n,value:r,empty:s})=>{const l=n.map(r),o=l.filter(u=>u!==null),a=Math.max(1,...o);return i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:e}),i.jsx("span",{className:"st-sub",children:t})]}),o.length===0&&s?i.jsx("div",{className:"st-sub",style:{marginTop:10},children:s}):i.jsx("div",{className:"st-bars",style:{height:90,gap:12},children:n.map((u,d)=>i.jsxs("div",{className:"st-bar",children:[i.jsx("div",{style:{fontSize:12},children:l[d]??"—"}),i.jsx("span",{style:{height:`${l[d]===null?2:Math.max(2,l[d]/a*56)}px`,opacity:l[d]===null?.25:1}}),i.jsx("div",{className:"st-sub",style:{fontSize:11},children:th(u.from)})]},u.from))})]})},rh=()=>{const{data:e,error:t}=ge("/api/week"),n=ge("/api/setup").data,r=n==null?void 0:n.checks.some(l=>l.id==="stop"&&l.state!=="missing"&&l.state!=="broken");if(t)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load: ",t,"."]})});if(!e)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const s=e.stories.filter(l=>l.stage==="stop");return i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"What only Rigour caught"}),i.jsx("p",{className:"st-lead",children:"Counted only where Rigour can show it. A bug stopped before a PR never reached your other reviewers, so it is not counted against them."}),i.jsxs("section",{style:{marginTop:28},children:[i.jsx("h2",{style:{margin:0,fontSize:18,fontWeight:600},children:"Your agent tried to finish with a bug"}),i.jsx("p",{className:"st-lead",style:{fontSize:14},children:e.agentSaidDone===0&&n&&!r?"The stop hook is not set up in this repository, so Rigour cannot see an agent finish. Run rigour setup.":e.agentSaidDone===0?"This week no agent tried to finish with a problem Rigour could prove.":`This week an agent tried to finish with a problem Rigour proved ${O(e.agentSaidDone,"time")}. Each was fixed before the agent stopped.`}),i.jsx("div",{className:"st-stack",style:{marginTop:14},children:s.map(l=>i.jsxs("div",{className:"st-card st-row",children:[i.jsxs("div",{style:{flex:1},children:[i.jsx("div",{style:{fontSize:15,lineHeight:1.5},children:l.title}),i.jsxs("div",{className:"st-sub",style:{marginTop:4},children:[i.jsx("span",{className:"st-mono",children:l.file})," · ",gt(l.at)]})]}),i.jsx("span",{className:"st-chip ok",children:"fixed"})]},l.id))})]}),i.jsxs("section",{style:{marginTop:32},children:[i.jsx("h2",{style:{margin:0,fontSize:18,fontWeight:600},children:"Rigour and your other PR reviewers"}),i.jsxs("div",{className:"st-empty",style:{marginTop:14},children:[e.prCatches===null?"No branch reviews recorded on this machine yet.":`Branch reviews here reported ${O(e.prCatches,"problem")} this week.`," ","Side by side with teammates and review bots (both caught it, only Rigour, only them) needs the PR's review comments; it comes with the PR integration."]})]})]})},sh=()=>i.jsxs("p",{className:"st-lead",children:["Every mistake fixed in development or caught at a PR becomes a lesson. An agent gets the lessons when it asks for a brief (the ",i.jsx("code",{children:"rigour_brief"})," tool, or ",i.jsx("code",{children:"rigour brief"}),"). In Claude Code, ",i.jsx("code",{children:"rigour hooks init --brief"})," hands them over by itself: at a session's first prompt and on each file's first edit."]}),rl=(e,t=!0)=>t?e===null?"not recorded here":e===1?"1 time":`${e} times`:"—",lh=({lesson:e,onDecide:t,onDecideReview:n})=>i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between",alignItems:"flex-start"},children:[i.jsx("div",{style:{fontSize:17,lineHeight:1.5,flex:1},children:fn(e.text)}),i.jsx("span",{className:"st-chip",children:e.scope==="team"?"shared with team":e.scope})]}),i.jsxs("div",{className:"st-journey",children:[i.jsxs("div",{style:{background:"var(--bg-surface)"},children:[i.jsx("div",{className:"st-sub",children:"Learned"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:e.learnedFrom})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Agents told"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:rl(e.told)})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Stopped in development"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:rl(e.stoppedInDevelopment,e.origin==="development")})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Reached a PR again"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:rl(e.reachedPr,e.origin==="development")})]})]}),e.takenBack&&i.jsxs("div",{style:{marginTop:14},children:[i.jsxs("div",{children:[i.jsx("span",{className:"st-chip warn",children:"taken back"})," ",i.jsx("span",{className:"st-sub",children:e.takenBack.detail})]}),i.jsxs("div",{className:"st-row",style:{marginTop:10},children:[i.jsx("span",{className:"st-sub",children:"Later pull requests a review found repeating it merged and stayed fine. Keep telling agents anyway?"}),i.jsx("button",{className:"st-btn primary",onClick:()=>n==null?void 0:n(e.id,"accepted"),type:"button",children:"Promote again"}),i.jsx("button",{className:"st-btn",onClick:()=>n==null?void 0:n(e.id,"rejected"),type:"button",children:"Drop"})]})]}),e.reclassified&&i.jsxs("div",{style:{marginTop:14},children:[i.jsxs("div",{children:[i.jsx("span",{className:"st-chip warn",children:"back to candidate"})," ",i.jsx("span",{className:"st-sub",children:e.reclassified.detail})]}),e.reclassified.evidence.map(r=>i.jsx("div",{className:"st-sub",style:{marginTop:4},children:r},r)),i.jsxs("div",{className:"st-row",style:{marginTop:10},children:[i.jsx("span",{className:"st-sub",children:"A later fix on its lines used to make this a lesson by itself; now a person decides. Keep telling agents?"}),i.jsx("button",{className:"st-btn primary",onClick:()=>n==null?void 0:n(e.id,"accepted"),type:"button",children:"Promote"}),i.jsx("button",{className:"st-btn",onClick:()=>n==null?void 0:n(e.id,"dismissed"),type:"button",children:"Dismiss"})]})]}),e.suggested&&i.jsxs("div",{style:{marginTop:14},children:[i.jsxs("div",{children:[i.jsx("span",{className:"st-chip",children:"a later fix changed these lines"})," ",i.jsx("span",{className:"st-sub",children:e.suggested.detail})]}),i.jsxs("div",{className:"st-row",style:{marginTop:10},children:[i.jsxs("span",{className:"st-sub",children:["The pull request (#",e.suggested.pr,") left this point alone, and a later fix changed its lines. If that fix is about this point, the lesson was right."]}),i.jsx("button",{className:"st-btn primary",onClick:()=>n==null?void 0:n(e.id,"accepted"),type:"button",children:"Promote"}),i.jsx("button",{className:"st-btn",onClick:()=>n==null?void 0:n(e.id,"dismissed"),type:"button",children:"Dismiss"})]})]}),e.canDecide&&!e.takenBack&&!e.suggested&&!e.reclassified&&i.jsxs("div",{className:"st-row",style:{marginTop:14},children:[i.jsx("span",{className:"st-sub",children:e.scope==="team"?"Shared by a teammate. Give it to everyone's agents?":"Seen once. Keep it so your agents get told?"}),i.jsx("button",{className:"st-btn primary",onClick:()=>t(e.id,e.scope==="team"?"promoted":"validated"),type:"button",children:e.scope==="team"?"Share with team":"Keep"}),i.jsx("button",{className:"st-btn",onClick:()=>t(e.id,"rejected"),type:"button",children:"Drop"})]})]}),ih=({model:{share:e,costPerPr:t}})=>i.jsxs("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:["The model reviewer: ",e.model," of ",e.model+e.checks," findings at first review on ",e.prs," pull request",e.prs===1?"":"s",e.rate===null?"":` (${Math.round(e.rate*100)}%)`,", the rest from the free checks."," ","It cost $",t.totalUsd.toFixed(2)," over ",t.prs," pull request",t.prs===1?"":"s",t.medianUsd===null?"":`, $${t.medianUsd.toFixed(2)} each at the median`,".",t.prsEarlierBasis?` ${t.prsEarlierBasis} more reviewed before every run was counted, left out.`:""]}),ha=e=>`${e.count} of ${e.of}${e.rate===null?"":` (${Math.round(e.rate*100)}%)`}`,oh=({numbers:e})=>i.jsxs("section",{className:"st-card",style:{margin:"0 0 24px"},children:[i.jsx("strong",{children:"After the merge"}),i.jsxs("div",{className:"st-sub",style:{marginTop:4},children:[e.records.merged," merged pull requests read on this machine; ",e.records.settled," settled, ",e.records.unsettled," with the window still open."]}),i.jsxs("div",{className:"st-journey",style:{marginTop:10},children:[i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"CI regressed on the merge"}),i.jsxs("div",{style:{fontSize:14,marginTop:4},children:[ha(e.settled.ciRegressed),e.settled.ciUnknown?`, ${e.settled.ciUnknown} with no CI to read`:""]})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Reverted"}),i.jsx("div",{style:{fontSize:14,marginTop:4},children:ha(e.settled.reverted)})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Reviewed by Rigour"}),i.jsxs("div",{style:{fontSize:14,marginTop:4},children:[e.settled.reviewed.prs," pull requests, ",e.settled.reviewed.fixedLater.count," fixed later"]})]}),i.jsxs("div",{children:[i.jsx("div",{className:"st-sub",children:"Not reviewed"}),i.jsxs("div",{style:{fontSize:14,marginTop:4},children:[e.settled.notReviewed.prs," pull requests, ",e.settled.notReviewed.fixedLater.count," fixed later"]})]})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:["Lessons: ",e.lessons.awaitingDecision," waiting on you, ",e.lessons.promotedFromEvidence," promoted from evidence, ",e.lessons.dismissed," dismissed, ",e.lessons.takenBack," taken back."," ","Teams choose which pull requests get reviewed, so the two groups differ: this is not a comparison."]}),e.model&&i.jsx(ih,{model:e.model})]}),ma=e=>`${e.fired} of ${e.n}${e.rate===null?"":` (${Math.round(e.rate*100)}%)`}`,ah=({checks:e,onDecide:t,onPropose:n})=>i.jsxs("section",{className:"st-card",style:{margin:"24px 0"},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:"Lessons compiled into checks"}),i.jsx("button",{className:"st-btn",type:"button",onClick:n,children:"Propose checks"})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.6},children:["A verified lesson that names its file and symbols becomes a check that runs on every review, for free; the model reviewer stops spending prompt on it. A proposed check runs only once you approve it. Who approved it, by git email, is committed with it in ",i.jsx("span",{className:"st-mono",children:".rigour/compiled-checks.json"}),"."]}),e.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10},children:"None yet. Propose checks once a lesson says never, avoid, instead of, always or must about a symbol in backticks."}):i.jsx("div",{className:"st-stack",style:{marginTop:12},children:e.map(r=>i.jsxs("div",{className:"st-need",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("span",{className:`st-chip ${r.suspended?"bad":r.state==="active"?"ok":r.state==="proposed"?"warn":""}`,children:r.suspended?"suspended":r.state}),i.jsx("span",{className:"st-sub st-mono",children:r.files})]}),i.jsx("div",{style:{marginTop:8},children:r.kind==="forbid"?i.jsxs(i.Fragment,{children:["Reports ",i.jsx("code",{children:r.symbol})," on a changed line."]}):i.jsxs(i.Fragment,{children:["Reports ",i.jsx("code",{children:r.symbol})," with no ",i.jsx("code",{children:r.with})," within three lines."]})}),i.jsxs("div",{className:"st-sub",style:{marginTop:4},children:[fn(r.message)," · lesson ",r.lessonId,r.by?` · ${r.state==="withdrawn"?"taken back":"approved"} by ${r.by}`:""]}),r.suspended&&i.jsx("div",{className:"st-sub",style:{marginTop:6},children:r.suspended}),r.backtest&&i.jsxs("div",{className:"st-sub",style:{marginTop:6,lineHeight:1.6},children:["On the last ",r.backtest.commits," merged changes to its files: fires on ",ma(r.backtest.repeating)," where a review found the lesson repeating, and on ",ma(r.backtest.other)," others (each a false fire, or a catch the review missed)."]}),i.jsxs("div",{className:"st-row",style:{marginTop:10,gap:8},children:[r.state!=="active"&&i.jsx("button",{className:"st-btn",type:"button",onClick:()=>t(r.id,"active"),children:"Approve"}),r.state==="active"&&i.jsx("button",{className:"st-btn",type:"button",onClick:()=>t(r.id,"withdrawn"),children:"Take back"})]})]},r.id))})]}),uh=()=>{const{data:e,error:t,reload:n}=ge("/api/learning");if(t)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load lessons: ",t,"."]})});if(!e)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const r=async(u,d)=>{(await We("/api/lessons","POST",JSON.stringify({id:u,state:d}))).ok&&n()},s=async(u,d)=>{(await We("/api/review-lessons","POST",JSON.stringify({id:u,decision:d}))).ok&&n()},l=async(u,d)=>{const v=await We("/api/compiled-checks","POST",JSON.stringify({id:u,state:d}));v.ok?n():window.alert((await v.json().catch(()=>({}))).error??"Could not record the decision.")},o=async()=>{(await We("/api/compiled-checks","POST",JSON.stringify({propose:!0}))).ok&&n()},a=Math.max(1,...e.weeks.map(u=>Math.max(u.stoppedInDevelopment,u.reachedPr??0)));return i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"How Rigour learns your codebase"}),i.jsx(sh,{}),i.jsxs("section",{className:"st-card",style:{margin:"24px 0"},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:"Repeat mistakes, by week"}),i.jsx("span",{className:"st-sub",children:"a mistake Rigour had already learned"})]}),i.jsx("div",{className:"st-bars",children:e.weeks.map(u=>i.jsxs("div",{className:"st-bar",children:[i.jsxs("div",{style:{fontSize:13},children:[u.stoppedInDevelopment," stopped",u.reachedPr===null?"":` · ${u.reachedPr} reached a PR`]}),i.jsx("span",{style:{height:`${Math.max(4,u.stoppedInDevelopment/a*80)}px`}}),i.jsxs("div",{className:"st-sub",children:["from ",new Date(u.from).toLocaleDateString(void 0,{month:"short",day:"numeric"})]})]},u.from))}),!e.prRecorded&&i.jsxs("div",{className:"st-sub",style:{marginTop:14},children:["Repeats that reached a PR show once branch reviews run on this machine (",i.jsx("span",{className:"st-mono",children:"rigour review --base main"}),", for example in a pre-push hook). Reviews in CI stay in CI."]})]}),e.outcomes&&i.jsx(oh,{numbers:e.outcomes}),i.jsx(ah,{checks:e.compiled??[],onDecide:l,onPropose:o}),e.lessons.length===0?i.jsx("div",{className:"st-empty",children:"No lessons yet. They form when an agent fixes something Rigour reported, when a PR comment leads to a fix, or when you tell your agent to remember something."}):i.jsx("div",{className:"st-stack",children:e.lessons.map(u=>i.jsx(lh,{lesson:u,onDecide:r,onDecideReview:s},u.id))}),i.jsx(ch,{})]})},ch=()=>{var r,s,l;const e=ge("/api/learned-rules").data??[],t=Object.entries(((r=ge("/api/memory").data)==null?void 0:r.memories)??{}),n=(l=(s=ge("/api/index-stats").data)==null?void 0:s.stats)==null?void 0:l.totalPatterns;return i.jsxs("div",{className:"st-grid",style:{gridTemplateColumns:"repeat(2, minmax(0, 1fr))"},children:[i.jsxs("section",{className:"st-card",children:[i.jsx("strong",{children:"Rules learned from fixes"}),i.jsx("div",{className:"st-sub",style:{marginTop:4},children:"Checked on every edit, like a built-in check."}),e.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:"None yet. rigour learn turns an agent's fixes into rules once they hold up."}):i.jsx("ul",{style:{margin:"10px 0 0",paddingLeft:18,lineHeight:1.6,fontSize:14},children:e.map(o=>i.jsxs("li",{children:[o.message,i.jsxs("div",{className:"st-sub",children:[o.requirement," · ",o.appliesTo]})]},o.id))})]}),i.jsxs("section",{className:"st-card",children:[i.jsx("strong",{children:"What your agents were told to remember"}),i.jsx("div",{className:"st-sub",style:{marginTop:4},children:"Facts saved with rigour_remember; agents recall them by meaning."}),t.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:10,lineHeight:1.6},children:"Nothing saved yet."}):i.jsx("ul",{style:{margin:"10px 0 0",paddingLeft:18,lineHeight:1.6,fontSize:14},children:t.slice(0,12).map(([o,a])=>i.jsxs("li",{children:[i.jsx("strong",{children:o.replace(/_/g," ")}),": ",a.value.length>220?`${a.value.slice(0,220)}…`:a.value]},o))}),t.length>12&&i.jsxs("div",{className:"st-sub",style:{marginTop:6},children:["and ",t.length-12," more"]})]}),typeof n=="number"&&n>0&&i.jsxs("section",{className:"st-card",style:{gridColumn:"1 / -1"},children:[i.jsxs("strong",{children:[n," functions indexed"]}),i.jsx("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.6},children:"Before an agent writes a new helper, Rigour checks whether one already exists and points to it, so the codebase doesn't fill with near-copies."})]})]})},va=e=>e>=1e3?`${Math.round(e/1e3)}k`:String(e),dh=()=>{const{data:e,error:t}=ge("/api/context");if(t)return i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load agent context: ",t,"."]})});if(!e)return i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})});const n=e.week,r=n.scopes+n.recalls+n.lessonsTold+n.reuse.length===0;return i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"What Rigour gave your agents"}),i.jsx("p",{className:"st-lead",children:"Before an agent writes, it can ask Rigour where to look, what this team already knows, and whether the thing it is about to write exists. Preventing a mistake is cheaper than catching it."}),r?i.jsx("div",{className:"st-empty",style:{marginTop:24},children:"No agent asked Rigour for context this week. Agents use it through the Rigour tools (rigour_context_scope, rigour_recall, rigour_check_pattern); Setup shows whether they are connected."}):i.jsxs("div",{className:"st-grid",style:{gridTemplateColumns:"repeat(2, minmax(0, 1fr))"},children:[i.jsx(ga,{title:"Where to look",value:n.scopes===0?"Not asked this week":`${O(n.filesReturned,"file")} instead of ${n.filesConsidered}`,detail:n.scopes===0?"Agents can ask for the files a task needs instead of reading broadly.":`${O(n.scopes,"request")}. About ${va(n.tokensReturned)} tokens returned out of ${va(n.tokensConsidered)} considered (Rigour's estimate).`}),i.jsx(ga,{title:"What this team knows",value:`${O(n.lessonsTold,"lesson")} told`,detail:`${O(n.recalls,"recall")} of saved facts and lessons. How it learns shows what each lesson stopped.`}),i.jsxs("section",{className:"st-card",style:{gridColumn:"1 / -1"},children:[i.jsx("strong",{children:"Pointed to code that already exists"}),n.reuse.length===0?i.jsx("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:"No duplicate was about to be written this week."}):i.jsx("div",{className:"st-stack",style:{marginTop:12},children:n.reuse.map(s=>i.jsxs("div",{className:"st-row",style:{alignItems:"flex-start"},children:[i.jsx("span",{className:`st-chip ${s.action==="BLOCK"?"warn":""}`,children:s.action==="BLOCK"?"reuse":"similar"}),i.jsxs("div",{style:{flex:1,fontSize:14,lineHeight:1.5},children:["About to write ",i.jsx("span",{className:"st-mono",children:s.planned}),"; told to use ",i.jsx("span",{className:"st-mono",children:s.existing})]}),i.jsx("span",{className:"st-sub",children:gt(s.at)})]},`${s.at}-${s.planned}`))})]})]}),i.jsx(fh,{weeks:e.weeks})]})},ga=({title:e,value:t,detail:n})=>i.jsxs("section",{className:"st-card",children:[i.jsx("div",{className:"st-sub",children:e}),i.jsx("div",{style:{fontSize:22,fontWeight:600,marginTop:6,color:"var(--text-primary)"},children:t}),i.jsx("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:n})]}),fh=({weeks:e})=>{const t=e.filter(n=>n.scopes+n.recalls+n.lessonsTold+n.reuse>0).reverse();return i.jsxs("section",{className:"st-card",style:{marginTop:24,padding:0,overflowX:"auto"},children:[i.jsx("div",{style:{padding:"16px 20px 8px"},children:i.jsx("strong",{children:"Last 8 weeks"})}),t.length===0?i.jsx("div",{className:"st-sub",style:{padding:"0 20px 18px"},children:"No context requests in the last 8 weeks."}):i.jsxs("table",{className:"st-table",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Week of"}),i.jsx("th",{children:"Focused file lists"}),i.jsx("th",{children:"Files given"}),i.jsx("th",{children:"Recalls"}),i.jsx("th",{children:"Lessons told"}),i.jsx("th",{children:"Duplicates avoided"})]})}),i.jsx("tbody",{children:t.map(n=>i.jsxs("tr",{children:[i.jsx("td",{children:new Date(n.from).toLocaleDateString(void 0,{month:"short",day:"numeric"})}),i.jsx("td",{children:n.scopes}),i.jsx("td",{children:n.scopes?`${n.filesReturned} of ${n.filesConsidered}`:"—"}),i.jsx("td",{children:n.recalls}),i.jsx("td",{children:n.lessonsTold}),i.jsx("td",{children:n.reuse})]},n.from))})]})]})},sl={single:"one judge",cross:"one judge from another vendor",full:"one judge per vendor, findings merged",panel:"a panel: only what a majority confirms blocks"},ph=e=>e.file?`${e.file}${e.line?`:${e.line}`:""}`:"",hh=({data:e,canWrite:t,onChange:n})=>{var s,l,o,a;const r=(s=e.status)==null?void 0:s.last;return i.jsxs("section",{style:{marginTop:24},children:[i.jsxs("h2",{style:{margin:"0 0 12px",fontSize:18,fontWeight:600},children:["The reviewer's verdict on ",e.branch]}),((l=e.status)==null?void 0:l.running)&&i.jsxs("div",{className:"st-sub",style:{marginBottom:8},children:["Reviewing ",e.status.running.head.slice(0,9)," now."]}),((o=e.status)==null?void 0:o.attempt)&&i.jsxs("div",{className:"st-card",style:{marginBottom:12},children:[i.jsx("span",{className:"st-chip warn",children:e.status.attempt.outcome==="skipped"?"skipped":"could not run"})," ",i.jsxs("span",{className:"st-sub",children:["The last review, of ",e.status.attempt.head.slice(0,9)," ",gt(e.status.attempt.at),": ",e.status.attempt.reason]})]}),r?i.jsxs("div",{className:"st-stack",children:[i.jsx("div",{className:"st-card st-row",style:{justifyContent:"space-between"},children:i.jsxs("span",{children:[i.jsx("span",{className:`st-chip ${r.open.length?"bad":"ok"}`,children:r.open.length?`${O(r.open.length,"finding")} to fix`:"nothing to fix"})," ",i.jsxs("span",{className:"st-sub",children:[r.ran?`${sl[r.ran.ran]??r.ran.ran}, `:"",r.mode==="delta"?"new commits":"the whole branch"," at ",r.head.slice(0,9),", ",gt(r.at)]})]})}),r.ran&&(r.ran.degraded||r.ran.escalation||r.ran.asked!==r.ran.ran)&&i.jsxs("div",{className:"st-sub",children:["Asked for ",sl[r.ran.asked]??r.ran.asked," (",r.ran.source,"); ran ",sl[r.ran.ran]??r.ran.ran,". ",[r.ran.degraded,r.ran.escalation].filter(Boolean).join("; ")]}),r.open.map(u=>i.jsx(ya,{item:u,canWrite:t&&e.effective.dismissals,onChange:n},u.id)),r.disputed.length>0&&i.jsx("div",{className:"st-sub",style:{marginTop:8},children:"No majority, so these never block:"}),r.disputed.map(u=>i.jsx(ya,{item:u,disputed:!0,canWrite:!1,onChange:n},u.id))]}):!((a=e.status)!=null&&a.attempt)&&i.jsxs("div",{className:"st-empty",children:["No verdict yet. Run ",i.jsx("span",{className:"st-mono",children:"rigour review --reviewer"}),", or push with the reviewer on."]})]})},ya=({item:e,disputed:t,canWrite:n,onChange:r})=>{const[s,l]=_.useState(""),[o,a]=_.useState(!1),[u,d]=_.useState(null),v=async()=>{const m=await We("/api/reviewer/dismiss","POST",JSON.stringify({id:e.id,reason:s}));m.ok?r():d((await m.json().catch(()=>({}))).error??`HTTP ${m.status}`)};return i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between",gap:12},children:[i.jsx("strong",{style:{fontSize:14},children:e.issue}),i.jsx("span",{className:"st-mono st-sub",children:ph(e)})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:6},children:[t?i.jsx("span",{className:"st-chip warn",children:"disputed"}):i.jsx("span",{className:"st-chip",children:e.class}),e.reviewer&&i.jsxs(i.Fragment,{children:[" found by ",e.reviewer.split("+").join(" and ")]})]}),e.consequence&&i.jsxs("div",{style:{marginTop:8,fontSize:14},children:["What goes wrong: ",e.consequence]}),e.evidence&&i.jsx("div",{className:"st-mono st-sub",style:{marginTop:6},children:e.evidence}),n&&e.kind!=="prior"&&(o?i.jsxs("div",{className:"st-row",style:{marginTop:10,gap:8},children:[i.jsx("input",{"aria-label":"Why it is not a bug",value:s,onChange:m=>l(m.target.value),placeholder:"Why it is not a bug",style:{flex:1,minHeight:36,padding:"0 10px",borderRadius:8,border:"1px solid var(--text-dim)",background:"var(--bg-card)",color:"var(--text-primary)"}}),i.jsx("button",{className:"st-btn",disabled:s.trim().length<5,onClick:v,children:"Dismiss"})]}):i.jsx("button",{className:"st-btn",style:{marginTop:10},onClick:()=>a(!0),children:"Not a bug"})),u&&i.jsxs("div",{className:"st-sub",style:{marginTop:6},children:[i.jsx("span",{className:"st-chip bad",children:"not dismissed"})," ",u]})]})},as=({label:e,value:t,options:n,disabled:r,withTeam:s,onChange:l})=>{const o=s?[{value:null,label:"Team"},...n]:n,a=t===void 0?null:t;return i.jsx("div",{className:"st-seg",role:"radiogroup","aria-label":e,children:o.map(u=>{const d=JSON.stringify(u.value)===JSON.stringify(a);return i.jsx("button",{type:"button",role:"radio","aria-checked":d,className:d?"on":"",disabled:r,onClick:()=>!d&&l(u.value),children:u.label},u.label)})})},mh={flag:"this run",env:"environment",user:"yours",team:"team"};function vh(e,t){return e.key==="mode"?t.source.mode:e.key==="panel"?t.source.panel:e.key==="escalate"&&(t.required.panel||t.required.mode)?"team":e.user&&e.user.value!==void 0?"user":"team"}const ll=[{value:!0,label:"on"},{value:!1,label:"off"}],xa=[{value:"single",label:"one judge"},{value:"cross",label:"one, another vendor"},{value:"full",label:"one per vendor"}],gh=({data:e,canWrite:t,saving:n,onSave:r,onSaveTeam:s})=>{const[l,o]=_.useState(!1),a=e.effective,u=e.team,d=a.required.panel||a.required.mode,v=[{key:"enabled",label:"Review at push",help:"Ask the reviewer when you push a branch that has an open pull request.",effective:a.enabled?"on":"off",user:{value:e.user.enabled,options:ll},team:{value:u.enabled??!1,options:ll}},{key:"mode",label:"Mode",help:"One judge; one from a vendor that did not write the code; or one judge per vendor (up to Judges), findings merged.",effective:a.mode,user:{value:e.user.mode,options:xa},team:{value:u.mode??"single",options:xa},locked:a.required.mode?"your team requires at least this":void 0},{key:"mode_required",label:"Required for everyone",help:"No person or run may review with fewer judges than the team's, in CI or anywhere.",effective:a.required.mode?"yes":"no",team:{value:u.mode_required??!1,options:[{value:!0,label:"yes"},{value:!1,label:"no"}]}},{key:"panel",label:"Panel",help:"Judges cross-examine what only one of them found; only what a majority confirms blocks. Required: no one may turn it off.",effective:a.panel?"on":"off",user:{value:e.user.panel,options:ll},team:{value:u.panel??"off",options:[{value:"off",label:"off"},{value:"on",label:"on"},{value:"required",label:"required"}]},locked:a.required.panel?"your team requires the panel":void 0},{key:"dismissals",label:"Dismissals",help:'Whether people may mark a reviewer finding "not a bug". Off: a wrong finding is fixed by improving the reviewer, a right one by fixing the code.',effective:a.dismissals?"allowed":"off",team:{value:u.dismissals??!1,options:[{value:!0,label:"allowed"},{value:!1,label:"off"}]}},{key:"judges",label:"Judges",help:"How many judges a full or panel review uses, each from a different vendor. Three give a real majority.",effective:String(a.judges),user:{value:e.user.judges,options:[{value:2,label:"2"},{value:3,label:"3"}]},team:{value:u.judges??2,options:[{value:2,label:"2"},{value:3,label:"3"}]}},{key:"escalate",label:"When to add judges",help:"Always, or only for a risky change or one a person has reviewed. The backtest shows whether that loses anything.",effective:a.escalate,user:{value:e.user.escalate,options:[{value:"always",label:"always"},{value:"risk",label:"when risky"}]},team:{value:u.escalate??"always",options:[{value:"always",label:"always"},{value:"risk",label:"when risky"}]},locked:d?"your team requires every review to be full":void 0}],m=t&&(e.teamFile||l);return i.jsxs(i.Fragment,{children:[i.jsxs("p",{className:"st-sub",style:{margin:"0 0 12px",lineHeight:1.6},children:[i.jsx("strong",{children:"Yours"})," applies to your own runs, in every repository on this machine, and wins over the team's except where the team set a floor. ",i.jsx("strong",{children:"Team"})," is"," ",e.teamFile?i.jsxs(i.Fragment,{children:["in ",i.jsx("span",{className:"st-mono",children:"rigour.yml"}),": a change here edits the file, and you commit it"]}):i.jsxs(i.Fragment,{children:["Rigour's defaults: this repository has no ",i.jsx("span",{className:"st-mono",children:"rigour.yml"})]}),".",!t&&" Open Studio from the link the terminal printed to change settings here."]}),t&&!e.teamFile&&!l&&i.jsxs("div",{className:"st-card st-row",style:{justifyContent:"space-between",marginBottom:12},children:[i.jsxs("span",{className:"st-sub",children:["Setting team defaults creates a ",i.jsx("span",{className:"st-mono",children:"rigour.yml"}),": from then on this repository uses the team setup."]}),i.jsx("button",{className:"st-btn",onClick:()=>o(!0),children:"Set team defaults"})]}),i.jsx("div",{className:"st-stack",children:v.map(h=>i.jsxs("div",{className:"st-card st-setting",children:[i.jsxs("div",{children:[i.jsx("div",{style:{fontSize:15},children:h.label}),i.jsx("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.5},children:h.help})]}),i.jsxs("div",{className:"st-setting-controls",children:[i.jsx("span",{className:"st-sub",children:"Runs"}),i.jsxs("span",{children:[i.jsx("span",{className:"st-mono",children:h.effective})," ",i.jsxs("span",{className:"st-sub",children:["· ",mh[vh(h,a)]]}),h.locked&&i.jsxs("span",{title:h.locked,"aria-label":h.locked,children:[" ",i.jsx(Cs,{size:12})]})]}),i.jsx("span",{className:"st-sub",children:"Yours"}),h.user?i.jsx(as,{label:`Your ${h.label}`,withTeam:!0,disabled:!t||n!==null,value:h.user.value,options:h.user.options,onChange:y=>r({[h.key]:y})}):i.jsx("span",{className:"st-sub",children:"set by the team only"}),i.jsx("span",{className:"st-sub",children:"Team"}),i.jsx(as,{label:`Team ${h.label}`,disabled:!m||n!==null,value:h.team.value,options:h.team.options,onChange:y=>s({[h.key]:y},!e.teamFile)})]})]},h.key))}),i.jsx(yh,{data:e}),a.refused.length>0&&i.jsx("div",{className:"st-stack",style:{marginTop:12},children:a.refused.map(h=>i.jsxs("div",{className:"st-sub",children:[i.jsx("span",{className:"st-chip warn",children:"not applied"})," ",h]},h))})]})},Uc=({diff:e})=>i.jsxs("div",{className:"st-card",style:{marginTop:12},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{style:{fontSize:14},children:"rigour.yml changed"}),i.jsx("span",{className:"st-sub",children:"Commit it so the change reaches your team."})]}),i.jsx("pre",{className:"st-code",style:{marginTop:8},children:e.split(`
|
|
166
|
+
`).map((t,n)=>i.jsx("div",{className:`st-ln ${t.startsWith("+")?"add":t.startsWith("-")?"del":""}`,children:t},n))})]}),yh=({data:e})=>{var s;const t=((s=e.status)==null?void 0:s.today)??{runs:0,usd:0},{max_runs_per_day:n,max_usd_per_day:r}=e.effective;return i.jsxs("div",{className:"st-card",style:{marginTop:12},children:[i.jsx("div",{style:{fontSize:15},children:"Today in this repository"}),i.jsxs("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.6},children:[O(t.runs,"agent run"),n!==void 0?` of ${n} allowed`:"",t.usd||r!==void 0?`, $${t.usd.toFixed(2)} reported${r!==void 0?` of $${r.toFixed(2)}`:""}`:"","."," ",n===void 0&&r===void 0?i.jsxs(i.Fragment,{children:["No daily cap: set ",i.jsx("span",{className:"st-mono",children:"max_runs_per_day"})," or ",i.jsx("span",{className:"st-mono",children:"max_usd_per_day"})," in ",i.jsx("span",{className:"st-mono",children:"rigour.yml"}),"."]}):"Past a cap, reviews are skipped until tomorrow (or cannot run, where your team requires the reviewer)."]})]})},xh=({data:e})=>{const t=new Set(e.available.filter(r=>r.installed&&e.effective.reviewers.includes(r.name)).map(r=>r.vendor)).size,n=e.effective.required.panel||e.effective.required.mode;return i.jsxs("section",{style:{marginTop:20},children:[i.jsx("h3",{style:{margin:"0 0 6px",fontSize:15,fontWeight:600},children:"Agent CLIs on this machine"}),i.jsxs("p",{className:"st-sub",style:{margin:"0 0 12px"},children:["The reviewer uses their own logins: no API key. ",t>=3?"Enough vendors for three judges.":t===2?"Enough for two judges; a third vendor, listed in the reviewers, allows three.":n?"Your team requires two judges from different vendors: with one, the review cannot run until another is installed.":"Two judges need two vendors; with one, the review runs with one judge and says so."]}),i.jsx("div",{className:"st-row",style:{flexWrap:"wrap",gap:8},children:e.available.map(r=>i.jsxs("span",{className:`st-chip ${r.installed?"ok":""}`,children:[r.binary,r.installed?` ${r.version??""}`:": not installed"]},r.name))})]})};function Bc(){return ge("/api/reviewer")}const wh=()=>{const{data:e,error:t,reload:n}=Bc();return t?i.jsxs("div",{className:"st-empty",children:["Couldn't load the reviewer's verdict: ",t,"."]}):e?i.jsx(hh,{data:e,canWrite:Ts(),onChange:n}):i.jsx("div",{className:"st-sub",children:"Loading…"})},kh=()=>{const{data:e,error:t,reload:n}=Bc(),[r,s]=_.useState(null),[l,o]=_.useState(null),[a,u]=_.useState(null);if(t)return i.jsxs("div",{className:"st-empty",children:["Couldn't load the reviewer's settings: ",t,"."]});if(!e)return i.jsx("div",{className:"st-sub",children:"Loading…"});const d=async(v,m,h)=>{s(h),o(null);const y=await We(v,"POST",JSON.stringify(m)),w=await y.json().catch(()=>({}));y.ok?v.endsWith("/team")&&u(w.diff??null):o(w.error??`HTTP ${y.status}`),s(null),n()};return i.jsxs("section",{style:{marginTop:32},children:[i.jsx("h2",{style:{margin:"0 0 6px",fontSize:18,fontWeight:600},children:"The reviewer"}),i.jsx("p",{className:"st-sub",style:{margin:"0 0 12px",lineHeight:1.6},children:"A second opinion from other AI models, before a person reviews. Off until your team or you turn it on. With two or three judges from different vendors, a finding blocks only when most of them agree and it names what goes wrong."}),i.jsx(gh,{data:e,canWrite:Ts(),saving:r,onSave:v=>d("/api/reviewer/settings",v,Object.keys(v)[0]),onSaveTeam:(v,m)=>d("/api/reviewer/team",{patch:v,create:m},`team:${Object.keys(v)[0]}`)}),l&&i.jsxs("div",{className:"st-card",style:{marginTop:12},children:[i.jsx("span",{className:"st-chip bad",children:"not saved"})," ",i.jsx("span",{className:"st-sub",children:l})]}),a&&i.jsx(Uc,{diff:a}),i.jsx(xh,{data:e})]})},jh=e=>e==="agent"?"your agent":e==="human"?"you":e.replace(/^byok:/,""),Nh=()=>{const{data:e,error:t}=ge("/api/pre-pr-review");return t?i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load reviews: ",t,"."]})}):e?i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"Review before the PR"}),i.jsx("p",{className:"st-lead",children:"What still stands between this branch and a person's review: the reviewer's verdict, then the risky functions your agent checked."}),i.jsx(wh,{}),i.jsx("h2",{style:{margin:"32px 0 6px",fontSize:18,fontWeight:600},children:"Risky functions your agent checks"}),i.jsxs("p",{className:"st-sub",style:{margin:0,lineHeight:1.6},children:["Rigour picks the riskiest changed functions and asks specific questions about them. Your agent answers with its own model, or you do.",e.reviewed.total>0&&` So far: ${O(e.reviewed.total,"function")} reviewed, ${e.reviewed.fixed} fixed, ${e.reviewed.noIssue} with no issue.`]}),i.jsxs("section",{style:{marginTop:24},children:[i.jsx("h3",{style:{margin:"0 0 12px",fontSize:15,fontWeight:600},children:"Waiting"}),e.pending.length===0?i.jsx("div",{className:"st-empty",children:"No risky function in the current changes is waiting."}):i.jsx("div",{className:"st-stack",children:e.pending.map(n=>i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{className:"st-mono",style:{fontSize:14},children:n.function}),i.jsxs("span",{className:"st-mono st-sub",children:[n.file,":",n.start]})]}),i.jsx("ul",{style:{margin:"10px 0 0",paddingLeft:18,lineHeight:1.6,fontSize:14},children:n.questions.map(r=>i.jsx("li",{children:r},r))})]},`${n.file}:${n.function}`))})]}),i.jsxs("section",{style:{marginTop:28},children:[i.jsx("h3",{style:{margin:"0 0 12px",fontSize:15,fontWeight:600},children:"Checked"}),e.recent.length===0?i.jsx("div",{className:"st-empty",children:"Nothing reviewed yet. Agents review through rigour_review; you can run rigour review-task."}):i.jsx("div",{className:"st-stack",children:e.recent.map(n=>i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsxs("span",{children:[i.jsx("span",{className:`st-chip ${n.verdict==="fixed"?"ok":""}`,children:n.verdict==="fixed"?"fixed":n.verdict==="no_issue"?"no issue":n.verdict})," ",i.jsx("strong",{className:"st-mono",style:{fontSize:14,marginLeft:8},children:n.function})]}),i.jsxs("span",{className:"st-sub",children:[jh(n.reviewer)," · ",gt(n.at)]})]}),i.jsx("div",{className:"st-mono st-sub",style:{marginTop:6},children:n.file}),n.note&&i.jsx("div",{style:{marginTop:10,fontSize:14,lineHeight:1.6},children:n.note})]},`${n.file}:${n.function}:${n.at}`))})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:24},children:["Model reviews with your own key: ",e.spend.runs===0?"none run here":`${O(e.spend.runs,"run")}, ${Sh(e.spend)}${e.lastModel?`, last with ${e.lastModel}`:""}`,"."]})]}):i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})})};function Sh(e){return e.runs-e.unpricedRuns===0?"cost not reported by the provider":`$${e.costUsd.toFixed(2)} observed${e.unpricedRuns?` (${e.unpricedRuns} without a reported cost)`:""}`}const wa={stopped:{label:"blocked",cls:"warn"},reported:{label:"reported",cls:"warn"},fixed:{label:"fixed",cls:"ok"},checked:{label:"checked",cls:""},reviewed:{label:"reviewed",cls:""},taught:{label:"told",cls:""},pr:{label:"PR",cls:"warn"}},il=e=>new Date(e).toLocaleTimeString(void 0,{hour:"numeric",minute:"2-digit"}),Ch=e=>new Date(e).toLocaleDateString(void 0,{weekday:"long",month:"short",day:"numeric"}),Th=()=>{const{data:e,error:t}=ge("/api/activity");return t?i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't load activity: ",t,"."]})}):e?i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"Activity"}),i.jsx("p",{className:"st-lead",children:"Each block is one stretch of agent work. What Rigour blocked, reported or got fixed is listed; routine checks fold away."}),e.sessions.length===0?i.jsx("div",{className:"st-empty",style:{marginTop:24},children:"Nothing yet. Activity appears as agents edit code, ask for reviews and finish their work."}):i.jsx("div",{className:"st-stack",style:{marginTop:24,gap:16},children:e.sessions.map(n=>i.jsx(Eh,{session:n},n.start))})]}):i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Loading…"})})},Eh=({session:e})=>{const[t,n]=_.useState(!1),r=e.counts,s=r.fixed+r.reviewedFixed,l=[s&&`${O(s,"problem")} fixed`,r.stopped&&`${O(r.stopped,"edit")} blocked`,r.reported&&`${O(r.reported,"edit")} reported on`,r.pr&&`${O(r.pr,"branch review")} with findings`,r.reviewed&&`${O(r.reviewed,"risky function")} reviewed${r.reviewed-r.reviewedFixed?` (${r.reviewed-r.reviewedFixed} fine)`:""}`,r.checked&&`${O(r.checked,"edit")} checked clean`,r.taught&&`lessons given ${O(r.taught,"time")}`].filter(Boolean).join(" · ");return i.jsxs("section",{className:"st-card",style:{padding:0},children:[i.jsxs("div",{style:{padding:"16px 20px",borderBottom:e.highlights.length||t?"1px solid var(--border-dim)":0},children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsxs("strong",{children:[Ch(e.start),", ",il(e.start),e.start!==e.end?`–${il(e.end)}`:""]}),e.rest.length>0&&i.jsx("button",{className:"st-btn",onClick:()=>n(!t),type:"button",style:{minHeight:32},children:t?"Hide routine":`Show ${O(e.rest.length,"routine item")}`})]}),i.jsx("div",{className:"st-sub",style:{marginTop:6},children:l})]}),[...e.highlights,...t?e.rest:[]].map((o,a)=>i.jsxs("div",{className:"st-row",style:{padding:"12px 20px",borderTop:a?"1px solid var(--border-dim)":0,alignItems:"flex-start"},children:[i.jsx("span",{className:`st-chip ${o.kind==="reviewed"&&o.text.startsWith("Fixed ")?"ok":wa[o.kind].cls}`,style:{minWidth:70,textAlign:"center"},children:o.kind==="reviewed"&&o.text.startsWith("Fixed ")?"fixed":wa[o.kind].label}),i.jsxs("div",{style:{flex:1,minWidth:0},children:[i.jsx("div",{style:{fontSize:14,lineHeight:1.5},children:fn(o.text)}),o.detail&&i.jsx("div",{className:"st-sub",style:{marginTop:3,lineHeight:1.5},children:o.detail})]}),i.jsx("span",{className:"st-sub",style:{whiteSpace:"nowrap"},children:il(o.at)})]},`${o.at}-${a}`))]})},_h={flag:"this run",env:"environment",user:"yours",team:"team"},zh=({text:e,data:t,canWrite:n,saving:r,problem:s,diff:l,onSave:o})=>{const a=t.effective,u=a.required?`your team requires the ${e.name}`:void 0;return i.jsxs("section",{style:{marginTop:32},children:[i.jsx("h2",{style:{margin:"0 0 6px",fontSize:18,fontWeight:600},children:e.title}),i.jsxs("p",{className:"st-sub",style:{margin:"0 0 12px",lineHeight:1.6},children:[e.lead,!n&&" Open Studio from the link the terminal printed to change it here."]}),i.jsxs("div",{className:"st-card st-setting",children:[i.jsxs("div",{children:[i.jsx("div",{style:{fontSize:15},children:e.row}),i.jsx("div",{className:"st-sub",style:{marginTop:4,lineHeight:1.5},children:e.rowHelp})]}),i.jsxs("div",{className:"st-setting-controls",children:[i.jsx("span",{className:"st-sub",children:"Runs"}),i.jsxs("span",{children:[i.jsx("span",{className:"st-mono",children:a.enabled?"on":"off"})," ",i.jsxs("span",{className:"st-sub",children:["· ",_h[a.source]]}),u&&i.jsxs("span",{title:u,"aria-label":u,children:[" ",i.jsx(Cs,{size:12})]})]}),i.jsx("span",{className:"st-sub",children:"Yours"}),i.jsx(as,{label:`Your ${e.name}`,withTeam:!0,disabled:!n||r,value:t.user??void 0,options:[{value:!0,label:"on"},{value:!1,label:"off"}],onChange:d=>o({user:d})}),i.jsx("span",{className:"st-sub",children:"Team"}),i.jsx(as,{label:`Team ${e.name}`,disabled:!n||r,value:t.team,options:[{value:"off",label:"off"},{value:"on",label:"on"},{value:"required",label:"required"}],onChange:d=>o({team:d,create:!t.teamFile})})]})]}),!t.teamFile&&n&&i.jsxs("div",{className:"st-sub",style:{marginTop:8},children:["This repository has no ",i.jsx("span",{className:"st-mono",children:"rigour.yml"}),": setting the team's value creates one, and from then on it uses the team setup."]}),a.refused.length>0&&i.jsx("div",{className:"st-stack",style:{marginTop:12},children:a.refused.map(d=>i.jsxs("div",{className:"st-sub",children:[i.jsx("span",{className:"st-chip warn",children:"not applied"})," ",d]},d))}),s&&i.jsxs("div",{className:"st-card",style:{marginTop:12},children:[i.jsx("span",{className:"st-chip bad",children:"not saved"})," ",i.jsx("span",{className:"st-sub",children:s})]}),l&&i.jsx(Uc,{diff:l})]})},ka={goal:{title:"The goal check",lead:i.jsxs(i.Fragment,{children:["Checks a change against what its pull request says it is for: files outside its ",i.jsx("span",{className:"st-mono",children:"Scope"})," or inside ",i.jsx("span",{className:"st-mono",children:"Out of scope"}),", and"," ",i.jsx("span",{className:"st-mono",children:"Done when"})," items naming a file it never touched, block. No model; a description without these sections is never checked."]}),row:"Check the goal",rowHelp:i.jsxs(i.Fragment,{children:["Required: no person, environment variable or flag may turn it off. ",i.jsx("span",{className:"st-mono",children:"--goal"})," and ",i.jsx("span",{className:"st-mono",children:"--no-goal"})," choose for one run."]}),name:"goal check"},outcomes:{title:"The outcome loop",lead:i.jsxs(i.Fragment,{children:["What happened after each pull request merged: CI on its merge commit, later commits and fixes on its files, a revert. Read with"," ",i.jsx("span",{className:"st-mono",children:"rigour outcomes"}),", one GitHub call per merged pull request until its window closes, then never again."]}),row:"Read outcomes",rowHelp:i.jsxs(i.Fragment,{children:["Required: no person, environment variable or flag may turn it off. ",i.jsx("span",{className:"st-mono",children:"--outcomes"})," and ",i.jsx("span",{className:"st-mono",children:"--no-outcomes"})," choose for one run."]}),name:"outcome loop"},orchestrator:{title:"The review orchestrator",lead:i.jsxs(i.Fragment,{children:["Experimental. Triage, without a model, picks which parts of a review each change needs (earlier human points, correctness, production cost, what the change leaves behind, rules, lessons and the goal), and the judge does only those, in one pass: the same runs as one judge. A change over the judge's limit is split only with what the router has already saved over its last 20 reviews, so on average it never costs more than one judge. A change with nothing for a model to review gets no run. Under required, every part returns or there is no verdict. The daily caps (",i.jsx("span",{className:"st-mono",children:"max_runs_per_day"}),", ",i.jsx("span",{className:"st-mono",children:"max_usd_per_day"}),") count every pass. What blocks is unchanged."]}),row:"Use the orchestrator",rowHelp:i.jsxs(i.Fragment,{children:["Required: no person, environment variable or flag may turn it off. ",i.jsx("span",{className:"st-mono",children:"--orchestrator"})," and ",i.jsx("span",{className:"st-mono",children:"--no-orchestrator"})," choose for one run."]}),name:"review orchestrator"}},ol=({name:e})=>{const t=`/api/switches/${e}`,{data:n,error:r,reload:s}=ge(t),[l,o]=_.useState(!1),[a,u]=_.useState(null),[d,v]=_.useState(null);if(r)return i.jsxs("div",{className:"st-empty",children:["Couldn't load the ",ka[e].name,": ",r,"."]});if(!n)return i.jsx("div",{className:"st-sub",children:"Loading…"});const m=async h=>{o(!0),u(null);const y=await We(t,"POST",JSON.stringify(h)),w=await y.json().catch(()=>({}));y.ok?"team"in h&&v(w.diff??null):u(w.error??`HTTP ${y.status}`),o(!1),s()};return i.jsx(zh,{text:ka[e],data:n,canWrite:Ts(),saving:l,problem:a,diff:d,onSave:m})},Ph={working:"ok","set up":"",broken:"bad",missing:"warn"},Rh=()=>{const{data:e,error:t}=ge("/api/setup");return t?i.jsx("div",{className:"st-page",children:i.jsxs("div",{className:"st-empty",children:["Couldn't check setup: ",t,"."]})}):e?i.jsxs("div",{className:"st-page",children:[i.jsx("h1",{className:"st-h1",children:"Setup"}),i.jsxs("p",{className:"st-lead",children:["What runs in this repository, and whether Rigour saw it work this week. The same checks run with ",i.jsx("span",{className:"st-mono",children:"rigour doctor"}),"."]}),i.jsx("div",{className:"st-stack",style:{marginTop:24},children:e.checks.map(n=>i.jsxs("div",{className:"st-card st-row",children:[i.jsx("span",{className:`st-chip ${Ph[n.state]}`,style:{minWidth:72,textAlign:"center"},children:n.state}),i.jsxs("div",{style:{flex:1},children:[i.jsx("div",{style:{fontSize:15},children:n.name}),i.jsx("div",{className:"st-sub",style:{marginTop:4},children:n.detail})]}),n.fix&&n.state!=="working"&&i.jsx("span",{className:"st-mono st-sub",children:n.fix})]},n.id))}),i.jsx(ol,{name:"goal"}),i.jsx(ol,{name:"outcomes"}),i.jsx(ol,{name:"orchestrator"}),i.jsx(kh,{}),i.jsx("h2",{style:{margin:"32px 0 6px",fontSize:18,fontWeight:600},children:"Who double-checks risky code"}),i.jsxs("div",{className:"st-grid",style:{gridTemplateColumns:"repeat(2, minmax(0, 1fr))",marginTop:12},children:[i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:"Your agent's own model"}),i.jsx("span",{children:"Free"})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:["Your agent calls ",i.jsx("span",{className:"st-mono",children:"rigour_review"})," and answers Rigour's questions with the model you already pay for. No key."]})]}),i.jsxs("div",{className:"st-card",children:[i.jsxs("div",{className:"st-row",style:{justifyContent:"space-between"},children:[i.jsx("strong",{children:"Your own API key"}),i.jsx("span",{children:"Pay per use"})]}),i.jsxs("div",{className:"st-sub",style:{marginTop:8,lineHeight:1.6},children:["For code written without an agent, and for PR reviews. ",i.jsx("span",{className:"st-mono",children:"rigour settings set-key"}),"; keys are never shown here."]})]})]})]}):i.jsx("div",{className:"st-page",children:i.jsx("div",{className:"st-sub",children:"Checking…"})})},ja=60,Lh=({request:e,onClose:t})=>{const[n,r]=_.useState(ja),[s,l]=_.useState(null);_.useEffect(()=>{const a=e.timestamp?Date.parse(e.timestamp):Date.now(),u=()=>r(Math.max(0,ja-Math.floor((Date.now()-a)/1e3)));u();const d=window.setInterval(u,1e3);return()=>window.clearInterval(d)},[e.timestamp]);const o=async a=>{const u=await We("/api/arbitrate","POST",JSON.stringify({requestId:e.requestId||e.id,decision:a}));u.ok?t():l(u.status===403?"Studio was opened without the link from your terminal, or the request expired.":`That didn't go through (HTTP ${u.status}).`)};return i.jsx("div",{role:"dialog","aria-modal":"true","aria-label":"Approve a command",style:{position:"fixed",inset:0,background:"rgba(15, 17, 22, 0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:50},children:i.jsxs("div",{className:"st-card",style:{width:"min(560px, calc(100vw - 32px))",padding:24},children:[i.jsx("strong",{style:{fontSize:18},children:"Your agent wants to run a command"}),i.jsx("pre",{className:"st-code st-mono",style:{padding:"12px 14px",marginTop:14,whiteSpace:"pre-wrap"},children:e.command}),e.firewallDecision&&e.firewallDecision!=="allow"&&i.jsxs("div",{className:"st-sub",style:{marginTop:10},children:["Rigour's pre-check: ",e.firewallDecision,e.firewallReason?`: ${e.firewallReason}`:""]}),i.jsx("div",{className:"st-sub",style:{marginTop:10},children:n>0?`Denied automatically in ${n}s if nobody answers.`:"Time ran out: the request was denied."}),s&&i.jsx("div",{className:"st-sub",style:{marginTop:10,color:"var(--status-error)"},children:s}),i.jsxs("div",{className:"st-row",style:{marginTop:18,justifyContent:"flex-end"},children:[i.jsx("button",{className:"st-btn",onClick:t,type:"button",children:"Close"}),i.jsx("button",{className:"st-btn",onClick:()=>o("reject"),type:"button",disabled:n===0,children:"Deny"}),i.jsx("button",{className:"st-btn primary",onClick:()=>o("approve"),type:"button",disabled:n===0,children:"Allow"})]})]})})},Na="rigour-theme-v2",al=[{id:"week",label:"This week",icon:zp,page:e=>i.jsx(Jp,{onNavigate:e})},{id:"progress",label:"Progress",icon:Op,page:()=>i.jsx(nh,{})},{id:"only",label:"Only Rigour",icon:Fp,page:()=>i.jsx(rh,{})},{id:"learns",label:"How it learns",icon:_p,page:()=>i.jsx(uh,{})},{id:"context",label:"Agent context",icon:Cp,page:()=>i.jsx(dh,{})},{id:"reviews",label:"Review",icon:Pp,page:()=>i.jsx(Nh,{})},{id:"activity",label:"Activity",icon:ni,page:()=>i.jsx(Th,{})},{id:"setup",label:"Setup",icon:Hp,page:()=>i.jsx(Rh,{})}],$h=6e4;function Mh(){const[e,t]=_.useState(()=>{try{return localStorage.getItem(Na)||"light"}catch{return"light"}}),[n,r]=_.useState("week"),[s,l]=_.useState(null),[o,a]=_.useState("connecting"),[u,d]=_.useState(null),[v,m]=_.useState(null),[h,y]=_.useState(!0),[w,k]=_.useState(!1),M=_.useCallback(async()=>{y(!0);try{const c=await fetch("/api/health"),p=await c.json();m(c.ok?p:{error:p.error||`HTTP ${c.status}`})}catch(c){m({error:c instanceof Error?c.message:String(c)})}finally{y(!1)}},[]);_.useEffect(()=>{const c=new EventSource("/api/events");return c.onopen=()=>a("live"),c.onerror=()=>a("offline"),c.onmessage=p=>{try{const g=JSON.parse(p.data),j=!g.timestamp||Date.now()-Date.parse(g.timestamp)<$h;g.type==="interception_requested"&&j&&d(g)}catch{}},fetch("/api/info").then(p=>p.json()).then(l).catch(()=>l(null)),()=>c.close()},[]),_.useEffect(()=>{document.documentElement.setAttribute("data-theme",e);try{localStorage.setItem(Na,e)}catch{}},[e]);const f=al.find(c=>c.id===n)??al[0];return i.jsxs("div",{className:"studio",children:[i.jsxs("aside",{className:"sidebar glass-shell",children:[i.jsxs("div",{className:"brand",children:[i.jsx("div",{className:"logo-icon",children:i.jsx($p,{size:18})}),i.jsx("span",{children:"Rigour"}),(s==null?void 0:s.studioVersion)&&i.jsxs("div",{className:"version-pill",children:["v",s.studioVersion]})]}),i.jsx("nav",{children:al.map(c=>i.jsxs("button",{className:`nav-item ${c.id===f.id?"active":""}`,onClick:()=>r(c.id),type:"button",children:[i.jsx(c.icon,{size:18}),i.jsx("span",{children:c.label})]},c.id))}),s&&i.jsx("div",{className:"sidebar-footer",children:i.jsxs("div",{className:"trust-indicator",title:s.teamSync?"Lessons your team promotes are shared through your team store":"Nothing leaves this machine",children:[i.jsx(Cs,{size:14}),i.jsx("span",{children:s.teamSync?"Synced with your team":"Stored on this machine"})]})})]}),i.jsxs("main",{className:"main-content",children:[i.jsxs("header",{className:"glass-shell",children:[i.jsx("div",{className:"header-left",children:s&&i.jsx(Wp,{name:s.projectName,branch:s.branch})}),i.jsxs("div",{className:"header-right",children:[i.jsx("button",{type:"button",className:"connection-status",onClick:()=>{k(c=>!c),M()},"aria-expanded":w,title:"Studio receives Rigour's events live",children:i.jsxs("div",{className:`status-indicator ${o}`,children:[i.jsx("div",{className:"pulse-emitter"}),i.jsx("span",{children:o==="live"?"Live":o==="offline"?"Offline":"Connecting"})]})}),i.jsx("button",{className:"theme-toggle",onClick:()=>t(c=>c==="dark"?"light":"dark"),"aria-label":"Toggle theme",type:"button",children:e==="dark"?i.jsx(Mp,{size:18}):i.jsx(Rp,{size:18})})]})]}),w&&i.jsxs("div",{className:"health-popover",children:[i.jsxs("div",{className:"health-popover-title",children:[i.jsx("strong",{children:"Rigour system health"}),i.jsx("button",{type:"button",onClick:()=>k(!1),"aria-label":"Close health",children:i.jsx(Dc,{size:15})})]}),i.jsx(Bp,{data:v,loading:h,stale:!1,onRetry:M})]}),i.jsxs("div",{className:"view-container",children:[!Ts()&&i.jsx(Up,{}),i.jsx(Ap,{resetKey:f.id,children:i.jsx("div",{className:"full-view",children:f.page(r)})})]})]}),u&&i.jsx(Lh,{request:u,onClose:()=>d(null)})]})}Qp();ul.createRoot(document.getElementById("root")).render(i.jsx(oi.StrictMode,{children:i.jsx(Mh,{})}));
|
package/studio-dist/index.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
10
|
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&family=Fira+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-BCsbfh30.js"></script>
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/index-UWYx4t8T.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|