@hienlh/ppm 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/web/assets/{button-KIZetva8.js → button-CvHWF07y.js} +1 -1
- package/dist/web/assets/{chat-tab-D7dR7kbZ.js → chat-tab-C4ovA2w4.js} +3 -3
- package/dist/web/assets/{code-editor-r8P6Gk4M.js → code-editor-BgiyQO-M.js} +1 -1
- package/dist/web/assets/{dialog-D8ulRTfX.js → dialog-f3IZM-6v.js} +1 -1
- package/dist/web/assets/{diff-viewer-vSvrem_i.js → diff-viewer-8_asmBRZ.js} +1 -1
- package/dist/web/assets/{dist-C4W3AGh3.js → dist-CCBctnax.js} +1 -1
- package/dist/web/assets/{git-graph-Cn-s1k0-.js → git-graph-BiyTIbCz.js} +1 -1
- package/dist/web/assets/{git-status-panel-QjAQzNAi.js → git-status-panel-BifyO31N.js} +1 -1
- package/dist/web/assets/index-DILaVO6p.css +2 -0
- package/dist/web/assets/index-DasstYgw.js +11 -0
- package/dist/web/assets/project-list-C7L3hZct.js +1 -0
- package/dist/web/assets/settings-tab-Cn5Ja0_J.js +1 -0
- package/dist/web/assets/{terminal-tab-DDf6S-Tu.js → terminal-tab-CyjhG4Ao.js} +1 -1
- package/dist/web/index.html +8 -8
- package/dist/web/sw.js +1 -1
- package/package.json +3 -2
- package/src/cli/commands/init.ts +11 -1
- package/src/cli/commands/logs.ts +58 -0
- package/src/cli/commands/report.ts +60 -0
- package/src/index.ts +20 -1
- package/src/server/index.ts +82 -4
- package/src/types/config.ts +2 -0
- package/src/web/app.tsx +8 -0
- package/src/web/components/auth/login-screen.tsx +8 -1
- package/src/web/components/layout/sidebar.tsx +15 -0
- package/src/web/components/ui/sonner.tsx +9 -6
- package/src/web/hooks/use-health-check.ts +95 -0
- package/src/web/stores/settings-store.ts +19 -0
- package/src/web/stores/tab-store.ts +28 -8
- package/dist/web/assets/index-DUBI96T5.css +0 -2
- package/dist/web/assets/index-nk1dAWff.js +0 -10
- package/dist/web/assets/project-list-DqiatpaH.js +0 -1
- package/dist/web/assets/settings-tab-iCGeFFdt.js +0 -1
- /package/dist/web/assets/{dist-PA84y4Ga.js → dist-B6sG2GPc.js} +0 -0
- /package/dist/web/assets/{react-BSLFEYu8.js → react-gOPBns57.js} +0 -0
- /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
|
|
package/dist/web/index.html
CHANGED
|
@@ -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-
|
|
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-
|
|
14
|
-
<link rel="modulepreload" crossorigin href="/assets/button-
|
|
15
|
-
<link rel="modulepreload" crossorigin href="/assets/dist-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="/assets/dist-
|
|
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-
|
|
19
|
-
<link rel="modulepreload" crossorigin href="/assets/react-
|
|
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-
|
|
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,
|
|
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.
|
|
3
|
+
"version": "0.2.1",
|
|
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",
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -41,7 +41,16 @@ export async function initProject(options: InitOptions = {}) {
|
|
|
41
41
|
|
|
42
42
|
console.log("\n 🔧 PPM Setup\n");
|
|
43
43
|
|
|
44
|
-
// 1.
|
|
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 = "0.2.1";
|
|
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
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ const program = new Command();
|
|
|
6
6
|
program
|
|
7
7
|
.name("ppm")
|
|
8
8
|
.description("Personal Project Manager — mobile-first web IDE")
|
|
9
|
-
.version("0.1
|
|
9
|
+
.version("0.2.1");
|
|
10
10
|
|
|
11
11
|
program
|
|
12
12
|
.command("start")
|
|
@@ -52,6 +52,25 @@ program
|
|
|
52
52
|
await openBrowser();
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
+
program
|
|
56
|
+
.command("logs")
|
|
57
|
+
.description("View PPM daemon logs")
|
|
58
|
+
.option("-n, --tail <lines>", "Number of lines to show", "50")
|
|
59
|
+
.option("-f, --follow", "Follow log output")
|
|
60
|
+
.option("--clear", "Clear log file")
|
|
61
|
+
.action(async (options) => {
|
|
62
|
+
const { showLogs } = await import("./cli/commands/logs.ts");
|
|
63
|
+
await showLogs(options);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
program
|
|
67
|
+
.command("report")
|
|
68
|
+
.description("Report a bug on GitHub (pre-fills env info + logs)")
|
|
69
|
+
.action(async () => {
|
|
70
|
+
const { reportBug } = await import("./cli/commands/report.ts");
|
|
71
|
+
await reportBug();
|
|
72
|
+
});
|
|
73
|
+
|
|
55
74
|
program
|
|
56
75
|
.command("init")
|
|
57
76
|
.description("Initialize PPM configuration (interactive or via flags)")
|
package/src/server/index.ts
CHANGED
|
@@ -10,13 +10,85 @@ import { terminalWebSocket } from "./ws/terminal.ts";
|
|
|
10
10
|
import { chatWebSocket } from "./ws/chat.ts";
|
|
11
11
|
import { ok } from "../types/api.ts";
|
|
12
12
|
|
|
13
|
+
/** Tee console.log/error to ~/.ppm/ppm.log while preserving terminal output */
|
|
14
|
+
async function setupLogFile() {
|
|
15
|
+
const { resolve } = await import("node:path");
|
|
16
|
+
const { homedir } = await import("node:os");
|
|
17
|
+
const { appendFileSync, mkdirSync, existsSync } = await import("node:fs");
|
|
18
|
+
|
|
19
|
+
const ppmDir = resolve(homedir(), ".ppm");
|
|
20
|
+
if (!existsSync(ppmDir)) mkdirSync(ppmDir, { recursive: true });
|
|
21
|
+
const logPath = resolve(ppmDir, "ppm.log");
|
|
22
|
+
|
|
23
|
+
const origLog = console.log.bind(console);
|
|
24
|
+
const origError = console.error.bind(console);
|
|
25
|
+
const origWarn = console.warn.bind(console);
|
|
26
|
+
|
|
27
|
+
/** Redact tokens, passwords, API keys, and other sensitive values from log output */
|
|
28
|
+
const redact = (text: string): string =>
|
|
29
|
+
text
|
|
30
|
+
.replace(/Token:\s*\S+/gi, "Token: [REDACTED]")
|
|
31
|
+
.replace(/Bearer\s+\S+/gi, "Bearer [REDACTED]")
|
|
32
|
+
.replace(/password['":\s]+\S+/gi, "password: [REDACTED]")
|
|
33
|
+
.replace(/api[_-]?key['":\s]+\S+/gi, "api_key: [REDACTED]")
|
|
34
|
+
.replace(/ANTHROPIC_API_KEY=\S+/gi, "ANTHROPIC_API_KEY=[REDACTED]")
|
|
35
|
+
.replace(/secret['":\s]+\S+/gi, "secret: [REDACTED]");
|
|
36
|
+
|
|
37
|
+
const writeLog = (level: string, args: unknown[]) => {
|
|
38
|
+
const ts = new Date().toISOString();
|
|
39
|
+
const msg = args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ");
|
|
40
|
+
try { appendFileSync(logPath, `[${ts}] [${level}] ${redact(msg)}\n`); } catch {}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
console.log = (...args: unknown[]) => { origLog(...args); writeLog("INFO", args); };
|
|
44
|
+
console.error = (...args: unknown[]) => { origError(...args); writeLog("ERROR", args); };
|
|
45
|
+
console.warn = (...args: unknown[]) => { origWarn(...args); writeLog("WARN", args); };
|
|
46
|
+
|
|
47
|
+
// Capture uncaught errors
|
|
48
|
+
process.on("uncaughtException", (err) => {
|
|
49
|
+
writeLog("FATAL", [`Uncaught exception: ${err.stack ?? err.message}`]);
|
|
50
|
+
});
|
|
51
|
+
process.on("unhandledRejection", (reason) => {
|
|
52
|
+
writeLog("FATAL", [`Unhandled rejection: ${reason}`]);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
13
56
|
export const app = new Hono();
|
|
14
57
|
|
|
15
58
|
// CORS for dev
|
|
16
59
|
app.use("*", cors());
|
|
17
60
|
|
|
18
|
-
//
|
|
61
|
+
// Public endpoints (before auth)
|
|
19
62
|
app.get("/api/health", (c) => c.json(ok({ status: "running" })));
|
|
63
|
+
app.get("/api/info", (c) => c.json(ok({
|
|
64
|
+
version: "0.2.1",
|
|
65
|
+
device_name: configService.get("device_name") || null,
|
|
66
|
+
})));
|
|
67
|
+
|
|
68
|
+
// Public: recent logs for bug reports (last 30 lines)
|
|
69
|
+
app.get("/api/logs/recent", async (c) => {
|
|
70
|
+
const { resolve } = await import("node:path");
|
|
71
|
+
const { homedir } = await import("node:os");
|
|
72
|
+
const { existsSync, readFileSync } = await import("node:fs");
|
|
73
|
+
const logFile = resolve(homedir(), ".ppm", "ppm.log");
|
|
74
|
+
if (!existsSync(logFile)) return c.json(ok({ logs: "" }));
|
|
75
|
+
const content = readFileSync(logFile, "utf-8");
|
|
76
|
+
const lines = content.split("\n").slice(-30).join("\n").trim();
|
|
77
|
+
// Double-redact in case old logs have unredacted content
|
|
78
|
+
const redacted = lines
|
|
79
|
+
.replace(/Token:\s*\S+/gi, "Token: [REDACTED]")
|
|
80
|
+
.replace(/Bearer\s+\S+/gi, "Bearer [REDACTED]")
|
|
81
|
+
.replace(/password['":\s]+\S+/gi, "password: [REDACTED]")
|
|
82
|
+
.replace(/api[_-]?key['":\s]+\S+/gi, "api_key: [REDACTED]")
|
|
83
|
+
.replace(/ANTHROPIC_API_KEY=\S+/gi, "ANTHROPIC_API_KEY=[REDACTED]")
|
|
84
|
+
.replace(/secret['":\s]+\S+/gi, "secret: [REDACTED]");
|
|
85
|
+
return c.json(ok({ logs: redacted }));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Dev-only: crash endpoint for testing health check UI
|
|
89
|
+
if (process.env.NODE_ENV !== "production") {
|
|
90
|
+
app.get("/api/debug/crash", () => { process.exit(1); });
|
|
91
|
+
}
|
|
20
92
|
|
|
21
93
|
// Auth check endpoint (behind auth middleware)
|
|
22
94
|
app.use("/api/*", authMiddleware);
|
|
@@ -42,6 +114,9 @@ export async function startServer(options: {
|
|
|
42
114
|
const port = parseInt(options.port ?? String(configService.get("port")), 10);
|
|
43
115
|
const host = configService.get("host");
|
|
44
116
|
|
|
117
|
+
// Setup log file (both foreground and daemon modes)
|
|
118
|
+
await setupLogFile();
|
|
119
|
+
|
|
45
120
|
const isDaemon = !options.foreground;
|
|
46
121
|
|
|
47
122
|
if (isDaemon) {
|
|
@@ -60,13 +135,16 @@ export async function startServer(options: {
|
|
|
60
135
|
await ensureCloudflared();
|
|
61
136
|
}
|
|
62
137
|
|
|
63
|
-
// Spawn child process
|
|
138
|
+
// Spawn child process with log file
|
|
139
|
+
const { openSync } = await import("node:fs");
|
|
140
|
+
const logFile = resolve(ppmDir, "ppm.log");
|
|
141
|
+
const logFd = openSync(logFile, "a");
|
|
64
142
|
const child = Bun.spawn({
|
|
65
143
|
cmd: [
|
|
66
144
|
process.execPath, "run", import.meta.dir + "/index.ts", "__serve__",
|
|
67
145
|
String(port), host, options.config ?? "", options.share ? "share" : "",
|
|
68
146
|
],
|
|
69
|
-
stdio: ["ignore",
|
|
147
|
+
stdio: ["ignore", logFd, logFd],
|
|
70
148
|
env: process.env,
|
|
71
149
|
});
|
|
72
150
|
child.unref();
|
|
@@ -157,7 +235,7 @@ export async function startServer(options: {
|
|
|
157
235
|
} as Parameters<typeof Bun.serve>[0] extends { websocket?: infer W } ? W : never,
|
|
158
236
|
});
|
|
159
237
|
|
|
160
|
-
console.log(`\n PPM v0.2.
|
|
238
|
+
console.log(`\n PPM v0.2.1 ready\n`);
|
|
161
239
|
console.log(` ➜ Local: http://localhost:${server.port}/`);
|
|
162
240
|
|
|
163
241
|
const { networkInterfaces } = await import("node:os");
|
package/src/types/config.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export interface PpmConfig {
|
|
2
|
+
device_name: string;
|
|
2
3
|
port: number;
|
|
3
4
|
host: string;
|
|
4
5
|
auth: AuthConfig;
|
|
@@ -33,6 +34,7 @@ export interface AIProviderConfig {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export const DEFAULT_CONFIG: PpmConfig = {
|
|
37
|
+
device_name: "",
|
|
36
38
|
port: 8080,
|
|
37
39
|
host: "0.0.0.0",
|
|
38
40
|
auth: { enabled: true, token: "" },
|
package/src/web/app.tsx
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { getAuthToken } from "@/lib/api-client";
|
|
17
17
|
import { useUrlSync, parseUrlState } from "@/hooks/use-url-sync";
|
|
18
18
|
import { useGlobalKeybindings } from "@/hooks/use-global-keybindings";
|
|
19
|
+
import { useHealthCheck } from "@/hooks/use-health-check";
|
|
19
20
|
import { CommandPalette } from "@/components/layout/command-palette";
|
|
20
21
|
|
|
21
22
|
type AuthState = "checking" | "authenticated" | "unauthenticated";
|
|
@@ -25,6 +26,7 @@ export function App() {
|
|
|
25
26
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
26
27
|
const theme = useSettingsStore((s) => s.theme);
|
|
27
28
|
const fetchProjects = useProjectStore((s) => s.fetchProjects);
|
|
29
|
+
const fetchServerInfo = useSettingsStore((s) => s.fetchServerInfo);
|
|
28
30
|
const activeProject = useProjectStore((s) => s.activeProject);
|
|
29
31
|
|
|
30
32
|
// Apply theme on mount and when it changes
|
|
@@ -40,6 +42,9 @@ export function App() {
|
|
|
40
42
|
}
|
|
41
43
|
}, [theme]);
|
|
42
44
|
|
|
45
|
+
// Fetch server info on mount (before auth — shown on login screen)
|
|
46
|
+
useEffect(() => { fetchServerInfo(); }, [fetchServerInfo]);
|
|
47
|
+
|
|
43
48
|
// Auth check on mount
|
|
44
49
|
useEffect(() => {
|
|
45
50
|
async function checkAuth() {
|
|
@@ -73,6 +78,9 @@ export function App() {
|
|
|
73
78
|
// Global keyboard shortcuts (Shift+Shift → command palette, Alt+[/] → cycle tabs)
|
|
74
79
|
const { paletteOpen, closePalette } = useGlobalKeybindings();
|
|
75
80
|
|
|
81
|
+
// Health check — detects server crash/restart
|
|
82
|
+
useHealthCheck();
|
|
83
|
+
|
|
76
84
|
// Fetch projects after auth, then restore from URL if applicable
|
|
77
85
|
useEffect(() => {
|
|
78
86
|
if (authState !== "authenticated") return;
|
|
@@ -3,6 +3,7 @@ import { Button } from "@/components/ui/button";
|
|
|
3
3
|
import { Input } from "@/components/ui/input";
|
|
4
4
|
import { setAuthToken } from "@/lib/api-client";
|
|
5
5
|
import { Lock, AlertCircle } from "lucide-react";
|
|
6
|
+
import { useSettingsStore } from "@/stores/settings-store";
|
|
6
7
|
|
|
7
8
|
interface LoginScreenProps {
|
|
8
9
|
onSuccess: () => void;
|
|
@@ -10,6 +11,7 @@ interface LoginScreenProps {
|
|
|
10
11
|
|
|
11
12
|
export function LoginScreen({ onSuccess }: LoginScreenProps) {
|
|
12
13
|
const [token, setToken] = useState("");
|
|
14
|
+
const deviceName = useSettingsStore((s) => s.deviceName);
|
|
13
15
|
const [error, setError] = useState<string | null>(null);
|
|
14
16
|
const [loading, setLoading] = useState(false);
|
|
15
17
|
|
|
@@ -50,8 +52,13 @@ export function LoginScreen({ onSuccess }: LoginScreenProps) {
|
|
|
50
52
|
<Lock className="size-6 text-primary" />
|
|
51
53
|
</div>
|
|
52
54
|
<h1 className="text-xl font-semibold text-foreground">PPM</h1>
|
|
55
|
+
{deviceName && (
|
|
56
|
+
<p className="text-xs text-text-subtle bg-surface-elevated inline-block px-2 py-0.5 rounded-full">
|
|
57
|
+
{deviceName}
|
|
58
|
+
</p>
|
|
59
|
+
)}
|
|
53
60
|
<p className="text-sm text-text-secondary">
|
|
54
|
-
Enter your
|
|
61
|
+
Enter your access password to unlock
|
|
55
62
|
</p>
|
|
56
63
|
</div>
|
|
57
64
|
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
DropdownMenuSeparator,
|
|
10
10
|
DropdownMenuTrigger,
|
|
11
11
|
} from "@/components/ui/dropdown-menu";
|
|
12
|
+
import { useSettingsStore } from "@/stores/settings-store";
|
|
12
13
|
import { cn } from "@/lib/utils";
|
|
13
14
|
|
|
14
15
|
/** Max projects shown before needing to search (desktop) */
|
|
@@ -18,6 +19,8 @@ export function Sidebar() {
|
|
|
18
19
|
const { projects, activeProject, setActiveProject, loading } =
|
|
19
20
|
useProjectStore();
|
|
20
21
|
const openTab = useTabStore((s) => s.openTab);
|
|
22
|
+
const deviceName = useSettingsStore((s) => s.deviceName);
|
|
23
|
+
const version = useSettingsStore((s) => s.version);
|
|
21
24
|
const [query, setQuery] = useState("");
|
|
22
25
|
|
|
23
26
|
const sorted = useMemo(() => sortByRecent(projects), [projects]);
|
|
@@ -41,6 +44,11 @@ export function Sidebar() {
|
|
|
41
44
|
{/* Logo + project dropdown — same height as tab bar */}
|
|
42
45
|
<div className="flex items-center gap-2 px-3 h-[41px] border-b border-border shrink-0">
|
|
43
46
|
<span className="text-sm font-bold text-primary tracking-tight shrink-0">PPM</span>
|
|
47
|
+
{deviceName && (
|
|
48
|
+
<span className="text-[10px] text-text-subtle bg-surface-elevated px-1.5 py-0.5 rounded-full truncate max-w-[100px]" title={deviceName}>
|
|
49
|
+
{deviceName}
|
|
50
|
+
</span>
|
|
51
|
+
)}
|
|
44
52
|
|
|
45
53
|
<DropdownMenu onOpenChange={() => setQuery("")}>
|
|
46
54
|
<DropdownMenuTrigger asChild>
|
|
@@ -121,6 +129,13 @@ export function Sidebar() {
|
|
|
121
129
|
</p>
|
|
122
130
|
</div>
|
|
123
131
|
)}
|
|
132
|
+
|
|
133
|
+
{/* Version footer */}
|
|
134
|
+
{version && (
|
|
135
|
+
<div className="px-3 py-1.5 border-t border-border shrink-0">
|
|
136
|
+
<span className="text-[10px] text-text-subtle">v{version}</span>
|
|
137
|
+
</div>
|
|
138
|
+
)}
|
|
124
139
|
</aside>
|
|
125
140
|
);
|
|
126
141
|
}
|