difit 1.0.5 → 1.0.6

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/README.md CHANGED
@@ -35,21 +35,27 @@ reviewit 6f4a9b7
35
35
  # Review HEAD~3
36
36
  reviewit HEAD~3
37
37
 
38
+ # Review uncommitted changes (working directory)
39
+ reviewit .
40
+
38
41
  # Custom port, don't auto-open browser
39
42
  reviewit 6f4a9b7 --port 4300 --no-open
40
43
 
41
44
  # Via npx
42
45
  npx reviewit main~1
46
+ npx reviewit . # uncommitted changes
43
47
  ```
44
48
 
45
49
  ### ⚙️ CLI Options
46
50
 
47
- | Flag | Default | Description |
48
- | -------------- | ---------- | -------------------------------------------- |
49
- | `<commit-ish>` | (required) | Any Git reference: hash, tag, HEAD~n, branch |
50
- | `--port` | auto | Preferred port; falls back if occupied |
51
- | `--no-open` | false | Don't automatically open browser |
52
- | `--mode` | inline | Diff mode: `inline` or `side-by-side` |
51
+ | Flag | Default | Description |
52
+ | -------------- | ---------- | ---------------------------------------------------- |
53
+ | `<commit-ish>` | (required) | Any Git reference: hash, tag, HEAD~n, branch, or `.` |
54
+ | `--port` | auto | Preferred port; falls back if occupied |
55
+ | `--no-open` | false | Don't automatically open browser |
56
+ | `--mode` | inline | Diff mode: `inline` or `side-by-side` |
57
+
58
+ > **Note**: Use `.` as the commit-ish to review uncommitted changes in your working directory!
53
59
 
54
60
  ## 🛠️ Development
55
61
 
@@ -171,8 +171,8 @@ prismjs/prism.js:
171
171
  * @namespace
172
172
  * @public
173
173
  *)
174
- */function ey(e){var r;const t=(r=e.split(".").pop())==null?void 0:r.toLowerCase();return{ts:"typescript",tsx:"tsx",js:"javascript",jsx:"jsx",json:"json",css:"css",scss:"css",html:"html"}[t||""]||"text"}let Dc="";function ty(e){Dc=e}function Ko({code:e,language:t,className:n}){const r=t||ey(Dc);return v.jsx(Jg,{code:e,language:r,theme:zc.nightOwl,children:({style:l,tokens:o,getLineProps:i,getTokenProps:a})=>v.jsx("span",{className:n,style:{...l,background:"transparent"},children:o.map((s,d)=>v.jsx("span",{...i({line:s}),children:s.map((m,y)=>v.jsx("span",{...a({token:m})},y))},d))})})}function ny({chunk:e,comments:t,onAddComment:n,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o}){const[i,a]=O.useState(null),s=p=>{a(i===p?null:p)},d=()=>{a(null)},m=async p=>{i!==null&&(await n(i,p),a(null))},y=p=>t.filter(g=>g.line===p),k=(p=>{var f,w;const g=[];let x=e.oldStart,u=e.newStart,c=0;for(;c<p.length;){const b=p[c];if(!b){c++;continue}if(b.type==="normal")g.push({oldLine:b,newLine:{...b},oldLineNumber:x,newLineNumber:u}),x++,u++,c++;else if(b.type==="delete"){let E=c+1;for(;E<p.length&&((f=p[E])==null?void 0:f.type)==="delete";)E++;const C=p.slice(c,E),N=[];for(;E<p.length&&((w=p[E])==null?void 0:w.type)==="add";){const A=p[E];A&&N.push(A),E++}const R=Math.max(C.length,N.length);for(let A=0;A<R;A++){const z=C[A],T=N[A];g.push({oldLine:z,newLine:T,oldLineNumber:z?x+A:void 0,newLineNumber:T?u+A:void 0})}x+=C.length,u+=N.length,c=E}else b.type==="add"&&(g.push({newLine:b,newLineNumber:u}),u++,c++)}return g})(e.lines);return v.jsx("div",{className:"bg-github-bg-primary border border-github-border rounded-md overflow-hidden",children:v.jsx("table",{className:"w-full border-collapse font-mono text-xs leading-5",children:v.jsx("tbody",{children:k.map((p,g)=>{var u,c,f,w,b,E,C,N,R,A;const x=p.newLineNumber?y(p.newLineNumber):p.oldLineNumber?y(p.oldLineNumber):[];return v.jsxs(ei.Fragment,{children:[v.jsxs("tr",{className:"group",children:[v.jsx("td",{className:"w-[60px] px-2 text-right text-github-text-muted bg-github-bg-secondary border-r border-github-border select-none align-top",children:p.oldLineNumber||""}),v.jsx("td",{className:`w-1/2 p-0 align-top border-r border-github-border relative ${((u=p.oldLine)==null?void 0:u.type)==="delete"?"bg-diff-deletion-bg cursor-pointer":((c=p.oldLine)==null?void 0:c.type)==="normal"?"bg-transparent":"bg-github-bg-secondary"}`,onClick:()=>{var z;return((z=p.oldLine)==null?void 0:z.type)==="delete"&&p.oldLineNumber&&s(p.oldLineNumber)},title:((f=p.oldLine)==null?void 0:f.type)==="delete"&&p.oldLineNumber?"Click to add comment":"",children:p.oldLine&&v.jsx("div",{className:"flex items-center relative min-h-[20px] px-3",children:v.jsx(Ko,{code:p.oldLine.content,className:"flex-1 text-github-text-primary whitespace-pre-wrap break-all overflow-wrap-break-word [&_pre]:m-0 [&_pre]:p-0 [&_pre]:!bg-transparent [&_pre]:font-inherit [&_pre]:text-inherit [&_pre]:leading-inherit [&_code]:!bg-transparent [&_code]:font-inherit [&_code]:text-inherit [&_code]:leading-inherit"})})}),v.jsx("td",{className:"w-[60px] px-2 text-right text-github-text-muted bg-github-bg-secondary border-r border-github-border select-none align-top",children:p.newLineNumber||""}),v.jsx("td",{className:`w-1/2 p-0 align-top relative ${((w=p.newLine)==null?void 0:w.type)==="add"?"bg-diff-addition-bg cursor-pointer":((b=p.newLine)==null?void 0:b.type)==="normal"?"bg-transparent cursor-pointer":"bg-github-bg-secondary"}`,onClick:()=>{var z,T;return(((z=p.newLine)==null?void 0:z.type)==="add"||((T=p.newLine)==null?void 0:T.type)==="normal")&&p.newLineNumber&&s(p.newLineNumber)},title:(((E=p.newLine)==null?void 0:E.type)==="add"||((C=p.newLine)==null?void 0:C.type)==="normal")&&p.newLineNumber?"Click to add comment":"",children:p.newLine&&v.jsx("div",{className:"flex items-center relative min-h-[20px] px-3",children:v.jsx(Ko,{code:p.newLine.content,className:"flex-1 text-github-text-primary whitespace-pre-wrap break-all overflow-wrap-break-word [&_pre]:m-0 [&_pre]:p-0 [&_pre]:!bg-transparent [&_pre]:font-inherit [&_pre]:text-inherit [&_pre]:leading-inherit [&_code]:!bg-transparent [&_code]:font-inherit [&_code]:text-inherit [&_code]:leading-inherit"})})})]}),x.length>0&&v.jsx("tr",{className:"bg-github-bg-secondary",children:v.jsx("td",{colSpan:4,className:"p-0 border-t border-github-border",children:x.map(z=>v.jsx(Ac,{comment:z,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o},z.id))})}),i&&(i===p.oldLineNumber&&((N=p.oldLine)==null?void 0:N.type)==="delete"||i===p.newLineNumber&&(((R=p.newLine)==null?void 0:R.type)==="add"||((A=p.newLine)==null?void 0:A.type)==="normal"))&&v.jsx("tr",{className:"bg-github-bg-secondary",children:v.jsx("td",{colSpan:4,className:"p-0 border-t border-github-border",children:v.jsx(Fc,{onSubmit:m,onCancel:d})})})]},g)})})})})}function ry({chunk:e,comments:t,onAddComment:n,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o,mode:i="inline"}){const[a,s]=O.useState(null),[d,m]=O.useState(null),y=u=>{switch(u.type){case"add":return"bg-diff-addition-bg";case"delete":return"bg-diff-deletion-bg";default:return"bg-transparent"}},h=u=>{switch(u.type){case"add":return"+";case"delete":return"-";default:return" "}},k=(u,c)=>{a===u?(s(null),m(null)):(s(u),m(c))},p=()=>{s(null),m(null)},g=async u=>{a!==null&&(await n(a,u,d||void 0),s(null),m(null))},x=u=>t.filter(c=>c.line===u);return i==="side-by-side"?v.jsx(ny,{chunk:e,comments:t,onAddComment:n,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o}):v.jsx("div",{className:"bg-github-bg-primary",children:v.jsx("table",{className:"w-full border-collapse font-mono text-xs leading-5",children:v.jsx("tbody",{children:e.lines.map((u,c)=>{const f=x(u.newLineNumber||u.oldLineNumber||0);return v.jsxs(ei.Fragment,{children:[v.jsxs("tr",{className:`cursor-pointer group ${y(u)}`,onClick:()=>k(u.newLineNumber||u.oldLineNumber||0,u.content),title:"Click to add comment",children:[v.jsx("td",{className:"w-[50px] px-2 text-right text-github-text-muted bg-github-bg-secondary border-r border-github-border select-none align-top",children:u.oldLineNumber||""}),v.jsx("td",{className:"w-[50px] px-2 text-right text-github-text-muted bg-github-bg-secondary border-r border-github-border select-none align-top",children:u.newLineNumber||""}),v.jsx("td",{className:"p-0 w-full relative align-top",children:v.jsxs("div",{className:"flex items-center relative min-h-[20px]",children:[v.jsx("span",{className:`w-5 text-center text-github-text-muted flex-shrink-0 bg-github-bg-secondary border-r border-github-border ${u.type==="add"?"text-github-accent bg-diff-addition-bg":u.type==="delete"?"text-github-danger bg-diff-deletion-bg":""}`,children:h(u)}),v.jsx(Ko,{code:u.content,className:"flex-1 px-3 text-github-text-primary whitespace-pre-wrap break-all overflow-wrap-break-word [&_pre]:m-0 [&_pre]:p-0 [&_pre]:!bg-transparent [&_pre]:font-inherit [&_pre]:text-inherit [&_pre]:leading-inherit [&_code]:!bg-transparent [&_code]:font-inherit [&_code]:text-inherit [&_code]:leading-inherit"})]})})]}),f.map(w=>v.jsx("tr",{className:"bg-github-bg-secondary",children:v.jsx("td",{colSpan:3,className:"p-0 border-t border-github-border",children:v.jsx(Ac,{comment:w,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o})})},w.id)),a===(u.newLineNumber||u.oldLineNumber)&&v.jsx("tr",{className:"bg-[var(--bg-secondary)]",children:v.jsx("td",{colSpan:3,className:"p-0 border-t border-[var(--border-muted)]",children:v.jsx(Fc,{onSubmit:g,onCancel:p})})})]},c)})})})})}function ly({file:e,comments:t,diffMode:n,reviewedFiles:r,onToggleReviewed:l,onAddComment:o,onGeneratePrompt:i,onRemoveComment:a,onUpdateComment:s}){const d=r.has(e.path);ty(e.path);const m=h=>{switch(h){case"added":return v.jsx(_c,{size:16,className:"text-github-accent"});case"deleted":return v.jsx(Nc,{size:16,className:"text-github-danger"});case"renamed":return v.jsx(Ec,{size:16,className:"text-github-warning"});default:return v.jsx(Cc,{size:16,className:"text-github-text-secondary"})}},y=async(h,k,p)=>{try{await o(e.path,h,k,p)}catch(g){console.error("Failed to add comment:",g)}};return v.jsxs("div",{className:"bg-github-bg-primary",children:[v.jsxs("div",{className:"bg-github-bg-secondary border-b border-github-border px-5 py-4 flex items-center justify-between flex-wrap gap-3 sticky top-0 z-10",children:[v.jsxs("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:[v.jsx("button",{onClick:()=>l(e.path),className:"text-github-text-muted hover:text-github-text-primary transition-colors cursor-pointer",title:d?"Expand file":"Collapse file",children:d?v.jsx(Sc,{size:16}):v.jsx(kc,{size:16})}),m(e.status),v.jsx("h2",{className:"text-sm font-mono text-github-text-primary m-0 overflow-hidden text-ellipsis whitespace-nowrap",children:e.path}),v.jsx("button",{className:"bg-transparent border-none cursor-pointer px-1.5 py-1 rounded text-sm text-github-text-secondary transition-all hover:bg-github-bg-tertiary hover:text-github-text-primary",onClick:()=>{navigator.clipboard.writeText(e.path).then(()=>{console.log("File path copied to clipboard:",e.path)}).catch(h=>{console.error("Failed to copy file path:",h)})},title:"Copy file path",children:v.jsx(bc,{size:14})}),e.oldPath&&e.oldPath!==e.path&&v.jsxs("span",{className:"text-xs text-github-text-muted italic",children:["(renamed from ",e.oldPath,")"]})]}),v.jsxs("div",{className:"flex items-center gap-3",children:[v.jsxs("div",{className:"flex items-center gap-2 text-xs",children:[v.jsxs("span",{className:"font-medium px-1 py-0.5 rounded text-github-accent bg-green-100/10",children:["+",e.additions]}),v.jsxs("span",{className:"font-medium px-1 py-0.5 rounded text-github-danger bg-red-100/10",children:["-",e.deletions]})]}),v.jsxs("button",{onClick:()=>l(e.path),className:`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200 ${r.has(e.path)?"bg-github-accent text-white":"bg-gray-600 text-gray-200 border border-gray-500 hover:bg-gray-500 hover:text-white"}`,title:r.has(e.path)?"Mark as not reviewed":"Mark as reviewed",children:[r.has(e.path)?v.jsx(xc,{size:14}):v.jsx(Wf,{size:14}),"Viewed"]})]})]}),!d&&v.jsx("div",{className:"overflow-y-auto",children:e.chunks.map((h,k)=>v.jsxs("div",{className:"border-b border-github-border",children:[v.jsx("div",{className:"bg-github-bg-tertiary px-3 py-2 border-b border-github-border",children:v.jsx("code",{className:"text-github-text-secondary text-xs font-mono",children:h.header})}),v.jsx(ry,{chunk:h,comments:t,onAddComment:y,onGeneratePrompt:i,onRemoveComment:a,onUpdateComment:s,mode:n})]},k))})]})}function oy(e){const t={name:"",path:"",isDirectory:!0,children:[]};return e.forEach(n=>{const r=n.path.split("/");let l=t;for(let o=0;o<r.length;o++){const i=r[o];if(!i)continue;const a=o===r.length-1,s=r.slice(0,o+1).join("/");l.children||(l.children=[]);let d=l.children.find(m=>m.name===i);d||(d={name:i,path:s,isDirectory:!a,children:a?void 0:[],file:a?n:void 0},l.children.push(d)),l=d}}),t}function iy({files:e,onScrollToFile:t,comments:n,reviewedFiles:r,onToggleReviewed:l}){const o=oy(e),i=u=>{if(!u.isDirectory||!u.children)return[];const c=[];return u.path&&c.push(u.path),u.children.forEach(f=>{c.push(...i(f))}),c},[a,s]=O.useState(()=>new Set(i(o))),[d,m]=O.useState(""),y=u=>n.filter(c=>c.file===u).length,h=u=>{if(!d.trim())return u;if(u.isDirectory&&u.children){const c=u.children.map(f=>h(f)).filter(f=>f!==null);return c.length>0?{...u,children:c}:null}else if(u.file)return u.file.path.toLowerCase().includes(d.toLowerCase())?u:null;return null},k=h(o)||{...o,children:[]},p=u=>{switch(u){case"added":return v.jsx(_c,{size:16,className:"text-github-accent"});case"deleted":return v.jsx(Nc,{size:16,className:"text-github-danger"});case"renamed":return v.jsx(Ec,{size:16,className:"text-github-warning"});default:return v.jsx(Cc,{size:16,className:"text-github-text-secondary"})}},g=u=>{s(c=>{const f=new Set(c);return f.has(u)?f.delete(u):f.add(u),f})},x=(u,c=0)=>{if(u.isDirectory&&u.children){const f=a.has(u.path),w=E=>E.file&&y(E.file.path)>0?!0:E.children?E.children.some(C=>w(C)):!1,b=w(u);return v.jsxs("div",{children:[u.name&&v.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 hover:bg-github-bg-tertiary cursor-pointer",style:{paddingLeft:`${c*16+16}px`},onClick:()=>g(u.path),children:[f?v.jsx(kc,{size:16}):v.jsx(Sc,{size:16}),f?v.jsx(Pf,{size:16,className:"text-github-text-secondary"}):v.jsx(zf,{size:16,className:"text-github-text-secondary"}),v.jsx("span",{className:"text-sm text-github-text-primary font-medium flex-1 overflow-hidden text-ellipsis whitespace-nowrap",title:u.name,children:u.name}),b&&v.jsx("span",{className:"bg-github-warning/20 text-github-warning text-xs px-1.5 py-0.5 rounded-full font-medium ml-auto flex items-center gap-1",children:v.jsx(ns,{size:12})})]}),(f||!u.name)&&u.children.map(E=>x(E,c+1))]},u.path)}else if(u.file){const f=y(u.file.path),w=r.has(u.file.path);return v.jsxs("div",{className:`flex items-center gap-2 px-4 py-2 hover:bg-github-bg-tertiary cursor-pointer transition-colors ${w?"opacity-70":""}`,style:{paddingLeft:`${c*16+16}px`},onClick:()=>t(u.file.path),children:[v.jsx(Lc,{checked:w,onChange:()=>{l(u.file.path)},title:w?"Mark as not reviewed":"Mark as reviewed",className:"z-10"}),p(u.file.status),v.jsx("span",{className:`text-sm text-github-text-primary flex-1 overflow-hidden text-ellipsis whitespace-nowrap ${w?"line-through text-github-text-muted":""}`,title:u.file.path,children:u.name}),f>0&&v.jsxs("span",{className:"bg-github-warning/20 text-github-warning text-xs px-1.5 py-0.5 rounded-full font-medium ml-auto flex items-center gap-1",children:[v.jsx(ns,{size:12}),f]})]},u.file.path)}return null};return v.jsxs("div",{className:"h-full flex flex-col",children:[v.jsxs("div",{className:"px-4 py-3 border-b border-github-border bg-github-bg-tertiary",children:[v.jsxs("h3",{className:"text-sm font-semibold text-github-text-primary m-0 mb-3",children:["Files changed (",e.length,")"]}),v.jsxs("div",{className:"relative",children:[v.jsx(Hf,{size:16,className:"absolute left-3 top-1/2 transform -translate-y-1/2 text-github-text-muted"}),v.jsx("input",{type:"text",placeholder:"Filter files...",value:d,onChange:u=>m(u.target.value),className:"w-full pl-9 pr-3 py-2 text-sm bg-github-bg-primary border border-github-border rounded-md focus:outline-none focus:border-github-accent text-github-text-primary placeholder-github-text-muted"})]})]}),v.jsx("div",{className:"flex-1 overflow-y-auto",children:k.children&&k.children.map(u=>x(u))})]})}function ay(e){const[t,n]=O.useState([]),r=e?`reviewit-comments-${e}`:"reviewit-comments";return O.useEffect(()=>{const m=localStorage.getItem(r);if(m)try{n(JSON.parse(m))}catch(y){console.error("Failed to parse saved comments:",y)}},[r]),O.useEffect(()=>{localStorage.setItem(r,JSON.stringify(t))},[t,r]),{comments:t,addComment:(m,y,h,k)=>{console.log("Adding comment with codeContent:",k);const p={id:`${m}:${y}:${Date.now()}`,file:m,line:y,body:h,timestamp:new Date().toISOString(),codeContent:k};return n(g=>[...g,p]),p},removeComment:m=>{n(y=>y.filter(h=>h.id!==m))},updateComment:(m,y)=>{n(h=>h.map(k=>k.id===m?{...k,body:y}:k))},clearAllComments:()=>{n([]),localStorage.removeItem(r)},generatePrompt:m=>`${m.file}:${m.line}
174
+ */function ey(e){var o,i;const t=((o=e.split("/").pop())==null?void 0:o.toLowerCase())||"",n=(i=e.split(".").pop())==null?void 0:i.toLowerCase(),r={dockerfile:"docker",makefile:"makefile",".gitignore":"git",".env":"bash",".bashrc":"bash",".zshrc":"bash",".bash_profile":"bash",".profile":"bash"};return r[t]?r[t]:{ts:"typescript",tsx:"tsx",js:"javascript",jsx:"jsx",json:"json",css:"css",scss:"css",html:"html",sh:"bash",bash:"bash",zsh:"bash",fish:"bash",yml:"yaml",yaml:"yaml",md:"markdown",py:"python",rb:"ruby",go:"go",rs:"rust",java:"java",cpp:"cpp",c:"c",php:"php",sql:"sql",xml:"xml",swift:"swift",kt:"kotlin",scala:"scala",r:"r",lua:"lua",perl:"perl",dockerfile:"docker",makefile:"makefile",gitignore:"git",env:"bash",conf:"nginx",ini:"ini",toml:"toml"}[n||""]||"text"}let Dc="";function ty(e){Dc=e}function Ko({code:e,language:t,className:n}){const r=t||ey(Dc);return v.jsx(Jg,{code:e,language:r,theme:zc.nightOwl,children:({style:l,tokens:o,getLineProps:i,getTokenProps:a})=>v.jsx("span",{className:n,style:{...l,background:"transparent"},children:o.map((s,d)=>v.jsx("span",{...i({line:s}),children:s.map((m,y)=>v.jsx("span",{...a({token:m})},y))},d))})})}function ny({chunk:e,comments:t,onAddComment:n,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o}){const[i,a]=O.useState(null),s=p=>{a(i===p?null:p)},d=()=>{a(null)},m=async p=>{i!==null&&(await n(i,p),a(null))},y=p=>t.filter(g=>g.line===p),k=(p=>{var f,w;const g=[];let x=e.oldStart,u=e.newStart,c=0;for(;c<p.length;){const b=p[c];if(!b){c++;continue}if(b.type==="normal")g.push({oldLine:b,newLine:{...b},oldLineNumber:x,newLineNumber:u}),x++,u++,c++;else if(b.type==="delete"){let E=c+1;for(;E<p.length&&((f=p[E])==null?void 0:f.type)==="delete";)E++;const C=p.slice(c,E),N=[];for(;E<p.length&&((w=p[E])==null?void 0:w.type)==="add";){const A=p[E];A&&N.push(A),E++}const R=Math.max(C.length,N.length);for(let A=0;A<R;A++){const z=C[A],T=N[A];g.push({oldLine:z,newLine:T,oldLineNumber:z?x+A:void 0,newLineNumber:T?u+A:void 0})}x+=C.length,u+=N.length,c=E}else b.type==="add"&&(g.push({newLine:b,newLineNumber:u}),u++,c++)}return g})(e.lines);return v.jsx("div",{className:"bg-github-bg-primary border border-github-border rounded-md overflow-hidden",children:v.jsx("table",{className:"w-full border-collapse font-mono text-xs leading-5",children:v.jsx("tbody",{children:k.map((p,g)=>{var u,c,f,w,b,E,C,N,R,A;const x=p.newLineNumber?y(p.newLineNumber):p.oldLineNumber?y(p.oldLineNumber):[];return v.jsxs(ei.Fragment,{children:[v.jsxs("tr",{className:"group",children:[v.jsx("td",{className:"w-[60px] px-2 text-right text-github-text-muted bg-github-bg-secondary border-r border-github-border select-none align-top",children:p.oldLineNumber||""}),v.jsx("td",{className:`w-1/2 p-0 align-top border-r border-github-border relative ${((u=p.oldLine)==null?void 0:u.type)==="delete"?"bg-diff-deletion-bg cursor-pointer":((c=p.oldLine)==null?void 0:c.type)==="normal"?"bg-transparent":"bg-github-bg-secondary"}`,onClick:()=>{var z;return((z=p.oldLine)==null?void 0:z.type)==="delete"&&p.oldLineNumber&&s(p.oldLineNumber)},title:((f=p.oldLine)==null?void 0:f.type)==="delete"&&p.oldLineNumber?"Click to add comment":"",children:p.oldLine&&v.jsx("div",{className:"flex items-center relative min-h-[20px] px-3",children:v.jsx(Ko,{code:p.oldLine.content,className:"flex-1 text-github-text-primary whitespace-pre-wrap break-all overflow-wrap-break-word [&_pre]:m-0 [&_pre]:p-0 [&_pre]:!bg-transparent [&_pre]:font-inherit [&_pre]:text-inherit [&_pre]:leading-inherit [&_code]:!bg-transparent [&_code]:font-inherit [&_code]:text-inherit [&_code]:leading-inherit"})})}),v.jsx("td",{className:"w-[60px] px-2 text-right text-github-text-muted bg-github-bg-secondary border-r border-github-border select-none align-top",children:p.newLineNumber||""}),v.jsx("td",{className:`w-1/2 p-0 align-top relative ${((w=p.newLine)==null?void 0:w.type)==="add"?"bg-diff-addition-bg cursor-pointer":((b=p.newLine)==null?void 0:b.type)==="normal"?"bg-transparent cursor-pointer":"bg-github-bg-secondary"}`,onClick:()=>{var z,T;return(((z=p.newLine)==null?void 0:z.type)==="add"||((T=p.newLine)==null?void 0:T.type)==="normal")&&p.newLineNumber&&s(p.newLineNumber)},title:(((E=p.newLine)==null?void 0:E.type)==="add"||((C=p.newLine)==null?void 0:C.type)==="normal")&&p.newLineNumber?"Click to add comment":"",children:p.newLine&&v.jsx("div",{className:"flex items-center relative min-h-[20px] px-3",children:v.jsx(Ko,{code:p.newLine.content,className:"flex-1 text-github-text-primary whitespace-pre-wrap break-all overflow-wrap-break-word [&_pre]:m-0 [&_pre]:p-0 [&_pre]:!bg-transparent [&_pre]:font-inherit [&_pre]:text-inherit [&_pre]:leading-inherit [&_code]:!bg-transparent [&_code]:font-inherit [&_code]:text-inherit [&_code]:leading-inherit"})})})]}),x.length>0&&v.jsx("tr",{className:"bg-github-bg-secondary",children:v.jsx("td",{colSpan:4,className:"p-0 border-t border-github-border",children:x.map(z=>v.jsx(Ac,{comment:z,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o},z.id))})}),i&&(i===p.oldLineNumber&&((N=p.oldLine)==null?void 0:N.type)==="delete"||i===p.newLineNumber&&(((R=p.newLine)==null?void 0:R.type)==="add"||((A=p.newLine)==null?void 0:A.type)==="normal"))&&v.jsx("tr",{className:"bg-github-bg-secondary",children:v.jsx("td",{colSpan:4,className:"p-0 border-t border-github-border",children:v.jsx(Fc,{onSubmit:m,onCancel:d})})})]},g)})})})})}function ry({chunk:e,comments:t,onAddComment:n,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o,mode:i="inline"}){const[a,s]=O.useState(null),[d,m]=O.useState(null),y=u=>{switch(u.type){case"add":return"bg-diff-addition-bg";case"delete":return"bg-diff-deletion-bg";default:return"bg-transparent"}},h=u=>{switch(u.type){case"add":return"+";case"delete":return"-";default:return" "}},k=(u,c)=>{a===u?(s(null),m(null)):(s(u),m(c))},p=()=>{s(null),m(null)},g=async u=>{a!==null&&(await n(a,u,d||void 0),s(null),m(null))},x=u=>t.filter(c=>c.line===u);return i==="side-by-side"?v.jsx(ny,{chunk:e,comments:t,onAddComment:n,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o}):v.jsx("div",{className:"bg-github-bg-primary",children:v.jsx("table",{className:"w-full border-collapse font-mono text-xs leading-5",children:v.jsx("tbody",{children:e.lines.map((u,c)=>{const f=x(u.newLineNumber||u.oldLineNumber||0);return v.jsxs(ei.Fragment,{children:[v.jsxs("tr",{className:`cursor-pointer group ${y(u)}`,onClick:()=>k(u.newLineNumber||u.oldLineNumber||0,u.content),title:"Click to add comment",children:[v.jsx("td",{className:"w-[50px] px-2 text-right text-github-text-muted bg-github-bg-secondary border-r border-github-border select-none align-top",children:u.oldLineNumber||""}),v.jsx("td",{className:"w-[50px] px-2 text-right text-github-text-muted bg-github-bg-secondary border-r border-github-border select-none align-top",children:u.newLineNumber||""}),v.jsx("td",{className:"p-0 w-full relative align-top",children:v.jsxs("div",{className:"flex items-center relative min-h-[20px]",children:[v.jsx("span",{className:`w-5 text-center text-github-text-muted flex-shrink-0 bg-github-bg-secondary border-r border-github-border ${u.type==="add"?"text-github-accent bg-diff-addition-bg":u.type==="delete"?"text-github-danger bg-diff-deletion-bg":""}`,children:h(u)}),v.jsx(Ko,{code:u.content,className:"flex-1 px-3 text-github-text-primary whitespace-pre-wrap break-all overflow-wrap-break-word [&_pre]:m-0 [&_pre]:p-0 [&_pre]:!bg-transparent [&_pre]:font-inherit [&_pre]:text-inherit [&_pre]:leading-inherit [&_code]:!bg-transparent [&_code]:font-inherit [&_code]:text-inherit [&_code]:leading-inherit"})]})})]}),f.map(w=>v.jsx("tr",{className:"bg-github-bg-secondary",children:v.jsx("td",{colSpan:3,className:"p-0 border-t border-github-border",children:v.jsx(Ac,{comment:w,onGeneratePrompt:r,onRemoveComment:l,onUpdateComment:o})})},w.id)),a===(u.newLineNumber||u.oldLineNumber)&&v.jsx("tr",{className:"bg-[var(--bg-secondary)]",children:v.jsx("td",{colSpan:3,className:"p-0 border-t border-[var(--border-muted)]",children:v.jsx(Fc,{onSubmit:g,onCancel:p})})})]},c)})})})})}function ly({file:e,comments:t,diffMode:n,reviewedFiles:r,onToggleReviewed:l,onAddComment:o,onGeneratePrompt:i,onRemoveComment:a,onUpdateComment:s}){const d=r.has(e.path);ty(e.path);const m=h=>{switch(h){case"added":return v.jsx(_c,{size:16,className:"text-github-accent"});case"deleted":return v.jsx(Nc,{size:16,className:"text-github-danger"});case"renamed":return v.jsx(Ec,{size:16,className:"text-github-warning"});default:return v.jsx(Cc,{size:16,className:"text-github-text-secondary"})}},y=async(h,k,p)=>{try{await o(e.path,h,k,p)}catch(g){console.error("Failed to add comment:",g)}};return v.jsxs("div",{className:"bg-github-bg-primary",children:[v.jsxs("div",{className:"bg-github-bg-secondary border-b border-github-border px-5 py-4 flex items-center justify-between flex-wrap gap-3 sticky top-0 z-10",children:[v.jsxs("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:[v.jsx("button",{onClick:()=>l(e.path),className:"text-github-text-muted hover:text-github-text-primary transition-colors cursor-pointer",title:d?"Expand file":"Collapse file",children:d?v.jsx(Sc,{size:16}):v.jsx(kc,{size:16})}),m(e.status),v.jsx("h2",{className:"text-sm font-mono text-github-text-primary m-0 overflow-hidden text-ellipsis whitespace-nowrap",children:e.path}),v.jsx("button",{className:"bg-transparent border-none cursor-pointer px-1.5 py-1 rounded text-sm text-github-text-secondary transition-all hover:bg-github-bg-tertiary hover:text-github-text-primary",onClick:()=>{navigator.clipboard.writeText(e.path).then(()=>{console.log("File path copied to clipboard:",e.path)}).catch(h=>{console.error("Failed to copy file path:",h)})},title:"Copy file path",children:v.jsx(bc,{size:14})}),e.oldPath&&e.oldPath!==e.path&&v.jsxs("span",{className:"text-xs text-github-text-muted italic",children:["(renamed from ",e.oldPath,")"]})]}),v.jsxs("div",{className:"flex items-center gap-3",children:[v.jsxs("div",{className:"flex items-center gap-2 text-xs",children:[v.jsxs("span",{className:"font-medium px-1 py-0.5 rounded text-github-accent bg-green-100/10",children:["+",e.additions]}),v.jsxs("span",{className:"font-medium px-1 py-0.5 rounded text-github-danger bg-red-100/10",children:["-",e.deletions]})]}),v.jsxs("button",{onClick:()=>l(e.path),className:`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200 ${r.has(e.path)?"bg-github-accent text-white":"bg-gray-600 text-gray-200 border border-gray-500 hover:bg-gray-500 hover:text-white"}`,title:r.has(e.path)?"Mark as not reviewed":"Mark as reviewed",children:[r.has(e.path)?v.jsx(xc,{size:14}):v.jsx(Wf,{size:14}),"Viewed"]})]})]}),!d&&v.jsx("div",{className:"overflow-y-auto",children:e.chunks.map((h,k)=>v.jsxs("div",{className:"border-b border-github-border",children:[v.jsx("div",{className:"bg-github-bg-tertiary px-3 py-2 border-b border-github-border",children:v.jsx("code",{className:"text-github-text-secondary text-xs font-mono",children:h.header})}),v.jsx(ry,{chunk:h,comments:t,onAddComment:y,onGeneratePrompt:i,onRemoveComment:a,onUpdateComment:s,mode:n})]},k))})]})}function oy(e){const t={name:"",path:"",isDirectory:!0,children:[]};return e.forEach(n=>{const r=n.path.split("/");let l=t;for(let o=0;o<r.length;o++){const i=r[o];if(!i)continue;const a=o===r.length-1,s=r.slice(0,o+1).join("/");l.children||(l.children=[]);let d=l.children.find(m=>m.name===i);d||(d={name:i,path:s,isDirectory:!a,children:a?void 0:[],file:a?n:void 0},l.children.push(d)),l=d}}),t}function iy({files:e,onScrollToFile:t,comments:n,reviewedFiles:r,onToggleReviewed:l}){const o=oy(e),i=u=>{if(!u.isDirectory||!u.children)return[];const c=[];return u.path&&c.push(u.path),u.children.forEach(f=>{c.push(...i(f))}),c},[a,s]=O.useState(()=>new Set(i(o))),[d,m]=O.useState(""),y=u=>n.filter(c=>c.file===u).length,h=u=>{if(!d.trim())return u;if(u.isDirectory&&u.children){const c=u.children.map(f=>h(f)).filter(f=>f!==null);return c.length>0?{...u,children:c}:null}else if(u.file)return u.file.path.toLowerCase().includes(d.toLowerCase())?u:null;return null},k=h(o)||{...o,children:[]},p=u=>{switch(u){case"added":return v.jsx(_c,{size:16,className:"text-github-accent"});case"deleted":return v.jsx(Nc,{size:16,className:"text-github-danger"});case"renamed":return v.jsx(Ec,{size:16,className:"text-github-warning"});default:return v.jsx(Cc,{size:16,className:"text-github-text-secondary"})}},g=u=>{s(c=>{const f=new Set(c);return f.has(u)?f.delete(u):f.add(u),f})},x=(u,c=0)=>{if(u.isDirectory&&u.children){const f=a.has(u.path),w=E=>E.file&&y(E.file.path)>0?!0:E.children?E.children.some(C=>w(C)):!1,b=w(u);return v.jsxs("div",{children:[u.name&&v.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 hover:bg-github-bg-tertiary cursor-pointer",style:{paddingLeft:`${c*16+16}px`},onClick:()=>g(u.path),children:[f?v.jsx(kc,{size:16}):v.jsx(Sc,{size:16}),f?v.jsx(Pf,{size:16,className:"text-github-text-secondary"}):v.jsx(zf,{size:16,className:"text-github-text-secondary"}),v.jsx("span",{className:"text-sm text-github-text-primary font-medium flex-1 overflow-hidden text-ellipsis whitespace-nowrap",title:u.name,children:u.name}),b&&v.jsx("span",{className:"bg-github-warning/20 text-github-warning text-xs px-1.5 py-0.5 rounded-full font-medium ml-auto flex items-center gap-1",children:v.jsx(ns,{size:12})})]}),(f||!u.name)&&u.children.map(E=>x(E,c+1))]},u.path)}else if(u.file){const f=y(u.file.path),w=r.has(u.file.path);return v.jsxs("div",{className:`flex items-center gap-2 px-4 py-2 hover:bg-github-bg-tertiary cursor-pointer transition-colors ${w?"opacity-70":""}`,style:{paddingLeft:`${c*16+16}px`},onClick:()=>t(u.file.path),children:[v.jsx(Lc,{checked:w,onChange:()=>{l(u.file.path)},title:w?"Mark as not reviewed":"Mark as reviewed",className:"z-10"}),p(u.file.status),v.jsx("span",{className:`text-sm text-github-text-primary flex-1 overflow-hidden text-ellipsis whitespace-nowrap ${w?"line-through text-github-text-muted":""}`,title:u.file.path,children:u.name}),f>0&&v.jsxs("span",{className:"bg-github-warning/20 text-github-warning text-xs px-1.5 py-0.5 rounded-full font-medium ml-auto flex items-center gap-1",children:[v.jsx(ns,{size:12}),f]})]},u.file.path)}return null};return v.jsxs("div",{className:"h-full flex flex-col",children:[v.jsxs("div",{className:"px-4 py-3 border-b border-github-border bg-github-bg-tertiary",children:[v.jsxs("h3",{className:"text-sm font-semibold text-github-text-primary m-0 mb-3",children:["Files changed (",e.length,")"]}),v.jsxs("div",{className:"relative",children:[v.jsx(Hf,{size:16,className:"absolute left-3 top-1/2 transform -translate-y-1/2 text-github-text-muted"}),v.jsx("input",{type:"text",placeholder:"Filter files...",value:d,onChange:u=>m(u.target.value),className:"w-full pl-9 pr-3 py-2 text-sm bg-github-bg-primary border border-github-border rounded-md focus:outline-none focus:border-github-accent text-github-text-primary placeholder-github-text-muted"})]})]}),v.jsx("div",{className:"flex-1 overflow-y-auto",children:k.children&&k.children.map(u=>x(u))})]})}function ay(e){const[t,n]=O.useState([]),r=e?`reviewit-comments-${e}`:"reviewit-comments";return O.useEffect(()=>{const m=localStorage.getItem(r);if(m)try{n(JSON.parse(m))}catch(y){console.error("Failed to parse saved comments:",y)}},[r]),O.useEffect(()=>{localStorage.setItem(r,JSON.stringify(t))},[t,r]),{comments:t,addComment:(m,y,h,k)=>{console.log("Adding comment with codeContent:",k);const p={id:`${m}:${y}:${Date.now()}`,file:m,line:y,body:h,timestamp:new Date().toISOString(),codeContent:k};return n(g=>[...g,p]),p},removeComment:m=>{n(y=>y.filter(h=>h.id!==m))},updateComment:(m,y)=>{n(h=>h.map(k=>k.id===m?{...k,body:y}:k))},clearAllComments:()=>{n([]),localStorage.removeItem(r)},generatePrompt:m=>`${m.file}:${m.line}
175
175
  ${m.body}`,generateAllCommentsPrompt:()=>t.length===0?"No comments available.":t.map(y=>`${y.file}:${y.line}
176
176
  ${y.body}`).join(`
177
177
  =====
178
- `)}}function sy(){const[e,t]=O.useState(null),[n,r]=O.useState(new Set),[l,o]=O.useState("side-by-side"),[i,a]=O.useState(!0),[s,d]=O.useState(!0),[m,y]=O.useState(null),[h,k]=O.useState(!1),[p,g]=O.useState(320),{comments:x,addComment:u,removeComment:c,updateComment:f,generatePrompt:w,generateAllCommentsPrompt:b}=ay(e==null?void 0:e.commit),E=T=>{T.preventDefault();const W=T.clientX,D=p,G=We=>{const L=Math.max(200,Math.min(600,D+(We.clientX-W)));g(L)},ue=()=>{document.removeEventListener("mousemove",G),document.removeEventListener("mouseup",ue)};document.addEventListener("mousemove",G),document.addEventListener("mouseup",ue)};O.useEffect(()=>{N()},[i]);const C=T=>{const W=["pnpm-lock.yaml","package-lock.json","yarn.lock","Cargo.lock","Gemfile.lock","composer.lock","Pipfile.lock","poetry.lock","go.sum","mix.lock"],D=T.split("/").pop()||"";return W.includes(D)},N=async()=>{try{const T=await fetch(`/api/diff?ignoreWhitespace=${i}`);if(!T.ok)throw new Error("Failed to fetch diff data");const W=await T.json();t(W);const D=W.files.filter(G=>C(G.path)).map(G=>G.path);D.length>0&&r(G=>new Set([...G,...D]))}catch(T){y(T instanceof Error?T.message:"Unknown error")}finally{d(!1)}},R=(T,W,D,G)=>(u(T,W,D,G),Promise.resolve()),A=async()=>{try{const T=b();await navigator.clipboard.writeText(T),k(!0),setTimeout(()=>k(!1),2e3)}catch(T){console.error("Failed to copy all comments prompt:",T)}},z=T=>{r(W=>{const D=new Set(W);return D.has(T)?D.delete(T):(D.add(T),setTimeout(()=>{const ue=document.getElementById(`file-${T.replace(/[^a-zA-Z0-9]/g,"-")}`);ue&&ue.scrollIntoView({behavior:"instant",block:"start"})},100)),D})};return s?v.jsx("div",{className:"flex items-center justify-center h-screen bg-github-bg-primary",children:v.jsx("div",{className:"text-github-text-secondary text-base",children:"Loading diff..."})}):m?v.jsxs("div",{className:"flex flex-col items-center justify-center h-screen bg-github-bg-primary text-center gap-2",children:[v.jsx("h2",{className:"text-github-danger text-2xl mb-2",children:"Error"}),v.jsx("p",{className:"text-github-text-secondary text-base",children:m})]}):e?v.jsxs("div",{className:"h-screen flex flex-col",children:[v.jsxs("header",{className:"bg-github-bg-secondary border-b border-github-border flex items-center",children:[v.jsx("div",{className:"px-4 py-3 border-r border-github-border",style:{width:`${p}px`,minWidth:"200px",maxWidth:"600px"},children:v.jsxs("h1",{className:"text-lg font-semibold text-github-text-primary m-0 flex items-center gap-2",children:[v.jsx(_f,{size:20}),"ReviewIt"]})}),v.jsx("div",{className:"w-1"}),v.jsxs("div",{className:"flex-1 px-4 py-3 flex items-center justify-between gap-4",children:[v.jsxs("div",{className:"flex items-center gap-3",children:[v.jsxs("div",{className:"flex bg-github-bg-tertiary border border-github-border rounded-md p-1",children:[v.jsxs("button",{onClick:()=>o("side-by-side"),className:`px-3 py-1.5 text-xs font-medium rounded transition-all duration-200 flex items-center gap-1.5 cursor-pointer ${l==="side-by-side"?"bg-github-bg-primary text-github-text-primary shadow-sm":"text-github-text-secondary hover:text-github-text-primary"}`,children:[v.jsx(Nf,{size:14}),"Side by Side"]}),v.jsxs("button",{onClick:()=>o("inline"),className:`px-3 py-1.5 text-xs font-medium rounded transition-all duration-200 flex items-center gap-1.5 cursor-pointer ${l==="inline"?"bg-github-bg-primary text-github-text-primary shadow-sm":"text-github-text-secondary hover:text-github-text-primary"}`,children:[v.jsx(xf,{size:14}),"Inline"]})]}),v.jsx(Lc,{checked:i,onChange:a,label:"Ignore Whitespace",title:i?"Show whitespace changes":"Ignore whitespace changes"})]}),v.jsxs("div",{className:"flex items-center gap-4 text-sm text-github-text-secondary",children:[x.length>0&&v.jsxs("button",{onClick:A,className:"text-xs px-3 py-1.5 bg-yellow-900/20 text-yellow-200 border border-yellow-600/50 rounded hover:bg-yellow-800/30 hover:border-yellow-500 transition-all whitespace-nowrap flex items-center gap-1.5",title:`Copy all ${x.length} comments to Claude Code`,children:[v.jsx(bc,{size:12}),h?"Copied All!":`Copy All Prompt (${x.length})`]}),v.jsxs("span",{children:["Reviewing:"," ",v.jsx("code",{className:"bg-github-bg-tertiary px-1.5 py-0.5 rounded text-xs text-github-text-primary",children:e.commit.includes("..")?v.jsxs(v.Fragment,{children:[v.jsxs("span",{className:"text-github-text-secondary font-medium",children:[e.commit.split("..")[0],".."]}),v.jsx("span",{className:"font-medium",children:e.commit.split("..")[1]})]}):e.commit})]}),v.jsxs("span",{children:[e.files.length," file",e.files.length!==1?"s":""," changed"]})]})]})]}),v.jsxs("div",{className:"flex flex-1 overflow-hidden",children:[v.jsx("aside",{className:"bg-github-bg-secondary border-r border-github-border overflow-y-auto",style:{width:`${p}px`,minWidth:"200px",maxWidth:"600px"},children:v.jsx(iy,{files:e.files,onScrollToFile:T=>{const W=document.getElementById(`file-${T.replace(/[^a-zA-Z0-9]/g,"-")}`);W&&W.scrollIntoView({behavior:"smooth",block:"start"})},comments:x,reviewedFiles:n,onToggleReviewed:z})}),v.jsx("div",{className:"w-1 bg-github-border hover:bg-github-text-muted cursor-col-resize transition-colors",onMouseDown:E,title:"Drag to resize file list"}),v.jsx("main",{className:"flex-1 overflow-y-auto",children:e.files.map(T=>v.jsx("div",{id:`file-${T.path.replace(/[^a-zA-Z0-9]/g,"-")}`,className:"mb-6",children:v.jsx(ly,{file:T,comments:x.filter(W=>W.file===T.path),diffMode:l,reviewedFiles:n,onToggleReviewed:z,onAddComment:R,onGeneratePrompt:w,onRemoveComment:c,onUpdateComment:f})},T.path))})]})]}):v.jsxs("div",{className:"flex flex-col items-center justify-center h-screen bg-github-bg-primary text-center gap-2",children:[v.jsx("h2",{className:"text-github-danger text-2xl mb-2",children:"No data"}),v.jsx("p",{className:"text-github-text-secondary text-base",children:"No diff data available"})]})}to.createRoot(document.getElementById("root")).render(v.jsx(ei.StrictMode,{children:v.jsx(sy,{})}));
178
+ `)}}function sy(){const[e,t]=O.useState(null),[n,r]=O.useState(new Set),[l,o]=O.useState("side-by-side"),[i,a]=O.useState(!0),[s,d]=O.useState(!0),[m,y]=O.useState(null),[h,k]=O.useState(!1),[p,g]=O.useState(320),{comments:x,addComment:u,removeComment:c,updateComment:f,generatePrompt:w,generateAllCommentsPrompt:b}=ay(e==null?void 0:e.commit),E=T=>{T.preventDefault();const W=T.clientX,D=p,G=We=>{const L=Math.max(200,Math.min(600,D+(We.clientX-W)));g(L)},ue=()=>{document.removeEventListener("mousemove",G),document.removeEventListener("mouseup",ue)};document.addEventListener("mousemove",G),document.addEventListener("mouseup",ue)};O.useEffect(()=>{N()},[i]),O.useEffect(()=>{const T=new EventSource("/api/heartbeat");return T.onopen=()=>{console.log("Connected to server heartbeat")},T.onerror=()=>{console.log("Server connection lost"),T.close()},()=>{T.close()}},[]);const C=T=>{const W=["pnpm-lock.yaml","package-lock.json","yarn.lock","Cargo.lock","Gemfile.lock","composer.lock","Pipfile.lock","poetry.lock","go.sum","mix.lock"],D=T.split("/").pop()||"";return W.includes(D)},N=async()=>{try{const T=await fetch(`/api/diff?ignoreWhitespace=${i}`);if(!T.ok)throw new Error("Failed to fetch diff data");const W=await T.json();t(W);const D=W.files.filter(G=>C(G.path)).map(G=>G.path);D.length>0&&r(G=>new Set([...G,...D]))}catch(T){y(T instanceof Error?T.message:"Unknown error")}finally{d(!1)}},R=(T,W,D,G)=>(u(T,W,D,G),Promise.resolve()),A=async()=>{try{const T=b();await navigator.clipboard.writeText(T),k(!0),setTimeout(()=>k(!1),2e3)}catch(T){console.error("Failed to copy all comments prompt:",T)}},z=T=>{r(W=>{const D=new Set(W);return D.has(T)?D.delete(T):(D.add(T),setTimeout(()=>{const ue=document.getElementById(`file-${T.replace(/[^a-zA-Z0-9]/g,"-")}`);ue&&ue.scrollIntoView({behavior:"instant",block:"start"})},100)),D})};return s?v.jsx("div",{className:"flex items-center justify-center h-screen bg-github-bg-primary",children:v.jsx("div",{className:"text-github-text-secondary text-base",children:"Loading diff..."})}):m?v.jsxs("div",{className:"flex flex-col items-center justify-center h-screen bg-github-bg-primary text-center gap-2",children:[v.jsx("h2",{className:"text-github-danger text-2xl mb-2",children:"Error"}),v.jsx("p",{className:"text-github-text-secondary text-base",children:m})]}):e?v.jsxs("div",{className:"h-screen flex flex-col",children:[v.jsxs("header",{className:"bg-github-bg-secondary border-b border-github-border flex items-center",children:[v.jsx("div",{className:"px-4 py-3 border-r border-github-border",style:{width:`${p}px`,minWidth:"200px",maxWidth:"600px"},children:v.jsxs("h1",{className:"text-lg font-semibold text-github-text-primary m-0 flex items-center gap-2",children:[v.jsx(_f,{size:20}),"ReviewIt"]})}),v.jsx("div",{className:"w-1"}),v.jsxs("div",{className:"flex-1 px-4 py-3 flex items-center justify-between gap-4",children:[v.jsxs("div",{className:"flex items-center gap-3",children:[v.jsxs("div",{className:"flex bg-github-bg-tertiary border border-github-border rounded-md p-1",children:[v.jsxs("button",{onClick:()=>o("side-by-side"),className:`px-3 py-1.5 text-xs font-medium rounded transition-all duration-200 flex items-center gap-1.5 cursor-pointer ${l==="side-by-side"?"bg-github-bg-primary text-github-text-primary shadow-sm":"text-github-text-secondary hover:text-github-text-primary"}`,children:[v.jsx(Nf,{size:14}),"Side by Side"]}),v.jsxs("button",{onClick:()=>o("inline"),className:`px-3 py-1.5 text-xs font-medium rounded transition-all duration-200 flex items-center gap-1.5 cursor-pointer ${l==="inline"?"bg-github-bg-primary text-github-text-primary shadow-sm":"text-github-text-secondary hover:text-github-text-primary"}`,children:[v.jsx(xf,{size:14}),"Inline"]})]}),v.jsx(Lc,{checked:i,onChange:a,label:"Ignore Whitespace",title:i?"Show whitespace changes":"Ignore whitespace changes"})]}),v.jsxs("div",{className:"flex items-center gap-4 text-sm text-github-text-secondary",children:[x.length>0&&v.jsxs("button",{onClick:A,className:"text-xs px-3 py-1.5 bg-yellow-900/20 text-yellow-200 border border-yellow-600/50 rounded hover:bg-yellow-800/30 hover:border-yellow-500 transition-all whitespace-nowrap flex items-center gap-1.5",title:`Copy all ${x.length} comments to Claude Code`,children:[v.jsx(bc,{size:12}),h?"Copied All!":`Copy All Prompt (${x.length})`]}),v.jsxs("span",{children:["Reviewing:"," ",v.jsx("code",{className:"bg-github-bg-tertiary px-1.5 py-0.5 rounded text-xs text-github-text-primary",children:e.commit.includes("..")?v.jsxs(v.Fragment,{children:[v.jsxs("span",{className:"text-github-text-secondary font-medium",children:[e.commit.split("..")[0],".."]}),v.jsx("span",{className:"font-medium",children:e.commit.split("..")[1]})]}):e.commit})]}),v.jsxs("span",{children:[e.files.length," file",e.files.length!==1?"s":""," changed"]})]})]})]}),v.jsxs("div",{className:"flex flex-1 overflow-hidden",children:[v.jsx("aside",{className:"bg-github-bg-secondary border-r border-github-border overflow-y-auto",style:{width:`${p}px`,minWidth:"200px",maxWidth:"600px"},children:v.jsx(iy,{files:e.files,onScrollToFile:T=>{const W=document.getElementById(`file-${T.replace(/[^a-zA-Z0-9]/g,"-")}`);W&&W.scrollIntoView({behavior:"smooth",block:"start"})},comments:x,reviewedFiles:n,onToggleReviewed:z})}),v.jsx("div",{className:"w-1 bg-github-border hover:bg-github-text-muted cursor-col-resize transition-colors",onMouseDown:E,title:"Drag to resize file list"}),v.jsx("main",{className:"flex-1 overflow-y-auto",children:e.files.map(T=>v.jsx("div",{id:`file-${T.path.replace(/[^a-zA-Z0-9]/g,"-")}`,className:"mb-6",children:v.jsx(ly,{file:T,comments:x.filter(W=>W.file===T.path),diffMode:l,reviewedFiles:n,onToggleReviewed:z,onAddComment:R,onGeneratePrompt:w,onRemoveComment:c,onUpdateComment:f})},T.path))})]})]}):v.jsxs("div",{className:"flex flex-col items-center justify-center h-screen bg-github-bg-primary text-center gap-2",children:[v.jsx("h2",{className:"text-github-danger text-2xl mb-2",children:"No data"}),v.jsx("p",{className:"text-github-text-secondary text-base",children:"No diff data available"})]})}to.createRoot(document.getElementById("root")).render(v.jsx(ei.StrictMode,{children:v.jsx(sy,{})}));
@@ -10,7 +10,7 @@
10
10
  <link rel="icon" type="image/png" sizes="512x512" href="/icon-512x512.png" />
11
11
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
12
12
  <title>ReviewIt - Git Diff Viewer</title>
13
- <script type="module" crossorigin src="/assets/index-DlET-Ch1.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-CpfKzjSE.js"></script>
14
14
  <link rel="stylesheet" crossorigin href="/assets/index-CpclbaYk.css">
15
15
  </head>
16
16
  <body>
@@ -30,6 +30,27 @@ export async function startServer(options) {
30
30
  }
31
31
  res.json({ ...diffData, ignoreWhitespace });
32
32
  });
33
+ // SSE endpoint to detect when tab is closed
34
+ app.get('/api/heartbeat', (req, res) => {
35
+ res.writeHead(200, {
36
+ 'Content-Type': 'text/event-stream',
37
+ 'Cache-Control': 'no-cache',
38
+ Connection: 'keep-alive',
39
+ 'Access-Control-Allow-Origin': '*',
40
+ });
41
+ // Send initial heartbeat
42
+ res.write('data: connected\n\n');
43
+ // Send heartbeat every 5 seconds
44
+ const heartbeatInterval = setInterval(() => {
45
+ res.write('data: heartbeat\n\n');
46
+ }, 5000);
47
+ // When client disconnects (tab closed, navigation, etc.)
48
+ req.on('close', () => {
49
+ clearInterval(heartbeatInterval);
50
+ console.log('Client disconnected, shutting down server...');
51
+ process.exit(0);
52
+ });
53
+ });
33
54
  // Always runs in production mode when distributed as a CLI tool
34
55
  const isProduction = process.env.NODE_ENV === 'production' || process.env.NODE_ENV !== 'development';
35
56
  if (isProduction) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "difit",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "A lightweight command-line tool that spins up a local web server to display Git commit diffs in a GitHub-like Files changed view",
5
5
  "type": "module",
6
6
  "engines": {