@hienlh/ppm 0.2.0 → 0.2.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 (40) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/web/assets/{button-KIZetva8.js → button-CvHWF07y.js} +1 -1
  3. package/dist/web/assets/{chat-tab-D7dR7kbZ.js → chat-tab-C4ovA2w4.js} +3 -3
  4. package/dist/web/assets/{code-editor-r8P6Gk4M.js → code-editor-BgiyQO-M.js} +1 -1
  5. package/dist/web/assets/{dialog-D8ulRTfX.js → dialog-f3IZM-6v.js} +1 -1
  6. package/dist/web/assets/{diff-viewer-vSvrem_i.js → diff-viewer-8_asmBRZ.js} +1 -1
  7. package/dist/web/assets/{dist-C4W3AGh3.js → dist-CCBctnax.js} +1 -1
  8. package/dist/web/assets/{git-graph-Cn-s1k0-.js → git-graph-BiyTIbCz.js} +1 -1
  9. package/dist/web/assets/{git-status-panel-QjAQzNAi.js → git-status-panel-BifyO31N.js} +1 -1
  10. package/dist/web/assets/index-DILaVO6p.css +2 -0
  11. package/dist/web/assets/index-DasstYgw.js +11 -0
  12. package/dist/web/assets/project-list-C7L3hZct.js +1 -0
  13. package/dist/web/assets/settings-tab-Cn5Ja0_J.js +1 -0
  14. package/dist/web/assets/{terminal-tab-DDf6S-Tu.js → terminal-tab-CyjhG4Ao.js} +1 -1
  15. package/dist/web/index.html +8 -8
  16. package/dist/web/sw.js +1 -1
  17. package/package.json +3 -2
  18. package/src/cli/commands/init.ts +11 -1
  19. package/src/cli/commands/logs.ts +58 -0
  20. package/src/cli/commands/report.ts +60 -0
  21. package/src/cli/commands/status.ts +31 -22
  22. package/src/cli/commands/stop.ts +37 -29
  23. package/src/index.ts +21 -1
  24. package/src/server/index.ts +147 -65
  25. package/src/types/config.ts +2 -0
  26. package/src/version.ts +7 -0
  27. package/src/web/app.tsx +8 -0
  28. package/src/web/components/auth/login-screen.tsx +8 -1
  29. package/src/web/components/layout/sidebar.tsx +15 -0
  30. package/src/web/components/ui/sonner.tsx +9 -6
  31. package/src/web/hooks/use-health-check.ts +95 -0
  32. package/src/web/stores/settings-store.ts +19 -0
  33. package/src/web/stores/tab-store.ts +28 -8
  34. package/dist/web/assets/index-DUBI96T5.css +0 -2
  35. package/dist/web/assets/index-nk1dAWff.js +0 -10
  36. package/dist/web/assets/project-list-DqiatpaH.js +0 -1
  37. package/dist/web/assets/settings-tab-iCGeFFdt.js +0 -1
  38. /package/dist/web/assets/{dist-PA84y4Ga.js → dist-B6sG2GPc.js} +0 -0
  39. /package/dist/web/assets/{react-BSLFEYu8.js → react-gOPBns57.js} +0 -0
  40. /package/dist/web/assets/{utils-DpJF9mAi.js → utils-61GRB9Cb.js} +0 -0
