@hienlh/ppm 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/web/assets/api-client-Bnf9LAt4.js +1 -0
  2. package/dist/web/assets/arrow-up-from-line-BXL5dtbG.js +1 -0
  3. package/dist/web/assets/button-BxijdhtM.js +1 -0
  4. package/dist/web/assets/chat-tab-BZopEuub.js +61 -0
  5. package/dist/web/assets/code-editor-hbllHzj7.js +2 -0
  6. package/dist/web/assets/createLucideIcon-Dy1wlrF7.js +1 -0
  7. package/dist/web/assets/dialog-RczsXsmw.js +45 -0
  8. package/dist/web/assets/diff-viewer-D6ixPlNB.js +4 -0
  9. package/dist/web/assets/dist-CSp7ir0r.js +46 -0
  10. package/dist/web/assets/external-link-WSiY-639.js +1 -0
  11. package/dist/web/assets/git-graph-DXMB_DoT.js +1 -0
  12. package/dist/web/assets/git-status-panel-D8ZUQrRF.js +1 -0
  13. package/dist/web/assets/index-DGSLw2GE.js +10 -0
  14. package/dist/web/assets/index-DYd_2slk.css +2 -0
  15. package/dist/web/assets/jsx-runtime-BnxRlLMJ.js +1 -0
  16. package/dist/web/assets/project-list-DWVXEimw.js +1 -0
  17. package/dist/web/assets/react-Uzd0zARU.js +1 -0
  18. package/dist/web/assets/refresh-cw-DtopuYJf.js +1 -0
  19. package/dist/web/assets/settings-tab-DJRzIAuP.js +1 -0
  20. package/dist/web/assets/terminal-tab-BrP-ENHg.css +1 -0
  21. package/dist/web/assets/terminal-tab-CbwaI-oq.js +36 -0
  22. package/dist/web/assets/trash-2-CHLebaNh.js +1 -0
  23. package/dist/web/assets/utils-Cgi2TYRi.js +1 -0
  24. package/dist/web/assets/x-BISR7bpK.js +1 -0
  25. package/dist/web/icon-192.svg +5 -0
  26. package/dist/web/icon-512.svg +5 -0
  27. package/dist/web/index.html +25 -0
  28. package/dist/web/manifest.webmanifest +1 -0
  29. package/dist/web/registerSW.js +1 -0
  30. package/dist/web/sw.js +1 -0
  31. package/dist/web/workbox-3e722498.js +1 -0
  32. package/package.json +2 -1
  33. package/src/server/index.ts +17 -3
  34. package/.claude/agent-memory/tester/MEMORY.md +0 -3
  35. package/.claude/agent-memory/tester/project-ppm-test-conventions.md +0 -32
  36. package/.github/workflows/release.yml +0 -46
  37. package/plans/260314-2009-ppm-implementation/phase-01-project-skeleton.md +0 -81
  38. package/plans/260314-2009-ppm-implementation/phase-02-backend-core.md +0 -148
  39. package/plans/260314-2009-ppm-implementation/phase-03-frontend-shell.md +0 -256
  40. package/plans/260314-2009-ppm-implementation/phase-04-file-explorer-editor.md +0 -120
  41. package/plans/260314-2009-ppm-implementation/phase-05-web-terminal.md +0 -174
  42. package/plans/260314-2009-ppm-implementation/phase-06-git-integration.md +0 -244
  43. package/plans/260314-2009-ppm-implementation/phase-07-ai-chat.md +0 -242
  44. package/plans/260314-2009-ppm-implementation/phase-08-cli-commands.md +0 -143
  45. package/plans/260314-2009-ppm-implementation/phase-09-pwa-build-deploy.md +0 -209
  46. package/plans/260314-2009-ppm-implementation/phase-10-testing.md +0 -311
  47. package/plans/260314-2009-ppm-implementation/plan.md +0 -202
  48. package/plans/260315-0356-project-scoped-api-refactor/phase-01-backend-project-router.md +0 -145
  49. package/plans/260315-0356-project-scoped-api-refactor/phase-02-frontend-api-migration.md +0 -107
  50. package/plans/260315-0356-project-scoped-api-refactor/phase-03-per-project-tabs.md +0 -100
  51. package/plans/260315-0356-project-scoped-api-refactor/phase-04-websocket-migration.md +0 -66
  52. package/plans/260315-0356-project-scoped-api-refactor/plan.md +0 -87
  53. package/plans/reports/brainstorm-260314-1938-final-techstack.md +0 -342
  54. package/plans/reports/docs-manager-260315-1314-documentation-creation.md +0 -386
  55. package/plans/reports/fullstack-developer-260314-2252-phase-02-backend-core.md +0 -57
  56. package/plans/reports/fullstack-developer-260314-2253-phase-03-frontend-shell.md +0 -70
  57. package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-api-terminal-ws.md +0 -49
  58. package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-explorer-editor-terminal.md +0 -52
  59. package/plans/reports/fullstack-developer-260314-2307-ai-chat-phase7.md +0 -58
  60. package/plans/reports/fullstack-developer-260314-2307-phase-06-git-integration.md +0 -33
  61. package/plans/reports/research-260314-1911-ppm-tech-stack.md +0 -318
  62. package/plans/reports/research-260314-1930-claude-code-integration.md +0 -293
  63. package/plans/reports/researcher-260314-2232-node-pty-bun-crash-analysis.md +0 -305
  64. package/plans/reports/researcher-260314-2232-ui-style.md +0 -942
  65. package/plans/reports/researcher-260315-0300-opcode-claude-interaction.md +0 -745
  66. package/plans/reports/researcher-260315-0303-opcode-deep-analysis.md +0 -742
  67. package/plans/reports/researcher-260315-0305-claude-agent-sdk-github-research.md +0 -423
  68. package/plans/reports/tester-260314-2053-initial-test-suite.md +0 -81
  69. package/repomix-output.xml +0 -23745
  70. package/tests/integration/api/chat-routes.test.ts +0 -95
  71. package/tests/integration/claude-agent-sdk-integration.test.ts +0 -228
  72. package/tests/integration/ws/chat-websocket.test.ts +0 -312
  73. package/tests/test-setup.ts +0 -5
  74. package/tests/unit/providers/claude-agent-sdk.test.ts +0 -339
  75. package/tests/unit/providers/mock-provider.test.ts +0 -143
  76. package/tests/unit/services/chat-service.test.ts +0 -100
@@ -0,0 +1 @@
1
+ import{t as e}from"./createLucideIcon-Dy1wlrF7.js";var t=e(`external-link`,[[`path`,{d:`M15 3h6v6`,key:`1q9fwt`}],[`path`,{d:`M10 14 21 3`,key:`gplh6r`}],[`path`,{d:`M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6`,key:`a6xqqp`}]]);export{t};
@@ -0,0 +1 @@
1
+ import{i as e,n as t,t as n}from"./jsx-runtime-BnxRlLMJ.js";import{t as r}from"./button-BxijdhtM.js";import{t as i}from"./createLucideIcon-Dy1wlrF7.js";import{t as a}from"./arrow-up-from-line-BXL5dtbG.js";import{t as o}from"./external-link-WSiY-639.js";import{a as s,r as c,t as l}from"./api-client-Bnf9LAt4.js";import{t as u}from"./refresh-cw-DtopuYJf.js";import{t as d}from"./trash-2-CHLebaNh.js";import{a as f,i as p,n as m,o as h,t as g}from"./dialog-RczsXsmw.js";import{a as _,c as v,h as y,i as b,o as x,r as ee,s as S,u as te}from"./index-DGSLw2GE.js";var ne=i(`cherry`,[[`path`,{d:`M2 17a5 5 0 0 0 10 0c0-2.76-2.5-5-5-3-2.5-2-5 .24-5 3Z`,key:`cvxqlc`}],[`path`,{d:`M12 17a5 5 0 0 0 10 0c0-2.76-2.5-5-5-3-2.5-2-5 .24-5 3Z`,key:`1ostrc`}],[`path`,{d:`M7 14c3.22-2.91 4.29-8.75 5-12 1.66 2.38 4.94 9 5 12`,key:`hqx58h`}],[`path`,{d:`M22 9c-4.29 0-7.14-2.33-10-7 5.71 0 10 4.67 10 7Z`,key:`eykp1o`}]]),re=i(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]),C=i(`git-merge`,[[`circle`,{cx:`18`,cy:`18`,r:`3`,key:`1xkwt0`}],[`circle`,{cx:`6`,cy:`6`,r:`3`,key:`1lh9wr`}],[`path`,{d:`M6 21V9a9 9 0 0 0 9 9`,key:`7kw0sc`}]]),ie=i(`grip-vertical`,[[`circle`,{cx:`9`,cy:`12`,r:`1`,key:`1vctgf`}],[`circle`,{cx:`9`,cy:`5`,r:`1`,key:`hp0tcf`}],[`circle`,{cx:`9`,cy:`19`,r:`1`,key:`fkjjf6`}],[`circle`,{cx:`15`,cy:`12`,r:`1`,key:`1tmaij`}],[`circle`,{cx:`15`,cy:`5`,r:`1`,key:`19l28e`}],[`circle`,{cx:`15`,cy:`19`,r:`1`,key:`f4zoj3`}]]),ae=i(`rotate-ccw`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}]]),w=i(`tag`,[[`path`,{d:`M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z`,key:`vktsd0`}],[`circle`,{cx:`7.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`kqv944`}]]),T=e(t(),1),E=n(),D=[`#4fc3f7`,`#81c784`,`#ffb74d`,`#e57373`,`#ba68c8`,`#4dd0e1`,`#aed581`,`#ff8a65`,`#f06292`,`#7986cb`],O=32,k=20,oe=5;function A({metadata:e}){let t=e?.projectName,[n,i]=(0,T.useState)(null),[a,o]=(0,T.useState)(!0),[d,C]=(0,T.useState)(null),[A,j]=(0,T.useState)(!1),[M,N]=(0,T.useState)({type:null}),[P,F]=(0,T.useState)(``),[I,L]=(0,T.useState)(null),[R,z]=(0,T.useState)([]),[ce,B]=(0,T.useState)(!1),{openTab:V}=te(),H=(0,T.useCallback)(async()=>{if(t)try{o(!0),i(await l.get(`${c(t)}/git/graph?max=200`)),C(null)}catch(e){C(e instanceof Error?e.message:`Failed to fetch graph`)}finally{o(!1)}},[t]);(0,T.useEffect)(()=>{H()},[H]);let U=async(e,n)=>{if(t){j(!0);try{await l.post(`${c(t)}${e}`,n),await H()}catch(e){C(e instanceof Error?e.message:`Action failed`)}finally{j(!1)}}},W=e=>U(`/git/checkout`,{ref:e}),le=e=>U(`/git/cherry-pick`,{hash:e}),ue=e=>U(`/git/revert`,{hash:e}),de=e=>U(`/git/merge`,{source:e}),fe=e=>U(`/git/branch/delete`,{name:e}),pe=e=>U(`/git/push`,{branch:e}),G=async(e,t)=>{if(n?.branches.some(t=>t.name===e||t.name.endsWith(`/${e}`))){if(!window.confirm(`Branch "${e}" already exists.\nDelete it and recreate from this commit?`))return;await U(`/git/branch/delete`,{name:e})}await U(`/git/branch/create`,{name:e,from:t})},K=(e,t)=>U(`/git/tag`,{name:e,hash:t}),me=async e=>{if(t)try{let n=await l.get(`${c(t)}/git/pr-url?branch=${encodeURIComponent(e)}`);n.url&&window.open(n.url,`_blank`)}catch{}},q=e=>{navigator.clipboard.writeText(e)},he=async e=>{if(I?.hash===e.hash){L(null);return}L(e),B(!0);try{let n=e.parents[0]??``,r=n?`ref1=${encodeURIComponent(n)}&`:``,i=await l.get(`${c(t)}/git/diff-stat?${r}ref2=${encodeURIComponent(e.hash)}`);z(Array.isArray(i)?i:[])}catch(e){console.error(`diff-stat error:`,e),z([])}finally{B(!1)}},ge=e=>{let n=e.parents[0];V({type:`git-diff`,title:`Diff ${e.abbreviatedHash}`,closable:!0,metadata:{projectName:t,ref1:n??void 0,ref2:e.hash},projectId:t??null})},{laneMap:J,maxLane:_e}=(0,T.useMemo)(()=>{let e=new Map;if(!n)return{laneMap:e,maxLane:0};let t=0,r=new Map;for(let i of n.commits){let n=r.get(i.hash);n===void 0&&(n=t++),e.set(i.hash,n),r.delete(i.hash);for(let e=0;e<i.parents.length;e++){let a=i.parents[e];r.has(a)||r.set(a,e===0?n:t++)}}return{laneMap:e,maxLane:Math.max(t-1,0)}},[n]),Y=n?.branches.find(e=>e.current),ve=(0,T.useMemo)(()=>{let e=new Map;if(!n)return e;for(let t of n.branches){let n=e.get(t.commitHash)??[];n.push({name:t.name,type:`branch`}),e.set(t.commitHash,n)}for(let t of n.commits)for(let n of t.refs)if(n.startsWith(`tag: `)){let r=n.replace(`tag: `,``),i=e.get(t.hash)??[];i.push({name:r,type:`tag`}),e.set(t.hash,i)}return e},[n]),ye=(0,T.useMemo)(()=>{if(!n)return[];let e=[];for(let t=0;t<n.commits.length;t++){let r=n.commits[t],i=J.get(r.hash)??0,a=D[i%D.length];for(let o of r.parents){let s=n.commits.findIndex(e=>e.hash===o);if(s<0)continue;let c=J.get(o)??0,l=D[c%D.length],u=i*k+k/2,d=t*O+O/2,f=c*k+k/2,p=s*O+O/2,m,h=r.parents.indexOf(o)>0;if(u===f)m=`M ${u} ${d} L ${f} ${p}`;else if(h){let e=d+O;m=`M ${u} ${d} C ${u} ${e} ${f} ${d} ${f} ${e} L ${f} ${p}`}else{let e=p-O;m=`M ${u} ${d} L ${u} ${e} C ${u} ${p} ${f} ${e} ${f} ${p}`}let g=r.parents.indexOf(o)===0?a:l;e.push({d:m,color:g})}}return e},[n,J]);(_e+1)*k+k;let X=(n?.commits.length??0)*O,[Z,be]=(0,T.useState)((typeof window<`u`&&window.innerWidth<768?6:10)*k+k),Q=(0,T.useRef)(!1),$=(0,T.useCallback)(e=>{Q.current=!0;let t=Z,n=n=>{if(!Q.current)return;let r=`touches`in n?n.touches[0].clientX:n.clientX;be(Math.max(40,t+r-e))},r=()=>{Q.current=!1,window.removeEventListener(`mousemove`,n),window.removeEventListener(`mouseup`,r),window.removeEventListener(`touchmove`,n),window.removeEventListener(`touchend`,r)};window.addEventListener(`mousemove`,n),window.addEventListener(`mouseup`,r),window.addEventListener(`touchmove`,n,{passive:!1}),window.addEventListener(`touchend`,r)},[Z]),xe=(0,T.useCallback)(e=>{e.preventDefault(),$(e.clientX)},[$]),Se=(0,T.useCallback)(e=>{$(e.touches[0].clientX)},[$]);if(!t)return(0,E.jsx)(`div`,{className:`flex items-center justify-center h-full text-muted-foreground text-sm`,children:`No project selected.`});if(a&&!n)return(0,E.jsxs)(`div`,{className:`flex items-center justify-center h-full gap-2 text-muted-foreground`,children:[(0,E.jsx)(s,{className:`size-5 animate-spin`}),(0,E.jsx)(`span`,{className:`text-sm`,children:`Loading git graph...`})]});if(d&&!n)return(0,E.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-2 text-destructive text-sm`,children:[(0,E.jsx)(`p`,{children:d}),(0,E.jsx)(r,{variant:`outline`,size:`sm`,onClick:H,children:`Retry`})]});function Ce(e){let t=new Date(e),n=new Date().getTime()-t.getTime(),r=Math.floor(n/6e4);if(r<1)return`just now`;if(r<60)return`${r}m ago`;let i=Math.floor(r/60);if(i<24)return`${i}h ago`;let a=Math.floor(i/24);if(a<30)return`${a}d ago`;let o=Math.floor(a/30);return o<12?`${o}mo ago`:`${Math.floor(o/12)}y ago`}return(0,E.jsxs)(`div`,{className:`flex flex-col h-full`,children:[(0,E.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-2 border-b`,children:[(0,E.jsxs)(`span`,{className:`text-sm font-medium`,children:[`Git Graph`,Y?` - ${Y.name}`:``]}),(0,E.jsx)(r,{variant:`ghost`,size:`icon-xs`,onClick:H,disabled:A,children:(0,E.jsx)(u,{className:a?`animate-spin`:``})})]}),d&&(0,E.jsx)(`div`,{className:`px-3 py-1.5 text-xs text-destructive bg-destructive/10`,children:d}),(0,E.jsx)(`div`,{className:`flex-1 overflow-y-auto overflow-x-auto md:overflow-x-hidden`,children:(0,E.jsxs)(`div`,{className:`flex min-w-max md:min-w-0`,style:{height:`${X}px`},children:[(0,E.jsxs)(`div`,{className:`sticky left-0 z-10 shrink-0 bg-background`,style:{width:`${Z}px`},children:[(0,E.jsxs)(`svg`,{width:Z,height:X,children:[ye.map((e,t)=>(0,E.jsx)(`path`,{d:e.d,stroke:e.color,strokeWidth:2,fill:`none`},t)),n?.commits.map((e,t)=>{let n=J.get(e.hash)??0,r=n*k+k/2,i=t*O+O/2,a=D[n%D.length];return(0,E.jsx)(`circle`,{cx:r,cy:i,r:oe,fill:a,stroke:`#0f1419`,strokeWidth:2},e.hash)})]}),(0,E.jsx)(`div`,{className:`absolute top-0 right-0 w-3 md:w-2 h-full cursor-col-resize hover:bg-primary/20 flex items-center justify-center bg-primary/10 md:bg-transparent`,onMouseDown:xe,onTouchStart:Se,children:(0,E.jsx)(ie,{className:`size-3 text-muted-foreground md:opacity-0 md:hover:opacity-100`})})]}),(0,E.jsx)(`div`,{className:`flex-1 min-w-[400px]`,children:n?.commits.map((e,t)=>{let n=D[(J.get(e.hash)??0)%D.length],r=ve.get(e.hash)??[],i=r.filter(e=>e.type===`branch`),a=r.filter(e=>e.type===`tag`);return(0,E.jsxs)(b,{children:[(0,E.jsx)(v,{asChild:!0,children:(0,E.jsx)(`div`,{className:`flex items-center hover:bg-muted/50 cursor-pointer text-sm border-b border-border/30 ${I?.hash===e.hash?`bg-primary/10`:``}`,style:{height:`${O}px`},onClick:()=>he(e),children:(0,E.jsxs)(`div`,{className:`flex items-center gap-2 flex-1 min-w-0 px-2`,children:[(0,E.jsx)(`span`,{className:`font-mono text-xs text-muted-foreground w-14 shrink-0`,children:e.abbreviatedHash}),i.map(e=>(0,E.jsx)(se,{label:e,color:n,currentBranch:Y,onCheckout:W,onMerge:de,onPush:pe,onCreatePr:me,onDelete:fe},`branch-${e.name}`)),a.map(e=>(0,E.jsxs)(`span`,{className:`inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] font-medium shrink-0 bg-amber-500/20 text-amber-500 border border-amber-500/30`,children:[(0,E.jsx)(w,{className:`size-2.5`}),e.name]},`tag-${e.name}`)),(0,E.jsx)(`span`,{className:`flex-1 truncate`,children:e.subject}),(0,E.jsx)(`span`,{className:`text-xs text-muted-foreground shrink-0 hidden sm:inline`,children:e.authorName}),(0,E.jsx)(`span`,{className:`text-xs text-muted-foreground shrink-0 w-14 text-right`,children:Ce(e.authorDate)})]})})}),(0,E.jsxs)(_,{children:[(0,E.jsx)(x,{onClick:()=>W(e.hash),children:`Checkout`}),(0,E.jsxs)(x,{onClick:()=>{N({type:`branch`,hash:e.hash}),F(``)},children:[(0,E.jsx)(y,{className:`size-3`}),`Create Branch...`]}),(0,E.jsx)(S,{}),(0,E.jsxs)(x,{onClick:()=>le(e.hash),children:[(0,E.jsx)(ne,{className:`size-3`}),`Cherry Pick`]}),(0,E.jsxs)(x,{onClick:()=>ue(e.hash),children:[(0,E.jsx)(ae,{className:`size-3`}),`Revert`]}),(0,E.jsxs)(x,{onClick:()=>{N({type:`tag`,hash:e.hash}),F(``)},children:[(0,E.jsx)(w,{className:`size-3`}),`Create Tag...`]}),(0,E.jsx)(S,{}),(0,E.jsx)(x,{onClick:()=>ge(e),children:`View Diff`}),(0,E.jsxs)(x,{onClick:()=>q(e.hash),children:[(0,E.jsx)(re,{className:`size-3`}),`Copy Hash`]})]})]},e.hash)})})]})}),I&&(0,E.jsxs)(`div`,{className:`border-t bg-muted/30 max-h-[40%] overflow-auto`,children:[(0,E.jsxs)(`div`,{className:`px-3 py-2 border-b flex items-center justify-between`,children:[(0,E.jsxs)(`span`,{className:`text-sm font-medium truncate`,children:[I.abbreviatedHash,` — `,I.subject]}),(0,E.jsx)(r,{variant:`ghost`,size:`icon-xs`,onClick:()=>L(null),children:`✕`})]}),(0,E.jsxs)(`div`,{className:`px-3 py-2 text-xs space-y-1`,children:[(0,E.jsxs)(`div`,{className:`flex gap-4`,children:[(0,E.jsx)(`span`,{className:`text-muted-foreground`,children:`Author`}),(0,E.jsxs)(`span`,{children:[I.authorName,` <`,I.authorEmail,`>`]})]}),(0,E.jsxs)(`div`,{className:`flex gap-4`,children:[(0,E.jsx)(`span`,{className:`text-muted-foreground`,children:`Date`}),(0,E.jsx)(`span`,{children:new Date(I.authorDate).toLocaleString()})]}),(0,E.jsxs)(`div`,{className:`flex gap-4`,children:[(0,E.jsx)(`span`,{className:`text-muted-foreground`,children:`Hash`}),(0,E.jsx)(`span`,{className:`font-mono cursor-pointer hover:text-primary`,onClick:()=>q(I.hash),children:I.hash})]}),I.parents.length>0&&(0,E.jsxs)(`div`,{className:`flex gap-4`,children:[(0,E.jsx)(`span`,{className:`text-muted-foreground`,children:`Parents`}),(0,E.jsx)(`span`,{className:`font-mono`,children:I.parents.map(e=>e.slice(0,7)).join(`, `)})]}),I.body&&(0,E.jsx)(`div`,{className:`mt-2 p-2 bg-background rounded text-xs whitespace-pre-wrap`,children:I.body})]}),(0,E.jsxs)(`div`,{className:`px-3 py-1 border-t`,children:[(0,E.jsx)(`div`,{className:`text-xs text-muted-foreground py-1`,children:ce?`Loading files...`:`${R.length} file${R.length===1?``:`s`} changed`}),R.map(e=>(0,E.jsxs)(`div`,{className:`flex items-center gap-2 py-0.5 text-xs hover:bg-muted/50 rounded px-1 cursor-pointer`,onClick:()=>V({type:`git-diff`,title:`Diff ${e.path.split(`/`).pop()}`,closable:!0,metadata:{projectName:t,ref1:I.parents[0]??void 0,ref2:I.hash,filePath:e.path},projectId:t??null}),children:[(0,E.jsx)(`span`,{className:`flex-1 truncate font-mono`,children:e.path}),e.additions>0&&(0,E.jsxs)(`span`,{className:`text-green-500`,children:[`+`,e.additions]}),e.deletions>0&&(0,E.jsxs)(`span`,{className:`text-red-500`,children:[`-`,e.deletions]})]},e.path))]})]}),(0,E.jsx)(g,{open:M.type!==null,onOpenChange:e=>{e||N({type:null})},children:(0,E.jsxs)(m,{children:[(0,E.jsx)(f,{children:(0,E.jsx)(h,{children:M.type===`branch`?`Create Branch`:`Create Tag`})}),(0,E.jsx)(ee,{placeholder:M.type===`branch`?`Branch name`:`Tag name`,value:P,onChange:e=>F(e.target.value),onKeyDown:e=>{e.key===`Enter`&&P.trim()&&(M.type===`branch`?G(P.trim(),M.hash):K(P.trim(),M.hash),N({type:null}))},autoFocus:!0}),(0,E.jsxs)(p,{children:[(0,E.jsx)(r,{variant:`outline`,onClick:()=>N({type:null}),children:`Cancel`}),(0,E.jsx)(r,{disabled:!P.trim(),onClick:()=>{M.type===`branch`?G(P.trim(),M.hash):K(P.trim(),M.hash),N({type:null})},children:`Create`})]})]})})]})}function se({label:e,color:t,currentBranch:n,onCheckout:r,onMerge:i,onPush:s,onCreatePr:c,onDelete:l}){return(0,E.jsxs)(b,{children:[(0,E.jsx)(v,{asChild:!0,children:(0,E.jsxs)(`span`,{className:`inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] font-medium shrink-0 cursor-context-menu`,style:{backgroundColor:`${t}30`,color:t,border:`1px solid ${t}50`},children:[(0,E.jsx)(y,{className:`size-2.5`}),e.name]})}),(0,E.jsxs)(_,{children:[(0,E.jsx)(x,{onClick:()=>r(e.name),children:`Checkout`}),(0,E.jsxs)(x,{onClick:()=>i(e.name),disabled:e.name===n?.name,children:[(0,E.jsx)(C,{className:`size-3`}),`Merge into current`]}),(0,E.jsx)(S,{}),(0,E.jsxs)(x,{onClick:()=>s(e.name),children:[(0,E.jsx)(a,{className:`size-3`}),`Push`]}),(0,E.jsxs)(x,{onClick:()=>c(e.name),children:[(0,E.jsx)(o,{className:`size-3`}),`Create PR`]}),(0,E.jsx)(S,{}),(0,E.jsxs)(x,{variant:`destructive`,onClick:()=>l(e.name),disabled:e.name===n?.name,children:[(0,E.jsx)(d,{className:`size-3`}),`Delete`]})]})]})}export{A as GitGraph};
@@ -0,0 +1 @@
1
+ import{i as e,n as t,t as n}from"./jsx-runtime-BnxRlLMJ.js";import{t as r}from"./button-BxijdhtM.js";import{t as i}from"./createLucideIcon-Dy1wlrF7.js";import{t as a}from"./arrow-up-from-line-BXL5dtbG.js";import{a as o,r as s,t as c}from"./api-client-Bnf9LAt4.js";import{t as l}from"./refresh-cw-DtopuYJf.js";import{a as u,i as d,n as f,o as p,r as m,t as h}from"./dialog-RczsXsmw.js";import{C as g,d as _,p as v,u as y,w as b}from"./index-DGSLw2GE.js";var x=i(`arrow-down-to-line`,[[`path`,{d:`M12 17V3`,key:`1cwfxf`}],[`path`,{d:`m6 11 6 6 6-6`,key:`12ii2o`}],[`path`,{d:`M19 21H5`,key:`150jfl`}]]),S=i(`folder-tree`,[[`path`,{d:`M20 10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1h-2.5a1 1 0 0 1-.8-.4l-.9-1.2A1 1 0 0 0 15 3h-2a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z`,key:`hod4my`}],[`path`,{d:`M20 21a1 1 0 0 0 1-1v-3a1 1 0 0 0-1-1h-2.9a1 1 0 0 1-.88-.55l-.42-.85a1 1 0 0 0-.92-.6H13a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z`,key:`w4yl2u`}],[`path`,{d:`M3 5a2 2 0 0 0 2 2h3`,key:`f2jnh7`}],[`path`,{d:`M3 3v13a2 2 0 0 0 2 2h3`,key:`k8epm1`}]]),C=i(`list`,[[`path`,{d:`M3 5h.01`,key:`18ugdj`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M3 19h.01`,key:`noohij`}],[`path`,{d:`M8 5h13`,key:`1pao27`}],[`path`,{d:`M8 12h13`,key:`1za7za`}],[`path`,{d:`M8 19h13`,key:`m83p4d`}]]),w=i(`minus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}]]),T=i(`undo-2`,[[`path`,{d:`M9 14 4 9l5-5`,key:`102s5s`}],[`path`,{d:`M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11`,key:`f3b9sd`}]]),E=e(t(),1),D=n(),O={M:`text-yellow-500`,A:`text-green-500`,D:`text-red-500`,R:`text-blue-500`,C:`text-purple-500`,"?":`text-gray-400`};function k(e){let t=[];for(let n of e){let e=n.path.split(`/`),r=t;for(let t=0;t<e.length;t++){let i=e[t],a=e.slice(0,t+1).join(`/`),o=t===e.length-1,s=r.find(e=>e.name===i);s||(s={name:i,fullPath:a,file:o?n:void 0,children:[]},r.push(s)),o&&(s.file=n),r=s.children}}return t}function A(e){let t=[];e.file&&t.push(e.file);for(let n of e.children)t.push(...A(n));return t}function j({metadata:e,tabId:t}){let n=e?.projectName,[i,g]=(0,E.useState)(null),[b,T]=(0,E.useState)(!0),[O,k]=(0,E.useState)(null),[A,j]=(0,E.useState)(``),[M,P]=(0,E.useState)(!1),[F,I]=(0,E.useState)(null),{openTab:L,updateTab:R}=y(),z=e?.viewMode===`tree`?`tree`:`flat`,B=n=>{t&&R(t,{metadata:{...e,viewMode:n}})},V=(0,E.useCallback)(async()=>{if(n)try{T(!0),g(await c.get(`${s(n)}/git/status`)),k(null)}catch(e){k(e instanceof Error?e.message:`Failed to fetch status`)}finally{T(!1)}},[n]);(0,E.useEffect)(()=>{V()},[V]);let H=async e=>{if(n){P(!0);try{await c.post(`${s(n)}/git/stage`,{files:e}),await V()}catch(e){k(e instanceof Error?e.message:`Stage failed`)}finally{P(!1)}}},U=async e=>{if(n){P(!0);try{await c.post(`${s(n)}/git/unstage`,{files:e}),await V()}catch(e){k(e instanceof Error?e.message:`Unstage failed`)}finally{P(!1)}}},W=async e=>{if(n){P(!0);try{await c.post(`${s(n)}/git/discard`,{files:e}),await V()}catch(e){k(e instanceof Error?e.message:`Discard failed`)}finally{P(!1)}}},G=async()=>{F&&(await W(F.files),I(null))},K=async()=>{if(!(!n||!A.trim()||!i?.staged.length)){P(!0);try{await c.post(`${s(n)}/git/commit`,{message:A.trim()}),j(``),await V()}catch(e){k(e instanceof Error?e.message:`Commit failed`)}finally{P(!1)}}},q=async()=>{if(n){P(!0);try{await c.post(`${s(n)}/git/push`,{}),await V()}catch(e){k(e instanceof Error?e.message:`Push failed`)}finally{P(!1)}}},J=async()=>{if(n){P(!0);try{await c.post(`${s(n)}/git/pull`,{}),await V()}catch(e){k(e instanceof Error?e.message:`Pull failed`)}finally{P(!1)}}},Y=e=>{L({type:`git-diff`,title:e.path.split(`/`).pop()??e.path,closable:!0,metadata:{projectName:n,filePath:e.path},projectId:n??null})},X=(0,E.useMemo)(()=>[...i?.unstaged??[],...i?.untracked.map(e=>({path:e,status:`?`}))??[]],[i]);return n?b&&!i?(0,D.jsxs)(`div`,{className:`flex items-center justify-center h-full gap-2 text-muted-foreground`,children:[(0,D.jsx)(o,{className:`size-5 animate-spin`}),(0,D.jsx)(`span`,{className:`text-sm`,children:`Loading git status...`})]}):O&&!i?(0,D.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-2 text-destructive text-sm`,children:[(0,D.jsx)(`p`,{children:O}),(0,D.jsx)(r,{variant:`outline`,size:`sm`,onClick:V,children:`Retry`})]}):(0,D.jsxs)(`div`,{className:`flex flex-col h-full overflow-hidden`,children:[(0,D.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-2 border-b shrink-0`,children:[(0,D.jsx)(`span`,{className:`text-sm font-medium`,children:i?.current?`On: ${i.current}`:`Git Status`}),(0,D.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,D.jsx)(r,{variant:z===`flat`?`secondary`:`ghost`,size:`icon-xs`,onClick:()=>B(`flat`),title:`Flat view`,children:(0,D.jsx)(C,{className:`size-3.5`})}),(0,D.jsx)(r,{variant:z===`tree`?`secondary`:`ghost`,size:`icon-xs`,onClick:()=>B(`tree`),title:`Tree view`,children:(0,D.jsx)(S,{className:`size-3.5`})}),(0,D.jsx)(r,{variant:`ghost`,size:`icon-xs`,onClick:V,disabled:M,children:(0,D.jsx)(l,{className:b?`animate-spin`:``})})]})]}),O&&(0,D.jsx)(`div`,{className:`px-3 py-1.5 text-xs text-destructive bg-destructive/10 shrink-0`,children:O}),(0,D.jsx)(_,{className:`flex-1 overflow-hidden`,children:(0,D.jsxs)(`div`,{className:`p-2 space-y-3 overflow-hidden`,children:[(0,D.jsx)(N,{title:`Staged Changes`,count:i?.staged.length??0,files:i?.staged??[],viewMode:z,actionIcon:(0,D.jsx)(w,{className:`size-3.5`}),actionTitle:`Unstage`,onAction:e=>U([e.path]),onActionAll:i?.staged.length?()=>U(i.staged.map(e=>e.path)):void 0,actionAllLabel:`Unstage All`,onFolderAction:e=>U(e.map(e=>e.path)),onClickFile:Y,disabled:M}),(0,D.jsx)(N,{title:`Changes`,count:X.length,files:X,viewMode:z,actionIcon:(0,D.jsx)(v,{className:`size-3.5`}),actionTitle:`Stage`,onAction:e=>H([e.path]),onActionAll:X.length?()=>H(X.map(e=>e.path)):void 0,actionAllLabel:`Stage All`,onFolderAction:e=>H(e.map(e=>e.path)),onClickFile:Y,disabled:M,showRevert:!0,onRevert:e=>I({label:e.path,files:[e.path]}),onFolderRevert:(e,t)=>I({label:`${t}/ (${e.length} files)`,files:e.map(e=>e.path)})})]})}),(0,D.jsxs)(`div`,{className:`border-t p-2 space-y-2 shrink-0`,children:[(0,D.jsx)(`textarea`,{className:`w-full h-16 px-2 py-1.5 text-sm bg-muted/50 border rounded resize-none focus:outline-none focus:ring-1 focus:ring-ring`,placeholder:`Commit message...`,value:A,onChange:e=>j(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.metaKey||e.ctrlKey)&&K()}}),(0,D.jsx)(r,{size:`sm`,className:`w-full`,disabled:M||!A.trim()||!i?.staged.length,onClick:K,children:M?(0,D.jsx)(o,{className:`size-3 animate-spin`}):`Commit (${i?.staged.length??0})`}),(0,D.jsxs)(`div`,{className:`flex gap-2`,children:[(0,D.jsxs)(r,{variant:`outline`,size:`sm`,className:`flex-1`,disabled:M,onClick:q,children:[(0,D.jsx)(a,{className:`size-3`}),`Push`]}),(0,D.jsxs)(r,{variant:`outline`,size:`sm`,className:`flex-1`,disabled:M,onClick:J,children:[(0,D.jsx)(x,{className:`size-3`}),`Pull`]})]})]}),(0,D.jsx)(h,{open:!!F,onOpenChange:e=>!e&&I(null),children:(0,D.jsxs)(f,{showCloseButton:!1,children:[(0,D.jsxs)(u,{children:[(0,D.jsx)(p,{children:`Discard Changes`}),(0,D.jsxs)(m,{children:[`Are you sure you want to discard all changes to`,` `,(0,D.jsx)(`code`,{className:`px-1 py-0.5 rounded bg-muted text-sm font-mono`,children:F?.label}),`? This action cannot be undone.`]})]}),(0,D.jsxs)(d,{children:[(0,D.jsx)(r,{variant:`outline`,onClick:()=>I(null),children:`Cancel`}),(0,D.jsx)(r,{variant:`destructive`,onClick:G,disabled:M,children:M?(0,D.jsx)(o,{className:`size-3 animate-spin`}):`Discard`})]})]})})]}):(0,D.jsx)(`div`,{className:`flex items-center justify-center h-full text-muted-foreground text-sm`,children:`No project selected.`})}function M({showRevert:e,onRevert:t,onAction:n,actionIcon:r,actionTitle:i,disabled:a}){return(0,D.jsxs)(`div`,{className:`flex items-center gap-0.5 shrink-0 ml-1`,children:[e&&t&&(0,D.jsx)(`button`,{type:`button`,className:`flex items-center justify-center size-7 rounded border border-border/60 bg-muted/60 text-muted-foreground hover:bg-destructive/15 hover:text-destructive hover:border-destructive/40 active:scale-95 transition-colors`,onClick:e=>{e.stopPropagation(),t()},disabled:a,title:`Discard changes`,children:(0,D.jsx)(T,{className:`size-3.5`})}),(0,D.jsx)(`button`,{type:`button`,className:`flex items-center justify-center size-7 rounded border border-border/60 bg-muted/60 text-muted-foreground hover:bg-accent hover:text-accent-foreground active:scale-95 transition-colors`,onClick:e=>{e.stopPropagation(),n()},disabled:a,title:i,children:r})]})}function N({title:e,count:t,files:n,viewMode:i,actionIcon:a,actionTitle:o,onAction:s,onActionAll:c,actionAllLabel:l,onFolderAction:u,onClickFile:d,disabled:f,showRevert:p,onRevert:m,onFolderRevert:h}){return(0,D.jsxs)(`div`,{children:[(0,D.jsxs)(`div`,{className:`flex items-center justify-between mb-1`,children:[(0,D.jsxs)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase`,children:[e,` (`,t,`)`]}),c&&t>0&&(0,D.jsx)(r,{variant:`ghost`,size:`xs`,onClick:c,disabled:f,title:l,children:l})]}),n.length===0?(0,D.jsx)(`p`,{className:`text-xs text-muted-foreground px-1`,children:`No changes`}):i===`flat`?(0,D.jsx)(`div`,{className:`divide-y divide-border/40 w-full overflow-hidden`,children:n.map(e=>(0,D.jsx)(P,{file:e,actionIcon:a,actionTitle:o,onAction:s,onClickFile:d,disabled:f,showRevert:p,onRevert:m},e.path))}):(0,D.jsx)(F,{files:n,actionIcon:a,actionTitle:o,onAction:s,onFolderAction:u,onClickFile:d,disabled:f,showRevert:p,onRevert:m,onFolderRevert:h})]})}function P({file:e,actionIcon:t,actionTitle:n,onAction:r,onClickFile:i,disabled:a,showRevert:o,onRevert:s,displayName:c}){return(0,D.jsxs)(`div`,{className:`flex items-center gap-1 hover:bg-muted/50 rounded px-1 py-1 w-full min-w-0`,children:[(0,D.jsx)(`span`,{className:`text-xs font-mono w-4 text-center shrink-0 ${O[e.status]??``}`,children:e.status}),(0,D.jsx)(`button`,{type:`button`,className:`flex-1 text-left text-xs font-mono truncate hover:underline min-w-0`,onClick:()=>i(e),title:e.path,children:c??e.path}),(0,D.jsx)(M,{showRevert:o,onRevert:s?()=>s(e):void 0,onAction:()=>r(e),actionIcon:t,actionTitle:n,disabled:a})]})}function F({files:e,actionIcon:t,actionTitle:n,onAction:r,onFolderAction:i,onClickFile:a,disabled:o,showRevert:s,onRevert:c,onFolderRevert:l}){let u=(0,E.useMemo)(()=>k(e),[e]);return(0,D.jsx)(`div`,{children:u.map((e,d)=>(0,D.jsx)(I,{node:e,depth:0,isLast:d===u.length-1,actionIcon:t,actionTitle:n,onAction:r,onFolderAction:i,onClickFile:a,disabled:o,showRevert:s,onRevert:c,onFolderRevert:l},e.fullPath))})}function I({node:e,depth:t,isLast:n,actionIcon:r,actionTitle:i,onAction:a,onFolderAction:o,onClickFile:s,disabled:c,showRevert:l,onRevert:u,onFolderRevert:d}){let[f,p]=(0,E.useState)(!0),m=e.children.length>0&&!e.file;if(e.file)return(0,D.jsxs)(`div`,{className:`relative overflow-hidden border-b border-border/30`,style:{paddingLeft:t*16},children:[t>0&&(0,D.jsx)(`div`,{className:`absolute top-0 bottom-0 border-l border-border/30`,style:{left:t*16-8}}),(0,D.jsx)(P,{file:e.file,displayName:e.name,actionIcon:r,actionTitle:i,onAction:a,onClickFile:s,disabled:c,showRevert:l,onRevert:u})]});if(m){let m=A(e);return(0,D.jsxs)(`div`,{className:`relative overflow-hidden`,children:[t>0&&(0,D.jsx)(`div`,{className:`absolute top-0 border-l border-border/30`,style:{left:t*16-8,bottom:n?`50%`:0}}),(0,D.jsxs)(`div`,{className:`flex items-center hover:bg-muted/50 rounded py-1 pr-1 border-b border-border/30`,style:{paddingLeft:t*16+4},children:[(0,D.jsxs)(`button`,{type:`button`,className:`flex items-center gap-1 flex-1 min-w-0 text-xs font-mono text-muted-foreground`,onClick:()=>p(!f),children:[f?(0,D.jsx)(b,{className:`size-3.5 shrink-0`}):(0,D.jsx)(g,{className:`size-3.5 shrink-0`}),(0,D.jsx)(`span`,{className:`truncate font-semibold`,children:e.name}),(0,D.jsxs)(`span`,{className:`text-[10px] opacity-60 shrink-0`,children:[`(`,m.length,`)`]})]}),(0,D.jsx)(M,{showRevert:l,onRevert:d?()=>d(m,e.fullPath):void 0,onAction:()=>o?.(m),actionIcon:r,actionTitle:`${i} ${e.name}/`,disabled:c})]}),f&&(0,D.jsxs)(`div`,{className:`relative`,children:[(0,D.jsx)(`div`,{className:`absolute top-0 bottom-0 border-l border-border/30`,style:{left:t*16+8}}),e.children.map((n,f)=>(0,D.jsx)(I,{node:n,depth:t+1,isLast:f===e.children.length-1,actionIcon:r,actionTitle:i,onAction:a,onFolderAction:o,onClickFile:s,disabled:c,showRevert:l,onRevert:u,onFolderRevert:d},n.fullPath))]})]})}return null}export{j as GitStatusPanel};