@@ -0,0 +1 @@
1
+ import{a as e,n as t,r as n,t as r}from"./jsx-runtime-BFALxl05.js";import{t as i}from"./button-CvHWF07y.js";import{a,i as o,n as s,o as c,t as l}from"./dialog-f3IZM-6v.js";import{t as u}from"./utils-61GRB9Cb.js";import{t as d}from"./api-client-BgVufYKf.js";import{_ as f,b as p,c as m,h,l as g,n as _,v}from"./index-DasstYgw.js";var y=t(`circle`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),b=t(`folder-git-2`,[[`path`,{d:`M18 19a5 5 0 0 1-5-5v8`,key:`sz5oeg`}],[`path`,{d:`M9 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v5`,key:`1w6njk`}],[`circle`,{cx:`13`,cy:`12`,r:`2`,key:`1j92g6`}],[`circle`,{cx:`20`,cy:`19`,r:`2`,key:`1obnsp`}]]),x=e(n(),1),S=r();function C({value:e,onChange:t,onSelect:n,placeholder:r,autoFocus:i}){let[a,o]=(0,x.useState)([]),[s,c]=(0,x.useState)([]),[l,u]=(0,x.useState)(!1),[p,m]=(0,x.useState)(0),[h,g]=(0,x.useState)(!1),v=(0,x.useRef)(null),y=(0,x.useRef)(!1);(0,x.useEffect)(()=>{y.current||(y.current=!0,g(!0),d.get(`/api/projects/suggest-dirs`).then(e=>{o(e),c(e.slice(0,50)),u(e.length>0)}).catch(()=>o([])).finally(()=>g(!1)))},[]),(0,x.useEffect)(()=>{if(a.length===0)return;let t=e.trim().toLowerCase();c(t?a.filter(e=>e.path.toLowerCase().includes(t)||e.name.toLowerCase().includes(t)).slice(0,50):a.slice(0,50)),m(0)},[e,a]),(0,x.useEffect)(()=>{let e=v.current;e&&e.children[p]?.scrollIntoView({block:`nearest`})},[p]);let C=(0,x.useCallback)(e=>{t(e.path),n?.(e),u(!1)},[t,n]),w=(0,x.useCallback)(e=>{if(!(!l||s.length===0))switch(e.key){case`ArrowDown`:e.preventDefault(),m(e=>e<s.length-1?e+1:0);break;case`ArrowUp`:e.preventDefault(),m(e=>e>0?e-1:s.length-1);break;case`Tab`:case`Enter`:s[p]&&(e.preventDefault(),C(s[p]));break;case`Escape`:e.preventDefault(),u(!1);break}},[l,s,p,C]);return(0,S.jsxs)(`div`,{className:`relative`,children:[(0,S.jsxs)(`div`,{className:`relative`,children:[(0,S.jsx)(_,{placeholder:r??`/home/user/my-project`,value:e,onChange:e=>t(e.target.value),onKeyDown:w,onFocus:()=>s.length>0&&u(!0),onBlur:()=>setTimeout(()=>u(!1),200),autoFocus:i}),h&&(0,S.jsx)(f,{className:`absolute right-2 top-1/2 -translate-y-1/2 size-4 text-text-subtle animate-spin`})]}),l&&s.length>0&&(0,S.jsx)(`div`,{className:`absolute z-50 left-0 right-0 top-full mt-1 max-h-48 overflow-y-auto rounded-md border border-border bg-surface shadow-lg`,children:(0,S.jsx)(`div`,{ref:v,className:`py-1`,children:s.map((e,t)=>(0,S.jsxs)(`button`,{type:`button`,className:`flex items-center gap-2 w-full px-3 py-1.5 text-left text-sm transition-colors ${t===p?`bg-primary/10 text-primary`:`hover:bg-surface-hover text-text-primary`}`,onMouseEnter:()=>m(t),onMouseDown:t=>{t.preventDefault(),C(e)},children:[(0,S.jsx)(b,{className:`size-4 text-green-500 shrink-0`}),(0,S.jsxs)(`div`,{className:`min-w-0 flex-1 flex items-baseline gap-2`,children:[(0,S.jsx)(`span`,{className:`font-medium`,children:e.name}),(0,S.jsx)(`span`,{className:`text-xs text-text-subtle truncate`,children:e.path})]})]},e.path))})})]})}function w(){let{projects:e,activeProject:t,setActiveProject:n,fetchProjects:r,loading:f,error:b}=m(),w=g(e=>e.openTab),[T,E]=(0,x.useState)(!1),[D,O]=(0,x.useState)(``),[k,A]=(0,x.useState)(``),[j,M]=(0,x.useState)(``);(0,x.useEffect)(()=>{r()},[r]);function N(e){n(e)}function P(e){n(e),w({type:`terminal`,title:`Terminal - ${e.name}`,metadata:{projectName:e.name},projectId:e.name,closable:!0})}let F=(0,x.useCallback)(async()=>{if(D.trim()){M(``);try{await d.post(`/api/projects`,{path:D.trim(),name:k.trim()||void 0}),await r(),E(!1),O(``),A(``)}catch(e){M(e instanceof Error?e.message:`Failed to add project`)}}},[D,k,r]);return b?(0,S.jsx)(`div`,{className:`flex items-center justify-center h-full p-4`,children:(0,S.jsx)(`p`,{className:`text-error text-sm`,children:b})}):(0,S.jsxs)(`div`,{className:`h-full p-4 space-y-4 overflow-auto`,children:[(0,S.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,S.jsx)(`h2`,{className:`text-lg font-semibold`,children:`Projects`}),(0,S.jsxs)(i,{variant:`outline`,size:`sm`,onClick:()=>E(!0),className:`gap-1.5`,children:[(0,S.jsx)(h,{className:`size-4`}),`Add Project`]})]}),f&&(0,S.jsx)(`p`,{className:`text-text-secondary text-sm`,children:`Loading projects...`}),!f&&e.length===0&&(0,S.jsxs)(`div`,{className:`text-center py-8 space-y-2`,children:[(0,S.jsx)(p,{className:`size-10 mx-auto text-text-subtle`}),(0,S.jsx)(`p`,{className:`text-text-secondary text-sm`,children:`No projects registered`}),(0,S.jsxs)(`p`,{className:`text-text-subtle text-xs`,children:[`Click "Add Project" or use `,(0,S.jsx)(`code`,{className:`font-mono bg-surface-elevated px-1 py-0.5 rounded`,children:`ppm projects add <path>`})]})]}),(0,S.jsx)(`div`,{className:`grid gap-3 sm:grid-cols-2 lg:grid-cols-3`,children:e.map(e=>(0,S.jsx)(`button`,{onClick:()=>N(e),onDoubleClick:()=>P(e),className:u(`text-left p-4 rounded-lg border transition-colors`,`min-h-[44px]`,t?.name===e.name?`bg-surface border-primary`:`bg-surface border-border hover:border-text-subtle`),children:(0,S.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,S.jsx)(p,{className:`size-5 text-primary shrink-0 mt-0.5`}),(0,S.jsxs)(`div`,{className:`flex-1 min-w-0 space-y-1`,children:[(0,S.jsx)(`p`,{className:`font-medium truncate`,children:e.name}),(0,S.jsx)(`p`,{className:`text-xs text-text-secondary truncate`,children:e.path}),e.branch&&(0,S.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs text-text-secondary`,children:[(0,S.jsx)(v,{className:`size-3`}),(0,S.jsx)(`span`,{children:e.branch}),e.status&&(0,S.jsx)(y,{className:u(`size-2 fill-current`,e.status===`clean`?`text-success`:`text-warning`)})]})]})]})},e.name))}),(0,S.jsx)(l,{open:T,onOpenChange:E,children:(0,S.jsxs)(s,{children:[(0,S.jsx)(a,{children:(0,S.jsx)(c,{children:`Add Project`})}),(0,S.jsxs)(`div`,{className:`space-y-3`,children:[(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`label`,{className:`text-sm text-text-secondary`,children:`Path (required)`}),(0,S.jsx)(C,{value:D,onChange:O,onSelect:e=>{k.trim()||A(e.name)},placeholder:`/home/user/my-project`,autoFocus:!0})]}),(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`label`,{className:`text-sm text-text-secondary`,children:`Name (optional)`}),(0,S.jsx)(_,{placeholder:`Auto-detected from folder name`,value:k,onChange:e=>A(e.target.value),onKeyDown:e=>e.key===`Enter`&&F()})]}),j&&(0,S.jsx)(`p`,{className:`text-sm text-error`,children:j})]}),(0,S.jsxs)(o,{children:[(0,S.jsx)(i,{variant:`outline`,onClick:()=>E(!1),children:`Cancel`}),(0,S.jsx)(i,{onClick:F,disabled:!D.trim(),children:`Add`})]})]})})]})}export{w as ProjectList};
@@ -0,0 +1 @@
1
+ import{a as e,n as t,r as n,t as r}from"./jsx-runtime-BFALxl05.js";import{_ as i,a,b as o,c as s,d as c,f as l,h as u,i as d,l as f,m as p,n as m,o as h,r as g,s as _,t as v,u as y,x as b}from"./button-CvHWF07y.js";import{a as x,i as S,n as C,o as w,r as T,t as E}from"./dist-CCBctnax.js";import{n as ee,t as D}from"./dist-B6sG2GPc.js";import{t as O}from"./utils-61GRB9Cb.js";import{t as k}from"./api-client-BgVufYKf.js";import{D as A,O as j,d as M,f as N,n as P,t as F}from"./index-DasstYgw.js";var te=t(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),I=t(`monitor`,[[`rect`,{width:`20`,height:`14`,x:`2`,y:`3`,rx:`2`,key:`48i651`}],[`line`,{x1:`8`,x2:`16`,y1:`21`,y2:`21`,key:`1svkeh`}],[`line`,{x1:`12`,x2:`12`,y1:`17`,y2:`21`,key:`vw1qmm`}]]),L=t(`moon`,[[`path`,{d:`M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401`,key:`kfwtm`}]]),R=t(`sun`,[[`circle`,{cx:`12`,cy:`12`,r:`4`,key:`4exip2`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M12 20v2`,key:`1lh1kg`}],[`path`,{d:`m4.93 4.93 1.41 1.41`,key:`149t6j`}],[`path`,{d:`m17.66 17.66 1.41 1.41`,key:`ptbguv`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`M20 12h2`,key:`1q8mjw`}],[`path`,{d:`m6.34 17.66-1.41 1.41`,key:`1m8zz5`}],[`path`,{d:`m19.07 4.93-1.41 1.41`,key:`1shlcs`}]]),z=e(n(),1);function B(e){let t=z.useRef({value:e,previous:e});return z.useMemo(()=>(t.current.value!==e&&(t.current.previous=t.current.value,t.current.value=e),t.current.previous),[e])}var V=r(),H=`Label`,ne=z.forwardRef((e,t)=>(0,V.jsx)(u.label,{...e,ref:t,onMouseDown:t=>{t.target.closest(`button, input, select, textarea`)||(e.onMouseDown?.(t),!t.defaultPrevented&&t.detail>1&&t.preventDefault())}}));ne.displayName=H;var re=ne,ie=e(b(),1),ae=[` `,`Enter`,`ArrowUp`,`ArrowDown`],oe=[` `,`Enter`],U=`Select`,[W,se,ce]=w(U),[G,le]=p(U,[ce,x]),K=x(),[ue,q]=G(U),[de,fe]=G(U),pe=e=>{let{__scopeSelect:t,children:n,open:r,defaultOpen:i,onOpenChange:a,value:o,defaultValue:s,onValueChange:c,dir:l,name:u,autoComplete:d,disabled:p,required:m,form:h}=e,g=K(t),[_,v]=z.useState(null),[b,x]=z.useState(null),[C,w]=z.useState(!1),T=ee(l),[E,D]=y({prop:r,defaultProp:i??!1,onChange:a,caller:U}),[O,k]=y({prop:o,defaultProp:s,onChange:c,caller:U}),A=z.useRef(null),j=_?h||!!_.closest(`form`):!0,[M,N]=z.useState(new Set),P=Array.from(M).map(e=>e.props.value).join(`;`);return(0,V.jsx)(S,{...g,children:(0,V.jsxs)(ue,{required:m,scope:t,trigger:_,onTriggerChange:v,valueNode:b,onValueNodeChange:x,valueNodeHasChildren:C,onValueNodeHasChildrenChange:w,contentId:f(),value:O,onValueChange:k,open:E,onOpenChange:D,dir:T,triggerPointerDownPosRef:A,disabled:p,children:[(0,V.jsx)(W.Provider,{scope:t,children:(0,V.jsx)(de,{scope:e.__scopeSelect,onNativeOptionAdd:z.useCallback(e=>{N(t=>new Set(t).add(e))},[]),onNativeOptionRemove:z.useCallback(e=>{N(t=>{let n=new Set(t);return n.delete(e),n})},[]),children:n})}),j?(0,V.jsxs)(rt,{"aria-hidden":!0,required:m,tabIndex:-1,name:u,autoComplete:d,value:O,onChange:e=>k(e.target.value),disabled:p,form:h,children:[O===void 0?(0,V.jsx)(`option`,{value:``}):null,Array.from(M)]},P):null]})})};pe.displayName=U;var me=`SelectTrigger`,he=z.forwardRef((e,t)=>{let{__scopeSelect:n,disabled:r=!1,...i}=e,a=K(n),s=q(me,n),c=s.disabled||r,d=o(t,s.onTriggerChange),f=se(n),p=z.useRef(`touch`),[m,h,g]=at(e=>{let t=f().filter(e=>!e.disabled),n=ot(t,e,t.find(e=>e.value===s.value));n!==void 0&&s.onValueChange(n.value)}),_=e=>{c||(s.onOpenChange(!0),g()),e&&(s.triggerPointerDownPosRef.current={x:Math.round(e.pageX),y:Math.round(e.pageY)})};return(0,V.jsx)(E,{asChild:!0,...a,children:(0,V.jsx)(u.button,{type:`button`,role:`combobox`,"aria-controls":s.contentId,"aria-expanded":s.open,"aria-required":s.required,"aria-autocomplete":`none`,dir:s.dir,"data-state":s.open?`open`:`closed`,disabled:c,"data-disabled":c?``:void 0,"data-placeholder":it(s.value)?``:void 0,...i,ref:d,onClick:l(i.onClick,e=>{e.currentTarget.focus(),p.current!==`mouse`&&_(e)}),onPointerDown:l(i.onPointerDown,e=>{p.current=e.pointerType;let t=e.target;t.hasPointerCapture(e.pointerId)&&t.releasePointerCapture(e.pointerId),e.button===0&&e.ctrlKey===!1&&e.pointerType===`mouse`&&(_(e),e.preventDefault())}),onKeyDown:l(i.onKeyDown,e=>{let t=m.current!==``;!(e.ctrlKey||e.altKey||e.metaKey)&&e.key.length===1&&h(e.key),!(t&&e.key===` `)&&ae.includes(e.key)&&(_(),e.preventDefault())})})})});he.displayName=me;var ge=`SelectValue`,_e=z.forwardRef((e,t)=>{let{__scopeSelect:n,className:r,style:i,children:a,placeholder:s=``,...l}=e,d=q(ge,n),{onValueNodeHasChildrenChange:f}=d,p=a!==void 0,m=o(t,d.onValueNodeChange);return c(()=>{f(p)},[f,p]),(0,V.jsx)(u.span,{...l,ref:m,style:{pointerEvents:`none`},children:it(d.value)?(0,V.jsx)(V.Fragment,{children:s}):a})});_e.displayName=ge;var ve=`SelectIcon`,ye=z.forwardRef((e,t)=>{let{__scopeSelect:n,children:r,...i}=e;return(0,V.jsx)(u.span,{"aria-hidden":!0,...i,ref:t,children:r||`▼`})});ye.displayName=ve;var be=`SelectPortal`,xe=e=>(0,V.jsx)(a,{asChild:!0,...e});xe.displayName=be;var J=`SelectContent`,Se=z.forwardRef((e,t)=>{let n=q(J,e.__scopeSelect),[r,i]=z.useState();if(c(()=>{i(new DocumentFragment)},[]),!n.open){let t=r;return t?ie.createPortal((0,V.jsx)(Ce,{scope:e.__scopeSelect,children:(0,V.jsx)(W.Slot,{scope:e.__scopeSelect,children:(0,V.jsx)(`div`,{children:e.children})})}),t):null}return(0,V.jsx)(Ee,{...e,ref:t})});Se.displayName=J;var Y=10,[Ce,X]=G(J),we=`SelectContentImpl`,Te=i(`SelectContent.RemoveScroll`),Ee=z.forwardRef((e,t)=>{let{__scopeSelect:n,position:r=`item-aligned`,onCloseAutoFocus:i,onEscapeKeyDown:a,onPointerDownOutside:s,side:c,sideOffset:u,align:f,alignOffset:p,arrowPadding:v,collisionBoundary:y,collisionPadding:b,sticky:x,hideWhenDetached:S,avoidCollisions:C,...w}=e,T=q(J,n),[E,ee]=z.useState(null),[D,O]=z.useState(null),k=o(t,e=>ee(e)),[A,j]=z.useState(null),[M,N]=z.useState(null),P=se(n),[F,te]=z.useState(!1),I=z.useRef(!1);z.useEffect(()=>{if(E)return m(E)},[E]),d();let L=z.useCallback(e=>{let[t,...n]=P().map(e=>e.ref.current),[r]=n.slice(-1),i=document.activeElement;for(let n of e)if(n===i||(n?.scrollIntoView({block:`nearest`}),n===t&&D&&(D.scrollTop=0),n===r&&D&&(D.scrollTop=D.scrollHeight),n?.focus(),document.activeElement!==i))return},[P,D]),R=z.useCallback(()=>L([A,E]),[L,A,E]);z.useEffect(()=>{F&&R()},[F,R]);let{onOpenChange:B,triggerPointerDownPosRef:H}=T;z.useEffect(()=>{if(E){let e={x:0,y:0},t=t=>{e={x:Math.abs(Math.round(t.pageX)-(H.current?.x??0)),y:Math.abs(Math.round(t.pageY)-(H.current?.y??0))}},n=n=>{e.x<=10&&e.y<=10?n.preventDefault():E.contains(n.target)||B(!1),document.removeEventListener(`pointermove`,t),H.current=null};return H.current!==null&&(document.addEventListener(`pointermove`,t),document.addEventListener(`pointerup`,n,{capture:!0,once:!0})),()=>{document.removeEventListener(`pointermove`,t),document.removeEventListener(`pointerup`,n,{capture:!0})}}},[E,B,H]),z.useEffect(()=>{let e=()=>B(!1);return window.addEventListener(`blur`,e),window.addEventListener(`resize`,e),()=>{window.removeEventListener(`blur`,e),window.removeEventListener(`resize`,e)}},[B]);let[ne,re]=at(e=>{let t=P().filter(e=>!e.disabled),n=ot(t,e,t.find(e=>e.ref.current===document.activeElement));n&&setTimeout(()=>n.ref.current.focus())}),ie=z.useCallback((e,t,n)=>{let r=!I.current&&!n;(T.value!==void 0&&T.value===t||r)&&(j(e),r&&(I.current=!0))},[T.value]),ae=z.useCallback(()=>E?.focus(),[E]),oe=z.useCallback((e,t,n)=>{let r=!I.current&&!n;(T.value!==void 0&&T.value===t||r)&&N(e)},[T.value]),U=r===`popper`?Ae:Oe,W=U===Ae?{side:c,sideOffset:u,align:f,alignOffset:p,arrowPadding:v,collisionBoundary:y,collisionPadding:b,sticky:x,hideWhenDetached:S,avoidCollisions:C}:{};return(0,V.jsx)(Ce,{scope:n,content:E,viewport:D,onViewportChange:O,itemRefCallback:ie,selectedItem:A,onItemLeave:ae,itemTextRefCallback:oe,focusSelectedItem:R,selectedItemText:M,position:r,isPositioned:F,searchRef:ne,children:(0,V.jsx)(g,{as:Te,allowPinchZoom:!0,children:(0,V.jsx)(h,{asChild:!0,trapped:T.open,onMountAutoFocus:e=>{e.preventDefault()},onUnmountAutoFocus:l(i,e=>{T.trigger?.focus({preventScroll:!0}),e.preventDefault()}),children:(0,V.jsx)(_,{asChild:!0,disableOutsidePointerEvents:!0,onEscapeKeyDown:a,onPointerDownOutside:s,onFocusOutside:e=>e.preventDefault(),onDismiss:()=>T.onOpenChange(!1),children:(0,V.jsx)(U,{role:`listbox`,id:T.contentId,"data-state":T.open?`open`:`closed`,dir:T.dir,onContextMenu:e=>e.preventDefault(),...w,...W,onPlaced:()=>te(!0),ref:k,style:{display:`flex`,flexDirection:`column`,outline:`none`,...w.style},onKeyDown:l(w.onKeyDown,e=>{let t=e.ctrlKey||e.altKey||e.metaKey;if(e.key===`Tab`&&e.preventDefault(),!t&&e.key.length===1&&re(e.key),[`ArrowUp`,`ArrowDown`,`Home`,`End`].includes(e.key)){let t=P().filter(e=>!e.disabled).map(e=>e.ref.current);if([`ArrowUp`,`End`].includes(e.key)&&(t=t.slice().reverse()),[`ArrowUp`,`ArrowDown`].includes(e.key)){let n=e.target,r=t.indexOf(n);t=t.slice(r+1)}setTimeout(()=>L(t)),e.preventDefault()}})})})})})})});Ee.displayName=we;var De=`SelectItemAlignedPosition`,Oe=z.forwardRef((e,t)=>{let{__scopeSelect:n,onPlaced:r,...i}=e,a=q(J,n),s=X(J,n),[l,d]=z.useState(null),[f,p]=z.useState(null),m=o(t,e=>p(e)),h=se(n),g=z.useRef(!1),_=z.useRef(!0),{viewport:v,selectedItem:y,selectedItemText:b,focusSelectedItem:x}=s,S=z.useCallback(()=>{if(a.trigger&&a.valueNode&&l&&f&&v&&y&&b){let e=a.trigger.getBoundingClientRect(),t=f.getBoundingClientRect(),n=a.valueNode.getBoundingClientRect(),i=b.getBoundingClientRect();if(a.dir!==`rtl`){let r=i.left-t.left,a=n.left-r,o=e.left-a,s=e.width+o,c=Math.max(s,t.width),u=window.innerWidth-Y,d=D(a,[Y,Math.max(Y,u-c)]);l.style.minWidth=s+`px`,l.style.left=d+`px`}else{let r=t.right-i.right,a=window.innerWidth-n.right-r,o=window.innerWidth-e.right-a,s=e.width+o,c=Math.max(s,t.width),u=window.innerWidth-Y,d=D(a,[Y,Math.max(Y,u-c)]);l.style.minWidth=s+`px`,l.style.right=d+`px`}let o=h(),s=window.innerHeight-Y*2,c=v.scrollHeight,u=window.getComputedStyle(f),d=parseInt(u.borderTopWidth,10),p=parseInt(u.paddingTop,10),m=parseInt(u.borderBottomWidth,10),_=parseInt(u.paddingBottom,10),x=d+p+c+_+m,S=Math.min(y.offsetHeight*5,x),C=window.getComputedStyle(v),w=parseInt(C.paddingTop,10),T=parseInt(C.paddingBottom,10),E=e.top+e.height/2-Y,ee=s-E,O=y.offsetHeight/2,k=y.offsetTop+O,A=d+p+k,j=x-A;if(A<=E){let e=o.length>0&&y===o[o.length-1].ref.current;l.style.bottom=`0px`;let t=f.clientHeight-v.offsetTop-v.offsetHeight,n=A+Math.max(ee,O+(e?T:0)+t+m);l.style.height=n+`px`}else{let e=o.length>0&&y===o[0].ref.current;l.style.top=`0px`;let t=Math.max(E,d+v.offsetTop+(e?w:0)+O)+j;l.style.height=t+`px`,v.scrollTop=A-E+v.offsetTop}l.style.margin=`${Y}px 0`,l.style.minHeight=S+`px`,l.style.maxHeight=s+`px`,r?.(),requestAnimationFrame(()=>g.current=!0)}},[h,a.trigger,a.valueNode,l,f,v,y,b,a.dir,r]);c(()=>S(),[S]);let[C,w]=z.useState();return c(()=>{f&&w(window.getComputedStyle(f).zIndex)},[f]),(0,V.jsx)(je,{scope:n,contentWrapper:l,shouldExpandOnScrollRef:g,onScrollButtonChange:z.useCallback(e=>{e&&_.current===!0&&(S(),x?.(),_.current=!1)},[S,x]),children:(0,V.jsx)(`div`,{ref:d,style:{display:`flex`,flexDirection:`column`,position:`fixed`,zIndex:C},children:(0,V.jsx)(u.div,{...i,ref:m,style:{boxSizing:`border-box`,maxHeight:`100%`,...i.style}})})})});Oe.displayName=De;var ke=`SelectPopperPosition`,Ae=z.forwardRef((e,t)=>{let{__scopeSelect:n,align:r=`start`,collisionPadding:i=Y,...a}=e,o=K(n);return(0,V.jsx)(T,{...o,...a,ref:t,align:r,collisionPadding:i,style:{boxSizing:`border-box`,...a.style,"--radix-select-content-transform-origin":`var(--radix-popper-transform-origin)`,"--radix-select-content-available-width":`var(--radix-popper-available-width)`,"--radix-select-content-available-height":`var(--radix-popper-available-height)`,"--radix-select-trigger-width":`var(--radix-popper-anchor-width)`,"--radix-select-trigger-height":`var(--radix-popper-anchor-height)`}})});Ae.displayName=ke;var[je,Me]=G(J,{}),Ne=`SelectViewport`,Pe=z.forwardRef((e,t)=>{let{__scopeSelect:n,nonce:r,...i}=e,a=X(Ne,n),s=Me(Ne,n),c=o(t,a.onViewportChange),d=z.useRef(0);return(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`style`,{dangerouslySetInnerHTML:{__html:`[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}`},nonce:r}),(0,V.jsx)(W.Slot,{scope:n,children:(0,V.jsx)(u.div,{"data-radix-select-viewport":``,role:`presentation`,...i,ref:c,style:{position:`relative`,flex:1,overflow:`hidden auto`,...i.style},onScroll:l(i.onScroll,e=>{let t=e.currentTarget,{contentWrapper:n,shouldExpandOnScrollRef:r}=s;if(r?.current&&n){let e=Math.abs(d.current-t.scrollTop);if(e>0){let r=window.innerHeight-Y*2,i=parseFloat(n.style.minHeight),a=parseFloat(n.style.height),o=Math.max(i,a);if(o<r){let i=o+e,a=Math.min(r,i),s=i-a;n.style.height=a+`px`,n.style.bottom===`0px`&&(t.scrollTop=s>0?s:0,n.style.justifyContent=`flex-end`)}}}d.current=t.scrollTop})})})]})});Pe.displayName=Ne;var Fe=`SelectGroup`,[Ie,Le]=G(Fe),Re=z.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=f();return(0,V.jsx)(Ie,{scope:n,id:i,children:(0,V.jsx)(u.div,{role:`group`,"aria-labelledby":i,...r,ref:t})})});Re.displayName=Fe;var ze=`SelectLabel`,Be=z.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=Le(ze,n);return(0,V.jsx)(u.div,{id:i.id,...r,ref:t})});Be.displayName=ze;var Z=`SelectItem`,[Ve,He]=G(Z),Ue=z.forwardRef((e,t)=>{let{__scopeSelect:n,value:r,disabled:i=!1,textValue:a,...s}=e,c=q(Z,n),d=X(Z,n),p=c.value===r,[m,h]=z.useState(a??``),[g,_]=z.useState(!1),v=o(t,e=>d.itemRefCallback?.(e,r,i)),y=f(),b=z.useRef(`touch`),x=()=>{i||(c.onValueChange(r),c.onOpenChange(!1))};if(r===``)throw Error(`A <Select.Item /> must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder.`);return(0,V.jsx)(Ve,{scope:n,value:r,disabled:i,textId:y,isSelected:p,onItemTextChange:z.useCallback(e=>{h(t=>t||(e?.textContent??``).trim())},[]),children:(0,V.jsx)(W.ItemSlot,{scope:n,value:r,disabled:i,textValue:m,children:(0,V.jsx)(u.div,{role:`option`,"aria-labelledby":y,"data-highlighted":g?``:void 0,"aria-selected":p&&g,"data-state":p?`checked`:`unchecked`,"aria-disabled":i||void 0,"data-disabled":i?``:void 0,tabIndex:i?void 0:-1,...s,ref:v,onFocus:l(s.onFocus,()=>_(!0)),onBlur:l(s.onBlur,()=>_(!1)),onClick:l(s.onClick,()=>{b.current!==`mouse`&&x()}),onPointerUp:l(s.onPointerUp,()=>{b.current===`mouse`&&x()}),onPointerDown:l(s.onPointerDown,e=>{b.current=e.pointerType}),onPointerMove:l(s.onPointerMove,e=>{b.current=e.pointerType,i?d.onItemLeave?.():b.current===`mouse`&&e.currentTarget.focus({preventScroll:!0})}),onPointerLeave:l(s.onPointerLeave,e=>{e.currentTarget===document.activeElement&&d.onItemLeave?.()}),onKeyDown:l(s.onKeyDown,e=>{d.searchRef?.current!==``&&e.key===` `||(oe.includes(e.key)&&x(),e.key===` `&&e.preventDefault())})})})})});Ue.displayName=Z;var Q=`SelectItemText`,We=z.forwardRef((e,t)=>{let{__scopeSelect:n,className:r,style:i,...a}=e,s=q(Q,n),l=X(Q,n),d=He(Q,n),f=fe(Q,n),[p,m]=z.useState(null),h=o(t,e=>m(e),d.onItemTextChange,e=>l.itemTextRefCallback?.(e,d.value,d.disabled)),g=p?.textContent,_=z.useMemo(()=>(0,V.jsx)(`option`,{value:d.value,disabled:d.disabled,children:g},d.value),[d.disabled,d.value,g]),{onNativeOptionAdd:v,onNativeOptionRemove:y}=f;return c(()=>(v(_),()=>y(_)),[v,y,_]),(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(u.span,{id:d.textId,...a,ref:h}),d.isSelected&&s.valueNode&&!s.valueNodeHasChildren?ie.createPortal(a.children,s.valueNode):null]})});We.displayName=Q;var Ge=`SelectItemIndicator`,Ke=z.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e;return He(Ge,n).isSelected?(0,V.jsx)(u.span,{"aria-hidden":!0,...r,ref:t}):null});Ke.displayName=Ge;var qe=`SelectScrollUpButton`,Je=z.forwardRef((e,t)=>{let n=X(qe,e.__scopeSelect),r=Me(qe,e.__scopeSelect),[i,a]=z.useState(!1),s=o(t,r.onScrollButtonChange);return c(()=>{if(n.viewport&&n.isPositioned){let e=function(){a(t.scrollTop>0)},t=n.viewport;return e(),t.addEventListener(`scroll`,e),()=>t.removeEventListener(`scroll`,e)}},[n.viewport,n.isPositioned]),i?(0,V.jsx)(Ze,{...e,ref:s,onAutoScroll:()=>{let{viewport:e,selectedItem:t}=n;e&&t&&(e.scrollTop-=t.offsetHeight)}}):null});Je.displayName=qe;var Ye=`SelectScrollDownButton`,Xe=z.forwardRef((e,t)=>{let n=X(Ye,e.__scopeSelect),r=Me(Ye,e.__scopeSelect),[i,a]=z.useState(!1),s=o(t,r.onScrollButtonChange);return c(()=>{if(n.viewport&&n.isPositioned){let e=function(){let e=t.scrollHeight-t.clientHeight;a(Math.ceil(t.scrollTop)<e)},t=n.viewport;return e(),t.addEventListener(`scroll`,e),()=>t.removeEventListener(`scroll`,e)}},[n.viewport,n.isPositioned]),i?(0,V.jsx)(Ze,{...e,ref:s,onAutoScroll:()=>{let{viewport:e,selectedItem:t}=n;e&&t&&(e.scrollTop+=t.offsetHeight)}}):null});Xe.displayName=Ye;var Ze=z.forwardRef((e,t)=>{let{__scopeSelect:n,onAutoScroll:r,...i}=e,a=X(`SelectScrollButton`,n),o=z.useRef(null),s=se(n),d=z.useCallback(()=>{o.current!==null&&(window.clearInterval(o.current),o.current=null)},[]);return z.useEffect(()=>()=>d(),[d]),c(()=>{s().find(e=>e.ref.current===document.activeElement)?.ref.current?.scrollIntoView({block:`nearest`})},[s]),(0,V.jsx)(u.div,{"aria-hidden":!0,...i,ref:t,style:{flexShrink:0,...i.style},onPointerDown:l(i.onPointerDown,()=>{o.current===null&&(o.current=window.setInterval(r,50))}),onPointerMove:l(i.onPointerMove,()=>{a.onItemLeave?.(),o.current===null&&(o.current=window.setInterval(r,50))}),onPointerLeave:l(i.onPointerLeave,()=>{d()})})}),Qe=`SelectSeparator`,$e=z.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e;return(0,V.jsx)(u.div,{"aria-hidden":!0,...r,ref:t})});$e.displayName=Qe;var et=`SelectArrow`,tt=z.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=K(n),a=q(et,n),o=X(et,n);return a.open&&o.position===`popper`?(0,V.jsx)(C,{...i,...r,ref:t}):null});tt.displayName=et;var nt=`SelectBubbleInput`,rt=z.forwardRef(({__scopeSelect:e,value:t,...n},r)=>{let i=z.useRef(null),a=o(r,i),s=B(t);return z.useEffect(()=>{let e=i.current;if(!e)return;let n=window.HTMLSelectElement.prototype,r=Object.getOwnPropertyDescriptor(n,`value`).set;if(s!==t&&r){let n=new Event(`change`,{bubbles:!0});r.call(e,t),e.dispatchEvent(n)}},[s,t]),(0,V.jsx)(u.select,{...n,style:{...M,...n.style},ref:a,defaultValue:t})});rt.displayName=nt;function it(e){return e===``||e===void 0}function at(e){let t=s(e),n=z.useRef(``),r=z.useRef(0),i=z.useCallback(e=>{let i=n.current+e;t(i),(function e(t){n.current=t,window.clearTimeout(r.current),t!==``&&(r.current=window.setTimeout(()=>e(``),1e3))})(i)},[t]),a=z.useCallback(()=>{n.current=``,window.clearTimeout(r.current)},[]);return z.useEffect(()=>()=>window.clearTimeout(r.current),[]),[n,i,a]}function ot(e,t,n){let r=t.length>1&&Array.from(t).every(e=>e===t[0])?t[0]:t,i=n?e.indexOf(n):-1,a=st(e,Math.max(i,0));r.length===1&&(a=a.filter(e=>e!==n));let o=a.find(e=>e.textValue.toLowerCase().startsWith(r.toLowerCase()));return o===n?void 0:o}function st(e,t){return e.map((n,r)=>e[(t+r)%e.length])}var ct=pe,lt=he,ut=_e,dt=ye,ft=xe,pt=Se,mt=Pe,ht=Ue,gt=We,_t=Ke,vt=Je,yt=Xe;function $({className:e,...t}){return(0,V.jsx)(re,{"data-slot":`label`,className:O(`flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50`,e),...t})}function bt({...e}){return(0,V.jsx)(ct,{"data-slot":`select`,...e})}function xt({...e}){return(0,V.jsx)(ut,{"data-slot":`select-value`,...e})}function St({className:e,size:t=`default`,children:n,...r}){return(0,V.jsxs)(lt,{"data-slot":`select-trigger`,"data-size":t,className:O(`flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground`,e),...r,children:[n,(0,V.jsx)(dt,{asChild:!0,children:(0,V.jsx)(A,{className:`size-4 opacity-50`})})]})}function Ct({className:e,children:t,position:n=`item-aligned`,align:r=`center`,...i}){return(0,V.jsx)(ft,{children:(0,V.jsxs)(pt,{"data-slot":`select-content`,className:O(`relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95`,n===`popper`&&`data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1`,e),position:n,align:r,...i,children:[(0,V.jsx)(Tt,{}),(0,V.jsx)(mt,{className:O(`p-1`,n===`popper`&&`h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1`),children:t}),(0,V.jsx)(Et,{})]})})}function wt({className:e,children:t,...n}){return(0,V.jsxs)(ht,{"data-slot":`select-item`,className:O(`relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2`,e),...n,children:[(0,V.jsx)(`span`,{"data-slot":`select-item-indicator`,className:`absolute right-2 flex size-3.5 items-center justify-center`,children:(0,V.jsx)(_t,{children:(0,V.jsx)(j,{className:`size-4`})})}),(0,V.jsx)(gt,{children:t})]})}function Tt({className:e,...t}){return(0,V.jsx)(vt,{"data-slot":`select-scroll-up-button`,className:O(`flex cursor-default items-center justify-center py-1`,e),...t,children:(0,V.jsx)(te,{className:`size-4`})})}function Et({className:e,...t}){return(0,V.jsx)(yt,{"data-slot":`select-scroll-down-button`,className:O(`flex cursor-default items-center justify-center py-1`,e),...t,children:(0,V.jsx)(A,{className:`size-4`})})}function Dt(){return k.get(`/api/settings/ai`)}function Ot(e){return k.put(`/api/settings/ai`,e)}var kt=[{value:`claude-sonnet-4-6`,label:`Claude Sonnet 4.6`},{value:`claude-opus-4-6`,label:`Claude Opus 4.6`},{value:`claude-haiku-4-5`,label:`Claude Haiku 4.5`}],At=[{value:`low`,label:`Low`},{value:`medium`,label:`Medium`},{value:`high`,label:`High`},{value:`max`,label:`Max`}];function jt(){let[e,t]=(0,z.useState)(null),[n,r]=(0,z.useState)(!1),[i,a]=(0,z.useState)(null),[o,s]=(0,z.useState)(0);(0,z.useEffect)(()=>{Dt().then(t).catch(e=>a(e.message))},[]);let c=e?.default_provider??`claude`,l=e?.providers[c],u=async(n,i)=>{if(e){r(!0),a(null);try{t(await Ot({providers:{[c]:{[n]:i}}})),s(e=>e+1)}catch(e){a(e.message)}finally{r(!1)}}};return e?(0,V.jsxs)(`div`,{className:`space-y-4`,children:[(0,V.jsx)(`h3`,{className:`text-sm font-medium text-text-secondary`,children:`AI Provider`}),(0,V.jsxs)(`div`,{className:`space-y-3`,children:[(0,V.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,V.jsx)($,{htmlFor:`ai-model`,children:`Model`}),(0,V.jsxs)(bt,{value:l?.model??`claude-sonnet-4-6`,onValueChange:e=>u(`model`,e),children:[(0,V.jsx)(St,{id:`ai-model`,className:`w-full`,children:(0,V.jsx)(xt,{})}),(0,V.jsx)(Ct,{children:kt.map(e=>(0,V.jsx)(wt,{value:e.value,children:e.label},e.value))})]})]}),(0,V.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,V.jsx)($,{htmlFor:`ai-effort`,children:`Effort`}),(0,V.jsxs)(bt,{value:l?.effort??`high`,onValueChange:e=>u(`effort`,e),children:[(0,V.jsx)(St,{id:`ai-effort`,className:`w-full`,children:(0,V.jsx)(xt,{})}),(0,V.jsx)(Ct,{children:At.map(e=>(0,V.jsx)(wt,{value:e.value,children:e.label},e.value))})]})]}),(0,V.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,V.jsx)($,{htmlFor:`ai-max-turns`,children:`Max Turns (1-500)`}),(0,V.jsx)(P,{id:`ai-max-turns`,type:`number`,min:1,max:500,defaultValue:l?.max_turns??100,onBlur:e=>{let t=parseInt(e.target.value);isNaN(t)||u(`max_turns`,t)}},`turns-${o}`)]}),(0,V.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,V.jsx)($,{htmlFor:`ai-budget`,children:`Max Budget (USD)`}),(0,V.jsx)(P,{id:`ai-budget`,type:`number`,step:.1,min:.01,max:50,defaultValue:l?.max_budget_usd??``,placeholder:`No limit`,onBlur:e=>{let t=parseFloat(e.target.value);u(`max_budget_usd`,isNaN(t)?void 0:t)}},`budget-${o}`)]}),(0,V.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,V.jsx)($,{htmlFor:`ai-thinking`,children:`Thinking Budget (tokens)`}),(0,V.jsx)(P,{id:`ai-thinking`,type:`number`,min:0,defaultValue:l?.thinking_budget_tokens??``,placeholder:`Disabled`,onBlur:e=>{let t=parseInt(e.target.value);u(`thinking_budget_tokens`,isNaN(t)?void 0:t)}},`thinking-${o}`)]})]}),n&&(0,V.jsx)(`p`,{className:`text-xs text-text-subtle`,children:`Saving...`}),i&&(0,V.jsx)(`p`,{className:`text-xs text-red-500`,children:i})]}):(0,V.jsxs)(`div`,{className:`space-y-3`,children:[(0,V.jsx)(`h3`,{className:`text-sm font-medium text-text-secondary`,children:`AI Provider`}),(0,V.jsx)(`p`,{className:`text-sm text-text-subtle`,children:i?`Error: ${i}`:`Loading...`})]})}var Mt=[{value:`light`,label:`Light`,icon:R},{value:`dark`,label:`Dark`,icon:L},{value:`system`,label:`System`,icon:I}];function Nt(){let{theme:e,setTheme:t}=N();return(0,V.jsxs)(`div`,{className:`h-full p-4 space-y-6 overflow-auto max-w-lg`,children:[(0,V.jsx)(`h2`,{className:`text-lg font-semibold`,children:`Settings`}),(0,V.jsxs)(`div`,{className:`space-y-3`,children:[(0,V.jsx)(`h3`,{className:`text-sm font-medium text-text-secondary`,children:`Theme`}),(0,V.jsx)(`div`,{className:`flex gap-2`,children:Mt.map(n=>{let r=n.icon;return(0,V.jsxs)(v,{variant:e===n.value?`default`:`outline`,size:`lg`,onClick:()=>t(n.value),className:O(`flex-1 gap-2`,e===n.value&&`ring-2 ring-primary`),children:[(0,V.jsx)(r,{className:`size-4`}),n.label]},n.value)})})]}),(0,V.jsx)(F,{}),(0,V.jsx)(jt,{}),(0,V.jsx)(F,{}),(0,V.jsxs)(`div`,{className:`space-y-3`,children:[(0,V.jsx)(`h3`,{className:`text-sm font-medium text-text-secondary`,children:`About`}),(0,V.jsx)(`p`,{className:`text-sm text-text-secondary`,children:`PPM — Personal Project Manager`}),(0,V.jsx)(`p`,{className:`text-xs text-text-subtle`,children:`A mobile-first web IDE for managing your projects.`})]})]})}export{Nt as SettingsTab};
@@ -1,4 +1,4 @@
1
- import{a as e,n as t,r as n,t as r}from"./jsx-runtime-BFALxl05.js";import{t as i}from"./copy-B-kLwqzg.js";import{t as a}from"./utils-DpJF9mAi.js";var o=t(`clipboard-paste`,[[`path`,{d:`M11 14h10`,key:`1w8e9d`}],[`path`,{d:`M16 4h2a2 2 0 0 1 2 2v1.344`,key:`1e62lh`}],[`path`,{d:`m17 18 4-4-4-4`,key:`z2g111`}],[`path`,{d:`M8 4H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 1.793-1.113`,key:`bjbb7m`}],[`rect`,{x:`8`,y:`2`,width:`8`,height:`4`,rx:`1`,key:`ublpy`}]]),s=e(n(),1),c=Object.defineProperty,l=Object.getOwnPropertyDescriptor,u=(e,t)=>{for(var n in t)c(e,n,{get:t[n],enumerable:!0})},d=(e,t,n,r)=>{for(var i=r>1?void 0:r?l(t,n):t,a=e.length-1,o;a>=0;a--)(o=e[a])&&(i=(r?o(t,n,i):o(i))||i);return r&&i&&c(t,n,i),i},f=(e,t)=>(n,r)=>t(n,r,e),p=`Terminal input`,m={get:()=>p,set:e=>p=e},h=`Too much output to announce, navigate to rows manually to read`,g={get:()=>h,set:e=>h=e};function _(e){return e.replace(/\r?\n/g,`\r`)}function v(e,t){return t?`\x1B[200~`+e+`\x1B[201~`:e}function ee(e,t){e.clipboardData&&e.clipboardData.setData(`text/plain`,t.selectionText),e.preventDefault()}function te(e,t,n,r){e.stopPropagation(),e.clipboardData&&ne(e.clipboardData.getData(`text/plain`),t,n,r)}function ne(e,t,n,r){e=_(e),e=v(e,n.decPrivateModes.bracketedPasteMode&&r.rawOptions.ignoreBracketedPasteMode!==!0),n.triggerDataEvent(e,!0),t.value=``}function re(e,t,n){let r=n.getBoundingClientRect(),i=e.clientX-r.left-10,a=e.clientY-r.top-10;t.style.width=`20px`,t.style.height=`20px`,t.style.left=`${i}px`,t.style.top=`${a}px`,t.style.zIndex=`1000`,t.focus()}function ie(e,t,n,r,i){re(e,t,n),i&&r.rightClickSelect(e),t.value=r.selectionText,t.select()}function y(e){return e>65535?(e-=65536,String.fromCharCode((e>>10)+55296)+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)}function ae(e,t=0,n=e.length){let r=``;for(let i=t;i<n;++i){let t=e[i];t>65535?(t-=65536,r+=String.fromCharCode((t>>10)+55296)+String.fromCharCode(t%1024+56320)):r+=String.fromCharCode(t)}return r}var oe=class{constructor(){this._interim=0}clear(){this._interim=0}decode(e,t){let n=e.length;if(!n)return 0;let r=0,i=0;if(this._interim){let n=e.charCodeAt(i++);56320<=n&&n<=57343?t[r++]=(this._interim-55296)*1024+n-56320+65536:(t[r++]=this._interim,t[r++]=n),this._interim=0}for(let a=i;a<n;++a){let i=e.charCodeAt(a);if(55296<=i&&i<=56319){if(++a>=n)return this._interim=i,r;let o=e.charCodeAt(a);56320<=o&&o<=57343?t[r++]=(i-55296)*1024+o-56320+65536:(t[r++]=i,t[r++]=o);continue}i!==65279&&(t[r++]=i)}return r}},b=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(e,t){let n=e.length;if(!n)return 0;let r=0,i,a,o,s,c=0,l=0;if(this.interim[0]){let i=!1,a=this.interim[0];a&=(a&224)==192?31:(a&240)==224?15:7;let o=0,s;for(;(s=this.interim[++o]&63)&&o<4;)a<<=6,a|=s;let c=(this.interim[0]&224)==192?2:(this.interim[0]&240)==224?3:4,u=c-o;for(;l<u;){if(l>=n)return 0;if(s=e[l++],(s&192)!=128){l--,i=!0;break}else this.interim[o++]=s,a<<=6,a|=s&63}i||(c===2?a<128?l--:t[r++]=a:c===3?a<2048||a>=55296&&a<=57343||a===65279||(t[r++]=a):a<65536||a>1114111||(t[r++]=a)),this.interim.fill(0)}let u=n-4,d=l;for(;d<n;){for(;d<u&&!((i=e[d])&128)&&!((a=e[d+1])&128)&&!((o=e[d+2])&128)&&!((s=e[d+3])&128);)t[r++]=i,t[r++]=a,t[r++]=o,t[r++]=s,d+=4;if(i=e[d++],i<128)t[r++]=i;else if((i&224)==192){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(c=(i&31)<<6|a&63,c<128){d--;continue}t[r++]=c}else if((i&240)==224){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,r;if(o=e[d++],(o&192)!=128){d--;continue}if(c=(i&15)<<12|(a&63)<<6|o&63,c<2048||c>=55296&&c<=57343||c===65279)continue;t[r++]=c}else if((i&248)==240){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,r;if(o=e[d++],(o&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,this.interim[2]=o,r;if(s=e[d++],(s&192)!=128){d--;continue}if(c=(i&7)<<18|(a&63)<<12|(o&63)<<6|s&63,c<65536||c>1114111)continue;t[r++]=c}}return r}},se=``,ce=` `,le=class e{constructor(){this.fg=0,this.bg=0,this.extended=new x}static toColorRGB(e){return[e>>>16&255,e>>>8&255,e&255]}static fromColorRGB(e){return(e[0]&255)<<16|(e[1]&255)<<8|e[2]&255}clone(){let t=new e;return t.fg=this.fg,t.bg=this.bg,t.extended=this.extended.clone(),t}isInverse(){return this.fg&67108864}isBold(){return this.fg&134217728}isUnderline(){return this.hasExtendedAttrs()&&this.extended.underlineStyle!==0?1:this.fg&268435456}isBlink(){return this.fg&536870912}isInvisible(){return this.fg&1073741824}isItalic(){return this.bg&67108864}isDim(){return this.bg&134217728}isStrikethrough(){return this.fg&2147483648}isProtected(){return this.bg&536870912}isOverline(){return this.bg&1073741824}getFgColorMode(){return this.fg&50331648}getBgColorMode(){return this.bg&50331648}isFgRGB(){return(this.fg&50331648)==50331648}isBgRGB(){return(this.bg&50331648)==50331648}isFgPalette(){return(this.fg&50331648)==16777216||(this.fg&50331648)==33554432}isBgPalette(){return(this.bg&50331648)==16777216||(this.bg&50331648)==33554432}isFgDefault(){return(this.fg&50331648)==0}isBgDefault(){return(this.bg&50331648)==0}isAttributeDefault(){return this.fg===0&&this.bg===0}getFgColor(){switch(this.fg&50331648){case 16777216:case 33554432:return this.fg&255;case 50331648:return this.fg&16777215;default:return-1}}getBgColor(){switch(this.bg&50331648){case 16777216:case 33554432:return this.bg&255;case 50331648:return this.bg&16777215;default:return-1}}hasExtendedAttrs(){return this.bg&268435456}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(this.bg&268435456&&~this.extended.underlineColor)switch(this.extended.underlineColor&50331648){case 16777216:case 33554432:return this.extended.underlineColor&255;case 50331648:return this.extended.underlineColor&16777215;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return this.bg&268435456&&~this.extended.underlineColor?this.extended.underlineColor&50331648:this.getFgColorMode()}isUnderlineColorRGB(){return this.bg&268435456&&~this.extended.underlineColor?(this.extended.underlineColor&50331648)==50331648:this.isFgRGB()}isUnderlineColorPalette(){return this.bg&268435456&&~this.extended.underlineColor?(this.extended.underlineColor&50331648)==16777216||(this.extended.underlineColor&50331648)==33554432:this.isFgPalette()}isUnderlineColorDefault(){return this.bg&268435456&&~this.extended.underlineColor?(this.extended.underlineColor&50331648)==0:this.isFgDefault()}getUnderlineStyle(){return this.fg&268435456?this.bg&268435456?this.extended.underlineStyle:1:0}getUnderlineVariantOffset(){return this.extended.underlineVariantOffset}},x=class e{constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}get ext(){return this._urlId?this._ext&-469762049|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(this._ext&469762048)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return this._ext&67108863}set underlineColor(e){this._ext&=-67108864,this._ext|=e&67108863}get urlId(){return this._urlId}set urlId(e){this._urlId=e}get underlineVariantOffset(){let e=(this._ext&3758096384)>>29;return e<0?e^4294967288:e}set underlineVariantOffset(e){this._ext&=536870911,this._ext|=e<<29&3758096384}clone(){return new e(this._ext,this._urlId)}isEmpty(){return this.underlineStyle===0&&this._urlId===0}},S=class e extends le{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new x,this.combinedData=``}static fromCharData(t){let n=new e;return n.setFromCharData(t),n}isCombined(){return this.content&2097152}getWidth(){return this.content>>22}getChars(){return this.content&2097152?this.combinedData:this.content&2097151?y(this.content&2097151):``}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):this.content&2097151}setFromCharData(e){this.fg=e[0],this.bg=0;let t=!1;if(e[1].length>2)t=!0;else if(e[1].length===2){let n=e[1].charCodeAt(0);if(55296<=n&&n<=56319){let r=e[1].charCodeAt(1);56320<=r&&r<=57343?this.content=(n-55296)*1024+r-56320+65536|e[2]<<22:t=!0}else t=!0}else this.content=e[1].charCodeAt(0)|e[2]<<22;t&&(this.combinedData=e[1],this.content=2097152|e[2]<<22)}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}},ue=`di$target`,de=`di$dependencies`,C=new Map;function fe(e){return e[de]||[]}function w(e){if(C.has(e))return C.get(e);let t=function(e,n,r){if(arguments.length!==3)throw Error(`@IServiceName-decorator can only be used to decorate a parameter`);pe(t,e,r)};return t._id=e,C.set(e,t),t}function pe(e,t,n){t[ue]===t?t[de].push({id:e,index:n}):(t[de]=[{id:e,index:n}],t[ue]=t)}var T=w(`BufferService`),me=w(`CoreMouseService`),E=w(`CoreService`),he=w(`CharsetService`),ge=w(`InstantiationService`),_e=w(`LogService`),D=w(`OptionsService`),ve=w(`OscLinkService`),ye=w(`UnicodeService`),be=w(`DecorationService`),xe=class{constructor(e,t,n){this._bufferService=e,this._optionsService=t,this._oscLinkService=n}provideLinks(e,t){let n=this._bufferService.buffer.lines.get(e-1);if(!n){t(void 0);return}let r=[],i=this._optionsService.rawOptions.linkHandler,a=new S,o=n.getTrimmedLength(),s=-1,c=-1,l=!1;for(let t=0;t<o;t++)if(!(c===-1&&!n.hasContent(t))){if(n.loadCell(t,a),a.hasExtendedAttrs()&&a.extended.urlId)if(c===-1){c=t,s=a.extended.urlId;continue}else l=a.extended.urlId!==s;else c!==-1&&(l=!0);if(l||c!==-1&&t===o-1){let n=this._oscLinkService.getLinkData(s)?.uri;if(n){let a={start:{x:c+1,y:e},end:{x:t+(!l&&t===o-1?1:0),y:e}},s=!1;if(!i?.allowNonHttpProtocols)try{let e=new URL(n);[`http:`,`https:`].includes(e.protocol)||(s=!0)}catch{s=!0}s||r.push({text:n,range:a,activate:(e,t)=>i?i.activate(e,t,a):Se(e,t),hover:(e,t)=>i?.hover?.(e,t,a),leave:(e,t)=>i?.leave?.(e,t,a)})}l=!1,a.hasExtendedAttrs()&&a.extended.urlId?(c=t,s=a.extended.urlId):(c=-1,s=-1)}}t(r)}};xe=d([f(0,T),f(1,D),f(2,ve)],xe);function Se(e,t){if(confirm(`Do you want to navigate to ${t}?
1
+ import{a as e,n as t,r as n,t as r}from"./jsx-runtime-BFALxl05.js";import{t as i}from"./copy-B-kLwqzg.js";import{t as a}from"./utils-61GRB9Cb.js";var o=t(`clipboard-paste`,[[`path`,{d:`M11 14h10`,key:`1w8e9d`}],[`path`,{d:`M16 4h2a2 2 0 0 1 2 2v1.344`,key:`1e62lh`}],[`path`,{d:`m17 18 4-4-4-4`,key:`z2g111`}],[`path`,{d:`M8 4H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 1.793-1.113`,key:`bjbb7m`}],[`rect`,{x:`8`,y:`2`,width:`8`,height:`4`,rx:`1`,key:`ublpy`}]]),s=e(n(),1),c=Object.defineProperty,l=Object.getOwnPropertyDescriptor,u=(e,t)=>{for(var n in t)c(e,n,{get:t[n],enumerable:!0})},d=(e,t,n,r)=>{for(var i=r>1?void 0:r?l(t,n):t,a=e.length-1,o;a>=0;a--)(o=e[a])&&(i=(r?o(t,n,i):o(i))||i);return r&&i&&c(t,n,i),i},f=(e,t)=>(n,r)=>t(n,r,e),p=`Terminal input`,m={get:()=>p,set:e=>p=e},h=`Too much output to announce, navigate to rows manually to read`,g={get:()=>h,set:e=>h=e};function _(e){return e.replace(/\r?\n/g,`\r`)}function v(e,t){return t?`\x1B[200~`+e+`\x1B[201~`:e}function ee(e,t){e.clipboardData&&e.clipboardData.setData(`text/plain`,t.selectionText),e.preventDefault()}function te(e,t,n,r){e.stopPropagation(),e.clipboardData&&ne(e.clipboardData.getData(`text/plain`),t,n,r)}function ne(e,t,n,r){e=_(e),e=v(e,n.decPrivateModes.bracketedPasteMode&&r.rawOptions.ignoreBracketedPasteMode!==!0),n.triggerDataEvent(e,!0),t.value=``}function re(e,t,n){let r=n.getBoundingClientRect(),i=e.clientX-r.left-10,a=e.clientY-r.top-10;t.style.width=`20px`,t.style.height=`20px`,t.style.left=`${i}px`,t.style.top=`${a}px`,t.style.zIndex=`1000`,t.focus()}function ie(e,t,n,r,i){re(e,t,n),i&&r.rightClickSelect(e),t.value=r.selectionText,t.select()}function y(e){return e>65535?(e-=65536,String.fromCharCode((e>>10)+55296)+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)}function ae(e,t=0,n=e.length){let r=``;for(let i=t;i<n;++i){let t=e[i];t>65535?(t-=65536,r+=String.fromCharCode((t>>10)+55296)+String.fromCharCode(t%1024+56320)):r+=String.fromCharCode(t)}return r}var oe=class{constructor(){this._interim=0}clear(){this._interim=0}decode(e,t){let n=e.length;if(!n)return 0;let r=0,i=0;if(this._interim){let n=e.charCodeAt(i++);56320<=n&&n<=57343?t[r++]=(this._interim-55296)*1024+n-56320+65536:(t[r++]=this._interim,t[r++]=n),this._interim=0}for(let a=i;a<n;++a){let i=e.charCodeAt(a);if(55296<=i&&i<=56319){if(++a>=n)return this._interim=i,r;let o=e.charCodeAt(a);56320<=o&&o<=57343?t[r++]=(i-55296)*1024+o-56320+65536:(t[r++]=i,t[r++]=o);continue}i!==65279&&(t[r++]=i)}return r}},b=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(e,t){let n=e.length;if(!n)return 0;let r=0,i,a,o,s,c=0,l=0;if(this.interim[0]){let i=!1,a=this.interim[0];a&=(a&224)==192?31:(a&240)==224?15:7;let o=0,s;for(;(s=this.interim[++o]&63)&&o<4;)a<<=6,a|=s;let c=(this.interim[0]&224)==192?2:(this.interim[0]&240)==224?3:4,u=c-o;for(;l<u;){if(l>=n)return 0;if(s=e[l++],(s&192)!=128){l--,i=!0;break}else this.interim[o++]=s,a<<=6,a|=s&63}i||(c===2?a<128?l--:t[r++]=a:c===3?a<2048||a>=55296&&a<=57343||a===65279||(t[r++]=a):a<65536||a>1114111||(t[r++]=a)),this.interim.fill(0)}let u=n-4,d=l;for(;d<n;){for(;d<u&&!((i=e[d])&128)&&!((a=e[d+1])&128)&&!((o=e[d+2])&128)&&!((s=e[d+3])&128);)t[r++]=i,t[r++]=a,t[r++]=o,t[r++]=s,d+=4;if(i=e[d++],i<128)t[r++]=i;else if((i&224)==192){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(c=(i&31)<<6|a&63,c<128){d--;continue}t[r++]=c}else if((i&240)==224){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,r;if(o=e[d++],(o&192)!=128){d--;continue}if(c=(i&15)<<12|(a&63)<<6|o&63,c<2048||c>=55296&&c<=57343||c===65279)continue;t[r++]=c}else if((i&248)==240){if(d>=n)return this.interim[0]=i,r;if(a=e[d++],(a&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,r;if(o=e[d++],(o&192)!=128){d--;continue}if(d>=n)return this.interim[0]=i,this.interim[1]=a,this.interim[2]=o,r;if(s=e[d++],(s&192)!=128){d--;continue}if(c=(i&7)<<18|(a&63)<<12|(o&63)<<6|s&63,c<65536||c>1114111)continue;t[r++]=c}}return r}},se=``,ce=` `,le=class e{constructor(){this.fg=0,this.bg=0,this.extended=new x}static toColorRGB(e){return[e>>>16&255,e>>>8&255,e&255]}static fromColorRGB(e){return(e[0]&255)<<16|(e[1]&255)<<8|e[2]&255}clone(){let t=new e;return t.fg=this.fg,t.bg=this.bg,t.extended=this.extended.clone(),t}isInverse(){return this.fg&67108864}isBold(){return this.fg&134217728}isUnderline(){return this.hasExtendedAttrs()&&this.extended.underlineStyle!==0?1:this.fg&268435456}isBlink(){return this.fg&536870912}isInvisible(){return this.fg&1073741824}isItalic(){return this.bg&67108864}isDim(){return this.bg&134217728}isStrikethrough(){return this.fg&2147483648}isProtected(){return this.bg&536870912}isOverline(){return this.bg&1073741824}getFgColorMode(){return this.fg&50331648}getBgColorMode(){return this.bg&50331648}isFgRGB(){return(this.fg&50331648)==50331648}isBgRGB(){return(this.bg&50331648)==50331648}isFgPalette(){return(this.fg&50331648)==16777216||(this.fg&50331648)==33554432}isBgPalette(){return(this.bg&50331648)==16777216||(this.bg&50331648)==33554432}isFgDefault(){return(this.fg&50331648)==0}isBgDefault(){return(this.bg&50331648)==0}isAttributeDefault(){return this.fg===0&&this.bg===0}getFgColor(){switch(this.fg&50331648){case 16777216:case 33554432:return this.fg&255;case 50331648:return this.fg&16777215;default:return-1}}getBgColor(){switch(this.bg&50331648){case 16777216:case 33554432:return this.bg&255;case 50331648:return this.bg&16777215;default:return-1}}hasExtendedAttrs(){return this.bg&268435456}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(this.bg&268435456&&~this.extended.underlineColor)switch(this.extended.underlineColor&50331648){case 16777216:case 33554432:return this.extended.underlineColor&255;case 50331648:return this.extended.underlineColor&16777215;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return this.bg&268435456&&~this.extended.underlineColor?this.extended.underlineColor&50331648:this.getFgColorMode()}isUnderlineColorRGB(){return this.bg&268435456&&~this.extended.underlineColor?(this.extended.underlineColor&50331648)==50331648:this.isFgRGB()}isUnderlineColorPalette(){return this.bg&268435456&&~this.extended.underlineColor?(this.extended.underlineColor&50331648)==16777216||(this.extended.underlineColor&50331648)==33554432:this.isFgPalette()}isUnderlineColorDefault(){return this.bg&268435456&&~this.extended.underlineColor?(this.extended.underlineColor&50331648)==0:this.isFgDefault()}getUnderlineStyle(){return this.fg&268435456?this.bg&268435456?this.extended.underlineStyle:1:0}getUnderlineVariantOffset(){return this.extended.underlineVariantOffset}},x=class e{constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}get ext(){return this._urlId?this._ext&-469762049|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(this._ext&469762048)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return this._ext&67108863}set underlineColor(e){this._ext&=-67108864,this._ext|=e&67108863}get urlId(){return this._urlId}set urlId(e){this._urlId=e}get underlineVariantOffset(){let e=(this._ext&3758096384)>>29;return e<0?e^4294967288:e}set underlineVariantOffset(e){this._ext&=536870911,this._ext|=e<<29&3758096384}clone(){return new e(this._ext,this._urlId)}isEmpty(){return this.underlineStyle===0&&this._urlId===0}},S=class e extends le{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new x,this.combinedData=``}static fromCharData(t){let n=new e;return n.setFromCharData(t),n}isCombined(){return this.content&2097152}getWidth(){return this.content>>22}getChars(){return this.content&2097152?this.combinedData:this.content&2097151?y(this.content&2097151):``}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):this.content&2097151}setFromCharData(e){this.fg=e[0],this.bg=0;let t=!1;if(e[1].length>2)t=!0;else if(e[1].length===2){let n=e[1].charCodeAt(0);if(55296<=n&&n<=56319){let r=e[1].charCodeAt(1);56320<=r&&r<=57343?this.content=(n-55296)*1024+r-56320+65536|e[2]<<22:t=!0}else t=!0}else this.content=e[1].charCodeAt(0)|e[2]<<22;t&&(this.combinedData=e[1],this.content=2097152|e[2]<<22)}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}},ue=`di$target`,de=`di$dependencies`,C=new Map;function fe(e){return e[de]||[]}function w(e){if(C.has(e))return C.get(e);let t=function(e,n,r){if(arguments.length!==3)throw Error(`@IServiceName-decorator can only be used to decorate a parameter`);pe(t,e,r)};return t._id=e,C.set(e,t),t}function pe(e,t,n){t[ue]===t?t[de].push({id:e,index:n}):(t[de]=[{id:e,index:n}],t[ue]=t)}var T=w(`BufferService`),me=w(`CoreMouseService`),E=w(`CoreService`),he=w(`CharsetService`),ge=w(`InstantiationService`),_e=w(`LogService`),D=w(`OptionsService`),ve=w(`OscLinkService`),ye=w(`UnicodeService`),be=w(`DecorationService`),xe=class{constructor(e,t,n){this._bufferService=e,this._optionsService=t,this._oscLinkService=n}provideLinks(e,t){let n=this._bufferService.buffer.lines.get(e-1);if(!n){t(void 0);return}let r=[],i=this._optionsService.rawOptions.linkHandler,a=new S,o=n.getTrimmedLength(),s=-1,c=-1,l=!1;for(let t=0;t<o;t++)if(!(c===-1&&!n.hasContent(t))){if(n.loadCell(t,a),a.hasExtendedAttrs()&&a.extended.urlId)if(c===-1){c=t,s=a.extended.urlId;continue}else l=a.extended.urlId!==s;else c!==-1&&(l=!0);if(l||c!==-1&&t===o-1){let n=this._oscLinkService.getLinkData(s)?.uri;if(n){let a={start:{x:c+1,y:e},end:{x:t+(!l&&t===o-1?1:0),y:e}},s=!1;if(!i?.allowNonHttpProtocols)try{let e=new URL(n);[`http:`,`https:`].includes(e.protocol)||(s=!0)}catch{s=!0}s||r.push({text:n,range:a,activate:(e,t)=>i?i.activate(e,t,a):Se(e,t),hover:(e,t)=>i?.hover?.(e,t,a),leave:(e,t)=>i?.leave?.(e,t,a)})}l=!1,a.hasExtendedAttrs()&&a.extended.urlId?(c=t,s=a.extended.urlId):(c=-1,s=-1)}}t(r)}};xe=d([f(0,T),f(1,D),f(2,ve)],xe);function Se(e,t){if(confirm(`Do you want to navigate to ${t}?
2
2
 
3
3
  WARNING: This link could potentially be dangerous`)){let e=window.open();if(e){try{e.opener=null}catch{}e.location.href=t}else console.warn(`Opening link blocked as opener could not be cleared`)}}var Ce=w(`CharSizeService`),we=w(`CoreBrowserService`),Te=w(`MouseService`),Ee=w(`RenderService`),De=w(`SelectionService`),Oe=w(`CharacterJoinerService`),ke=w(`ThemeService`),Ae=w(`LinkProviderService`),je=new class{constructor(){this.listeners=[],this.unexpectedErrorHandler=function(e){setTimeout(()=>{throw e.stack?Le.isErrorNoTelemetry(e)?new Le(e.message+`
4
4
 
@@ -8,17 +8,17 @@
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=Geist+Mono:wght@400;500;600;700&family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet" />
11
- <script type="module" crossorigin src="/assets/index-nk1dAWff.js"></script>
11
+ <script type="module" crossorigin src="/assets/index-DasstYgw.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-BFALxl05.js">
13
- <link rel="modulepreload" crossorigin href="/assets/utils-DpJF9mAi.js">
14
- <link rel="modulepreload" crossorigin href="/assets/button-KIZetva8.js">
15
- <link rel="modulepreload" crossorigin href="/assets/dist-C4W3AGh3.js">
16
- <link rel="modulepreload" crossorigin href="/assets/dist-PA84y4Ga.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/utils-61GRB9Cb.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/button-CvHWF07y.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/dist-CCBctnax.js">
16
+ <link rel="modulepreload" crossorigin href="/assets/dist-B6sG2GPc.js">
17
17
  <link rel="modulepreload" crossorigin href="/assets/x-BxhOxZ5p.js">
18
- <link rel="modulepreload" crossorigin href="/assets/dialog-D8ulRTfX.js">
19
- <link rel="modulepreload" crossorigin href="/assets/react-BSLFEYu8.js">
18
+ <link rel="modulepreload" crossorigin href="/assets/dialog-f3IZM-6v.js">
19
+ <link rel="modulepreload" crossorigin href="/assets/react-gOPBns57.js">
20
20
  <link rel="modulepreload" crossorigin href="/assets/api-client-BgVufYKf.js">
21
- <link rel="stylesheet" crossorigin href="/assets/index-DUBI96T5.css">
21
+ <link rel="stylesheet" crossorigin href="/assets/index-DILaVO6p.css">
22
22
  <link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
23
23
  <body class="bg-[#0f1419] text-[#e5e7eb] font-sans antialiased">
24
24
  <div id="root"></div>
package/dist/web/sw.js CHANGED
@@ -1 +1 @@
1
- if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,r)=>{const n=s||("document"in self?document.currentScript.src:"")||location.href;if(e[n])return;let t={};const u=s=>i(s,n),o={module:{uri:n},exports:t,require:u};e[n]=Promise.all(l.map(s=>o[s]||u(s))).then(s=>(r(...s),t))}}define(["./workbox-3e722498"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"1115c63bcaa9689db6843d71ee1f60f3"},{url:"icon-512.svg",revision:"a0fb34fc84eb148d51812cd62669f20d"},{url:"icon-192.svg",revision:"a0fb34fc84eb148d51812cd62669f20d"},{url:"assets/x-BxhOxZ5p.js",revision:null},{url:"assets/utils-DpJF9mAi.js",revision:null},{url:"assets/trash-2-CjahwKg8.js",revision:null},{url:"assets/terminal-tab-DDf6S-Tu.js",revision:null},{url:"assets/terminal-tab-BrP-ENHg.css",revision:null},{url:"assets/settings-tab-iCGeFFdt.js",revision:null},{url:"assets/refresh-cw-DJSjl6Ev.js",revision:null},{url:"assets/react-BSLFEYu8.js",revision:null},{url:"assets/project-list-DqiatpaH.js",revision:null},{url:"assets/marked.esm-Cv8mjgnt.js",revision:null},{url:"assets/jsx-runtime-BFALxl05.js",revision:null},{url:"assets/index-nk1dAWff.js",revision:null},{url:"assets/index-DUBI96T5.css",revision:null},{url:"assets/git-status-panel-QjAQzNAi.js",revision:null},{url:"assets/git-graph-Cn-s1k0-.js",revision:null},{url:"assets/external-link-Dim3NH6h.js",revision:null},{url:"assets/dist-PA84y4Ga.js",revision:null},{url:"assets/dist-CBiGQxfr.js",revision:null},{url:"assets/dist-C4W3AGh3.js",revision:null},{url:"assets/diff-viewer-vSvrem_i.js",revision:null},{url:"assets/dialog-D8ulRTfX.js",revision:null},{url:"assets/copy-B-kLwqzg.js",revision:null},{url:"assets/code-editor-r8P6Gk4M.js",revision:null},{url:"assets/chat-tab-D7dR7kbZ.js",revision:null},{url:"assets/button-KIZetva8.js",revision:null},{url:"assets/arrow-up-from-line-DjfWTP75.js",revision:null},{url:"assets/api-client-BgVufYKf.js",revision:null},{url:"manifest.webmanifest",revision:"79c8870653c8f419f2e3323085e1f4be"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"))),s.registerRoute(/^https?:\/\/.*\/api\//,new s.NetworkOnly,"GET"),s.registerRoute(/^https?:\/\/.*\/ws\//,new s.NetworkOnly,"GET")});
1
+ if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,n)=>{const r=s||("document"in self?document.currentScript.src:"")||location.href;if(e[r])return;let t={};const u=s=>i(s,r),o={module:{uri:r},exports:t,require:u};e[r]=Promise.all(l.map(s=>o[s]||u(s))).then(s=>(n(...s),t))}}define(["./workbox-3e722498"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"a901473b3162fa81ec87e095b1092e71"},{url:"icon-512.svg",revision:"a0fb34fc84eb148d51812cd62669f20d"},{url:"icon-192.svg",revision:"a0fb34fc84eb148d51812cd62669f20d"},{url:"assets/x-BxhOxZ5p.js",revision:null},{url:"assets/utils-61GRB9Cb.js",revision:null},{url:"assets/trash-2-CjahwKg8.js",revision:null},{url:"assets/terminal-tab-CyjhG4Ao.js",revision:null},{url:"assets/terminal-tab-BrP-ENHg.css",revision:null},{url:"assets/settings-tab-Cn5Ja0_J.js",revision:null},{url:"assets/refresh-cw-DJSjl6Ev.js",revision:null},{url:"assets/react-gOPBns57.js",revision:null},{url:"assets/project-list-C7L3hZct.js",revision:null},{url:"assets/marked.esm-Cv8mjgnt.js",revision:null},{url:"assets/jsx-runtime-BFALxl05.js",revision:null},{url:"assets/index-DasstYgw.js",revision:null},{url:"assets/index-DILaVO6p.css",revision:null},{url:"assets/git-status-panel-BifyO31N.js",revision:null},{url:"assets/git-graph-BiyTIbCz.js",revision:null},{url:"assets/external-link-Dim3NH6h.js",revision:null},{url:"assets/dist-CCBctnax.js",revision:null},{url:"assets/dist-CBiGQxfr.js",revision:null},{url:"assets/dist-B6sG2GPc.js",revision:null},{url:"assets/diff-viewer-8_asmBRZ.js",revision:null},{url:"assets/dialog-f3IZM-6v.js",revision:null},{url:"assets/copy-B-kLwqzg.js",revision:null},{url:"assets/code-editor-BgiyQO-M.js",revision:null},{url:"assets/chat-tab-C4ovA2w4.js",revision:null},{url:"assets/button-CvHWF07y.js",revision:null},{url:"assets/arrow-up-from-line-DjfWTP75.js",revision:null},{url:"assets/api-client-BgVufYKf.js",revision:null},{url:"manifest.webmanifest",revision:"79c8870653c8f419f2e3323085e1f4be"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"))),s.registerRoute(/^https?:\/\/.*\/api\//,new s.NetworkOnly,"GET"),s.registerRoute(/^https?:\/\/.*\/ws\//,new s.NetworkOnly,"GET")});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
@@ -8,7 +8,8 @@
8
8
  "ppm": "src/index.ts"
9
9
  },
10
10
  "scripts": {
11
- "dev": "bun run --hot src/index.ts start",
11
+ "dev": "bun run --hot src/index.ts start -f & bun run vite --config vite.config.ts",
12
+ "dev:server": "bun run --hot src/index.ts start -f",
12
13
  "dev:web": "bun run vite --config vite.config.ts",
13
14
  "build:web": "bun run vite build --config vite.config.ts",
14
15
  "build": "bun run build:web && bun build src/index.ts --compile --outfile dist/ppm",
@@ -41,7 +41,16 @@ export async function initProject(options: InitOptions = {}) {
41
41
 
42
42
  console.log("\n 🔧 PPM Setup\n");
43
43
 
44
- // 1. Port
44
+ // 1. Device name
45
+ const defaultHostname = (await import("node:os")).hostname();
46
+ const deviceName = nonInteractive
47
+ ? (options as any).deviceName ?? defaultHostname
48
+ : await input({
49
+ message: "Device name (shown in UI to identify this machine):",
50
+ default: defaultHostname,
51
+ });
52
+
53
+ // 2. Port
45
54
  const portValue = options.port
46
55
  ? parseInt(options.port, 10)
47
56
  : nonInteractive
@@ -140,6 +149,7 @@ export async function initProject(options: InitOptions = {}) {
140
149
 
141
150
  // Apply config
142
151
  configService.load();
152
+ configService.set("device_name", deviceName);
143
153
  configService.set("port", portValue);
144
154
  configService.set("auth", { enabled: authEnabled, token: authToken });
145
155
  configService.set("ai", {
@@ -0,0 +1,58 @@
1
+ import { resolve } from "node:path";
2
+ import { homedir } from "node:os";
3
+ import { existsSync, readFileSync, statSync } from "node:fs";
4
+
5
+ const LOG_FILE = resolve(homedir(), ".ppm", "ppm.log");
6
+
7
+ export async function showLogs(options: { tail?: string; follow?: boolean; clear?: boolean }) {
8
+ if (options.clear) {
9
+ const { writeFileSync } = await import("node:fs");
10
+ writeFileSync(LOG_FILE, "");
11
+ console.log("Logs cleared.");
12
+ return;
13
+ }
14
+
15
+ if (!existsSync(LOG_FILE)) {
16
+ console.log("No log file found. Start PPM daemon first.");
17
+ return;
18
+ }
19
+
20
+ const lines = parseInt(options.tail ?? "50", 10);
21
+ const content = readFileSync(LOG_FILE, "utf-8");
22
+ const allLines = content.split("\n");
23
+ const lastN = allLines.slice(-lines).join("\n");
24
+
25
+ if (!lastN.trim()) {
26
+ console.log("Log file is empty.");
27
+ return;
28
+ }
29
+
30
+ console.log(lastN);
31
+
32
+ if (options.follow) {
33
+ // Tail -f behavior
34
+ const { watch } = await import("node:fs");
35
+ let lastSize = statSync(LOG_FILE).size;
36
+ console.log("\n--- Following logs (Ctrl+C to stop) ---\n");
37
+
38
+ watch(LOG_FILE, () => {
39
+ try {
40
+ const newSize = statSync(LOG_FILE).size;
41
+ if (newSize > lastSize) {
42
+ const fd = Bun.file(LOG_FILE);
43
+ fd.slice(lastSize, newSize).text().then((text) => {
44
+ process.stdout.write(text);
45
+ });
46
+ lastSize = newSize;
47
+ }
48
+ } catch {}
49
+ });
50
+ }
51
+ }
52
+
53
+ /** Get last N lines of log for bug reports */
54
+ export function getRecentLogs(lines = 30): string {
55
+ if (!existsSync(LOG_FILE)) return "(no logs)";
56
+ const content = readFileSync(LOG_FILE, "utf-8");
57
+ return content.split("\n").slice(-lines).join("\n").trim() || "(empty)";
58
+ }
@@ -0,0 +1,60 @@
1
+ import { homedir, platform, arch, release } from "node:os";
2
+ import { resolve } from "node:path";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { getRecentLogs } from "./logs.ts";
5
+
6
+ const REPO = "hienlh/ppm";
7
+
8
+ export async function reportBug() {
9
+ const { VERSION: version } = await import("../../version.ts");
10
+ const logs = getRecentLogs(30);
11
+ const statusFile = resolve(homedir(), ".ppm", "status.json");
12
+ let statusInfo = "(not running)";
13
+ if (existsSync(statusFile)) {
14
+ try { statusInfo = readFileSync(statusFile, "utf-8"); } catch {}
15
+ }
16
+
17
+ const body = [
18
+ "## Environment",
19
+ `- PPM: v${version}`,
20
+ `- OS: ${platform()} ${arch()} ${release()}`,
21
+ `- Bun: ${Bun.version}`,
22
+ "",
23
+ "## Description",
24
+ "<!-- Describe the bug -->",
25
+ "",
26
+ "## Steps to Reproduce",
27
+ "1. ",
28
+ "",
29
+ "## Expected Behavior",
30
+ "",
31
+ "## Daemon Status",
32
+ "```json",
33
+ statusInfo,
34
+ "```",
35
+ "",
36
+ "## Recent Logs (last 30 lines)",
37
+ "```",
38
+ logs,
39
+ "```",
40
+ ].join("\n");
41
+
42
+ const title = encodeURIComponent("bug: ");
43
+ const encodedBody = encodeURIComponent(body);
44
+ const url = `https://github.com/${REPO}/issues/new?title=${title}&body=${encodedBody}`;
45
+
46
+ console.log(" Opening GitHub issue form in browser...\n");
47
+ console.log(" Environment info and recent logs will be pre-filled.\n");
48
+
49
+ const { $ } = await import("bun");
50
+ try {
51
+ if (platform() === "darwin") {
52
+ await $`open ${url}`.quiet();
53
+ } else {
54
+ await $`xdg-open ${url}`.quiet();
55
+ }
56
+ } catch {
57
+ console.log(" Could not open browser. Copy this URL:\n");
58
+ console.log(` ${url}\n`);
59
+ }
60
+ }
@@ -11,40 +11,46 @@ interface DaemonStatus {
11
11
  port: number | null;
12
12
  host: string | null;
13
13
  shareUrl: string | null;
14
+ tunnelPid: number | null;
15
+ tunnelAlive: boolean;
16
+ }
17
+
18
+ function isAlive(pid: number): boolean {
19
+ try { process.kill(pid, 0); return true; } catch { return false; }
14
20
  }
15
21
 
16
22
  function getDaemonStatus(): DaemonStatus {
17
- const notRunning: DaemonStatus = { running: false, pid: null, port: null, host: null, shareUrl: null };
23
+ const dead: DaemonStatus = {
24
+ running: false, pid: null, port: null, host: null,
25
+ shareUrl: null, tunnelPid: null, tunnelAlive: false,
26
+ };
18
27
 
19
- // Try status.json first
20
28
  if (existsSync(STATUS_FILE)) {
21
29
  try {
22
30
  const data = JSON.parse(readFileSync(STATUS_FILE, "utf-8"));
23
31
  const pid = data.pid as number;
24
- // Check if process is actually alive
25
- try {
26
- process.kill(pid, 0); // signal 0 = check existence
27
- return { running: true, pid, port: data.port, host: data.host, shareUrl: data.shareUrl ?? null };
28
- } catch {
29
- return notRunning; // stale status file
30
- }
31
- } catch {
32
- return notRunning;
33
- }
32
+ const tunnelPid = (data.tunnelPid as number) ?? null;
33
+ const tunnelAlive = tunnelPid ? isAlive(tunnelPid) : false;
34
+ return {
35
+ running: isAlive(pid),
36
+ pid,
37
+ port: data.port,
38
+ host: data.host,
39
+ shareUrl: data.shareUrl ?? null,
40
+ tunnelPid,
41
+ tunnelAlive,
42
+ };
43
+ } catch { return dead; }
34
44
  }
35
45
 
36
- // Fallback to ppm.pid
37
46
  if (existsSync(PID_FILE)) {
38
47
  try {
39
48
  const pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10);
40
- process.kill(pid, 0);
41
- return { running: true, pid, port: null, host: null, shareUrl: null };
42
- } catch {
43
- return notRunning;
44
- }
49
+ return { ...dead, running: isAlive(pid), pid };
50
+ } catch { return dead; }
45
51
  }
46
52
 
47
- return notRunning;
53
+ return dead;
48
54
  }
49
55
 
50
56
  export async function showStatus(options: { json?: boolean }) {
@@ -55,14 +61,17 @@ export async function showStatus(options: { json?: boolean }) {
55
61
  return;
56
62
  }
57
63
 
58
- if (!status.running) {
64
+ if (!status.running && !status.tunnelAlive) {
59
65
  console.log(" PPM is not running.");
60
66
  return;
61
67
  }
62
68
 
63
- console.log(`\n PPM daemon is running\n`);
64
- console.log(` PID: ${status.pid}`);
69
+ console.log(`\n PPM daemon status\n`);
70
+ console.log(` Server: ${status.running ? "running" : "stopped"} (PID: ${status.pid})`);
65
71
  if (status.port) console.log(` Local: http://localhost:${status.port}/`);
72
+ if (status.tunnelPid) {
73
+ console.log(` Tunnel: ${status.tunnelAlive ? "running" : "stopped"} (PID: ${status.tunnelPid})`);
74
+ }
66
75
  if (status.shareUrl) {
67
76
  console.log(` Share: ${status.shareUrl}`);
68
77
  const qr = await import("qrcode-terminal");
@@ -5,43 +5,51 @@ import { readFileSync, unlinkSync, existsSync } from "node:fs";
5
5
  const PID_FILE = resolve(homedir(), ".ppm", "ppm.pid");
6
6
  const STATUS_FILE = resolve(homedir(), ".ppm", "status.json");
7
7
 
8
+ function killPid(pid: number, label: string): boolean {
9
+ try {
10
+ process.kill(pid);
11
+ console.log(` Stopped ${label} (PID: ${pid})`);
12
+ return true;
13
+ } catch (e) {
14
+ const err = e as NodeJS.ErrnoException;
15
+ if (err.code !== "ESRCH") console.error(` Failed to stop ${label}: ${err.message}`);
16
+ return false;
17
+ }
18
+ }
19
+
8
20
  export async function stopServer() {
9
- let pid: number | null = null;
21
+ let status: { pid?: number; tunnelPid?: number } | null = null;
10
22
 
11
- // Try status.json first (new format)
23
+ // Read status.json
12
24
  if (existsSync(STATUS_FILE)) {
13
- try {
14
- const status = JSON.parse(readFileSync(STATUS_FILE, "utf-8"));
15
- pid = status.pid;
16
- } catch {}
25
+ try { status = JSON.parse(readFileSync(STATUS_FILE, "utf-8")); } catch {}
17
26
  }
18
27
 
19
- // Fallback to ppm.pid (compat)
20
- if (!pid && existsSync(PID_FILE)) {
21
- pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10);
22
- }
28
+ // Fallback to ppm.pid
29
+ const pidFromFile = existsSync(PID_FILE)
30
+ ? parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10)
31
+ : NaN;
32
+
33
+ const serverPid = status?.pid ?? (isNaN(pidFromFile) ? null : pidFromFile);
34
+ const tunnelPid = status?.tunnelPid ?? null;
23
35
 
24
- if (!pid || isNaN(pid)) {
36
+ if (!serverPid && !tunnelPid) {
25
37
  console.log("No PPM daemon running.");
26
- // Cleanup stale files
27
- if (existsSync(STATUS_FILE)) unlinkSync(STATUS_FILE);
28
- if (existsSync(PID_FILE)) unlinkSync(PID_FILE);
38
+ cleanup();
29
39
  return;
30
40
  }
31
41
 
32
- try {
33
- process.kill(pid);
34
- if (existsSync(STATUS_FILE)) unlinkSync(STATUS_FILE);
35
- if (existsSync(PID_FILE)) unlinkSync(PID_FILE);
36
- console.log(`PPM daemon stopped (PID: ${pid}).`);
37
- } catch (e) {
38
- const error = e as NodeJS.ErrnoException;
39
- if (error.code === "ESRCH") {
40
- console.log(`Process ${pid} not found. Cleaning up stale files.`);
41
- if (existsSync(STATUS_FILE)) unlinkSync(STATUS_FILE);
42
- if (existsSync(PID_FILE)) unlinkSync(PID_FILE);
43
- } else {
44
- console.error(`Failed to stop process ${pid}: ${error.message}`);
45
- }
46
- }
42
+ // Kill server process
43
+ if (serverPid) killPid(serverPid, "server");
44
+
45
+ // Kill tunnel process (independent from server)
46
+ if (tunnelPid) killPid(tunnelPid, "tunnel");
47
+
48
+ cleanup();
49
+ console.log("PPM stopped.");
50
+ }
51
+
52
+ function cleanup() {
53
+ if (existsSync(STATUS_FILE)) unlinkSync(STATUS_FILE);
54
+ if (existsSync(PID_FILE)) unlinkSync(PID_FILE);
47
55
  }
package/src/index.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env bun
2
2
  import { Command } from "commander";
3
+ import { VERSION } from "./version.ts";
3
4
 
4
5
  const program = new Command();
5
6
 
6
7
  program
7
8
  .name("ppm")
8
9
  .description("Personal Project Manager — mobile-first web IDE")
9
- .version("0.1.0");
10
+ .version(VERSION);
10
11
 
11
12
  program
12
13
  .command("start")
@@ -52,6 +53,25 @@ program
52
53
  await openBrowser();
53
54
  });
54
55
 
56
+ program
57
+ .command("logs")
58
+ .description("View PPM daemon logs")
59
+ .option("-n, --tail <lines>", "Number of lines to show", "50")
60
+ .option("-f, --follow", "Follow log output")
61
+ .option("--clear", "Clear log file")
62
+ .action(async (options) => {
63
+ const { showLogs } = await import("./cli/commands/logs.ts");
64
+ await showLogs(options);
65
+ });
66
+
67
+ program
68
+ .command("report")
69
+ .description("Report a bug on GitHub (pre-fills env info + logs)")
70
+ .action(async () => {
71
+ const { reportBug } = await import("./cli/commands/report.ts");
72
+ await reportBug();
73
+ });
74
+
55
75
  program
56
76
  .command("init")
57
77
  .description("Initialize PPM configuration (interactive or via flags)")