codemini-cli 0.6.4 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/codemini-web/dist/assets/{AboutDialog-MRopwNIL.js → AboutDialog-dFkTshay.js} +2 -2
  2. package/codemini-web/dist/assets/CodeWikiPanel-Dqup5Sen.js +1 -0
  3. package/codemini-web/dist/assets/ConfigDialog-DTehAh2r.js +1 -0
  4. package/codemini-web/dist/assets/{GitDiffDialog-gSysUg2J.js → GitDiffDialog-D4uMixee.js} +2 -2
  5. package/codemini-web/dist/assets/{MemoryDialog-DFUmo3Kl.js → MemoryDialog-DJqtWamU.js} +3 -3
  6. package/codemini-web/dist/assets/MessageBubble-BGnFIxcq.js +12 -0
  7. package/codemini-web/dist/assets/{PatchDiff-B8rwvEg5.js → PatchDiff-CpHAbmv3.js} +1 -1
  8. package/codemini-web/dist/assets/ProjectSelector-CgJDcTNL.js +1 -0
  9. package/codemini-web/dist/assets/SkillDialog-D1J46nMC.js +8 -0
  10. package/codemini-web/dist/assets/{SoulDialog-BLjUGqqB.js → SoulDialog-DIqK4utD.js} +1 -1
  11. package/codemini-web/dist/assets/chevron-right-BBG4s6Zh.js +1 -0
  12. package/codemini-web/dist/assets/{chunk-BO2N2NFS-6uELoidu.js → chunk-BO2N2NFS-fRXUeu1b.js} +4 -4
  13. package/codemini-web/dist/assets/{highlighted-body-OFNGDK62-gb1UMBZ5.js → highlighted-body-OFNGDK62-CKKvx7S1.js} +1 -1
  14. package/codemini-web/dist/assets/index-DF9s7Tuc.css +2 -0
  15. package/codemini-web/dist/assets/{index-CDXQGwPs.js → index-DyIUhlc8.js} +6 -6
  16. package/codemini-web/dist/assets/input-BKNu4DOt.js +1 -0
  17. package/codemini-web/dist/assets/mermaid-GHXKKRXX-BM8yuNk5.js +1 -0
  18. package/codemini-web/dist/assets/{pencil-BhT11Ztp.js → pencil-C0uznNC_.js} +1 -1
  19. package/codemini-web/dist/assets/{refresh-cw-D7R5Lth6.js → refresh-cw-DUgU5bEu.js} +1 -1
  20. package/codemini-web/dist/assets/select-J6668k2a.js +1 -0
  21. package/codemini-web/dist/assets/{trash-2-BfNZcWfX.js → trash-2-H0DiWqiE.js} +1 -1
  22. package/codemini-web/dist/index.html +2 -2
  23. package/codemini-web/lib/runtime-bridge.js +7 -0
  24. package/codemini-web/server.js +100 -74
  25. package/package.json +1 -1
  26. package/src/commands/skill.js +188 -48
  27. package/src/core/agent-loop.js +73 -34
  28. package/src/core/chat-runtime.js +22 -17
  29. package/src/core/config-store.js +2 -4
  30. package/src/core/git-oplog-change-tracker.js +96 -15
  31. package/src/core/shell-profile.js +3 -2
  32. package/src/core/tools.js +144 -51
  33. package/codemini-web/dist/assets/CodeWikiPanel-UpK5xGE3.js +0 -1
  34. package/codemini-web/dist/assets/ConfigDialog-CNl28wsj.js +0 -1
  35. package/codemini-web/dist/assets/MessageBubble-CGnnViv0.js +0 -12
  36. package/codemini-web/dist/assets/ProjectSelector-BF59M1zb.js +0 -1
  37. package/codemini-web/dist/assets/SkillDialog-CQTjbSiw.js +0 -8
  38. package/codemini-web/dist/assets/chevron-right--85xg7qk.js +0 -1
  39. package/codemini-web/dist/assets/index-1xqD0R5t.css +0 -2
  40. package/codemini-web/dist/assets/input-Ca8O_061.js +0 -1
  41. package/codemini-web/dist/assets/mermaid-GHXKKRXX-ROliF8Yd.js +0 -1
  42. package/codemini-web/dist/assets/select-DBvcHBzs.js +0 -1
@@ -0,0 +1 @@
1
+ import"./rolldown-runtime-S-ySWqyJ.js";import{a as e,r as t}from"./bundle-mjs-C44PrJ2C.js";import{pt as n}from"./index-DyIUhlc8.js";e();var r=t();function i({className:e,type:t,...i}){return(0,r.jsx)(`input`,{type:t,"data-slot":`input`,className:n(`h-8 w-full min-w-0 rounded-md border border-(--border-default) bg-[color-mix(in_srgb,var(--bg-input)_88%,var(--text-muted)_12%)] px-3 py-1 text-[13px] text-(--text-primary) transition-colors outline-none placeholder:text-(--text-muted) disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50`,`hover:bg-[color-mix(in_srgb,var(--bg-input)_76%,var(--text-muted)_24%)] focus-visible:border-(--text-secondary) focus-visible:bg-(--bg-input) focus-visible:ring-0`,e),...i})}export{i as t};
@@ -0,0 +1 @@
1
+ import{a as e}from"./chunk-BO2N2NFS-fRXUeu1b.js";export{e as Mermaid};
@@ -1 +1 @@
1
- import{P as e}from"./index-CDXQGwPs.js";var t=e(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),n=e(`pencil`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]);export{t as n,n as t};
1
+ import{P as e}from"./index-DyIUhlc8.js";var t=e(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),n=e(`pencil`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]);export{t as n,n as t};
@@ -1 +1 @@
1
- import{P as e}from"./index-CDXQGwPs.js";var t=e(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]);export{t};
1
+ import{P as e}from"./index-DyIUhlc8.js";var t=e(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]);export{t};
@@ -0,0 +1 @@
1
+ import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{a as t,i as n,r}from"./bundle-mjs-C44PrJ2C.js";import{A as i,At as a,Ct as o,Et as s,Ft as c,Mt as l,Nt as u,Ot as d,Pt as f,St as p,Tt as m,_t as h,bt as g,gt as _,ht as v,jt as y,k as b,kt as x,mt as S,pt as C,vt as w,wt as ee,xt as T,yt as E}from"./index-DyIUhlc8.js";var D=e(n(),1),O=e(t(),1),k=r();function A(e){let t=e+`CollectionProvider`,[n,r]=y(t),[i,a]=n(t,{collectionRef:{current:null},itemMap:new Map}),o=e=>{let{scope:t,children:n}=e,r=O.useRef(null),a=O.useRef(new Map).current;return(0,k.jsx)(i,{scope:t,itemMap:a,collectionRef:r,children:n})};o.displayName=t;let s=e+`CollectionSlot`,l=f(s),u=O.forwardRef((e,t)=>{let{scope:n,children:r}=e;return(0,k.jsx)(l,{ref:c(t,a(s,n).collectionRef),children:r})});u.displayName=s;let d=e+`CollectionItemSlot`,p=`data-radix-collection-item`,m=f(d),h=O.forwardRef((e,t)=>{let{scope:n,children:r,...i}=e,o=O.useRef(null),s=c(t,o),l=a(d,n);return O.useEffect(()=>(l.itemMap.set(o,{ref:o,...i}),()=>void l.itemMap.delete(o))),(0,k.jsx)(m,{[p]:``,ref:s,children:r})});h.displayName=d;function g(t){let n=a(e+`CollectionConsumer`,t);return O.useCallback(()=>{let e=n.collectionRef.current;if(!e)return[];let t=Array.from(e.querySelectorAll(`[${p}]`));return Array.from(n.itemMap.values()).sort((e,n)=>t.indexOf(e.ref.current)-t.indexOf(n.ref.current))},[n.collectionRef,n.itemMap])}return[{Provider:o,Slot:u,ItemSlot:h},g,r]}var j=O.createContext(void 0);function M(e){let t=O.useContext(j);return e||t||`ltr`}function N(e){let t=O.useRef({value:e,previous:e});return O.useMemo(()=>(t.current.value!==e&&(t.current.previous=t.current.value,t.current.value=e),t.current.previous),[e])}function P(e,[t,n]){return Math.min(n,Math.max(t,e))}var F=[` `,`Enter`,`ArrowUp`,`ArrowDown`],I=[` `,`Enter`],L=`Select`,[R,z,B]=A(L),[V,H]=y(L,[B,w]),U=w(),[W,G]=V(L),[te,ne]=V(L),K=e=>{let{__scopeSelect:t,children:n,open:r,defaultOpen:i,onOpenChange:a,value:o,defaultValue:c,onValueChange:l,dir:u,name:f,autoComplete:p,disabled:m,required:g,form:_}=e,v=U(t),[y,b]=O.useState(null),[x,S]=O.useState(null),[C,w]=O.useState(!1),ee=M(u),[T,E]=d({prop:r,defaultProp:i??!1,onChange:a,caller:L}),[D,A]=d({prop:o,defaultProp:c,onChange:l,caller:L}),j=O.useRef(null),N=y?_||!!y.closest(`form`):!0,[P,F]=O.useState(new Set),I=Array.from(P).map(e=>e.props.value).join(`;`);return(0,k.jsx)(h,{...v,children:(0,k.jsxs)(W,{required:g,scope:t,trigger:y,onTriggerChange:b,valueNode:x,onValueNodeChange:S,valueNodeHasChildren:C,onValueNodeHasChildrenChange:w,contentId:s(),value:D,onValueChange:A,open:T,onOpenChange:E,dir:ee,triggerPointerDownPosRef:j,disabled:m,children:[(0,k.jsx)(R.Provider,{scope:t,children:(0,k.jsx)(te,{scope:e.__scopeSelect,onNativeOptionAdd:O.useCallback(e=>{F(t=>new Set(t).add(e))},[]),onNativeOptionRemove:O.useCallback(e=>{F(t=>{let n=new Set(t);return n.delete(e),n})},[]),children:n})}),N?(0,k.jsxs)(We,{"aria-hidden":!0,required:g,tabIndex:-1,name:f,autoComplete:p,value:D,onChange:e=>A(e.target.value),disabled:m,form:_,children:[D===void 0?(0,k.jsx)(`option`,{value:``}):null,Array.from(P)]},I):null]})})};K.displayName=L;var q=`SelectTrigger`,re=O.forwardRef((e,t)=>{let{__scopeSelect:n,disabled:r=!1,...i}=e,o=U(n),s=G(q,n),l=s.disabled||r,d=c(t,s.onTriggerChange),f=z(n),p=O.useRef(`touch`),[m,h,g]=Ke(e=>{let t=f().filter(e=>!e.disabled),n=qe(t,e,t.find(e=>e.value===s.value));n!==void 0&&s.onValueChange(n.value)}),_=e=>{l||(s.onOpenChange(!0),g()),e&&(s.triggerPointerDownPosRef.current={x:Math.round(e.pageX),y:Math.round(e.pageY)})};return(0,k.jsx)(S,{asChild:!0,...o,children:(0,k.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:l,"data-disabled":l?``:void 0,"data-placeholder":Ge(s.value)?``:void 0,...i,ref:d,onClick:a(i.onClick,e=>{e.currentTarget.focus(),p.current!==`mouse`&&_(e)}),onPointerDown:a(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:a(i.onKeyDown,e=>{let t=m.current!==``;!(e.ctrlKey||e.altKey||e.metaKey)&&e.key.length===1&&h(e.key),!(t&&e.key===` `)&&F.includes(e.key)&&(_(),e.preventDefault())})})})});re.displayName=q;var J=`SelectValue`,ie=O.forwardRef((e,t)=>{let{__scopeSelect:n,className:r,style:i,children:a,placeholder:o=``,...s}=e,l=G(J,n),{onValueNodeHasChildrenChange:d}=l,f=a!==void 0,p=c(t,l.onValueNodeChange);return x(()=>{d(f)},[d,f]),(0,k.jsx)(u.span,{...s,ref:p,style:{pointerEvents:`none`},children:Ge(l.value)?(0,k.jsx)(k.Fragment,{children:o}):a})});ie.displayName=J;var ae=`SelectIcon`,oe=O.forwardRef((e,t)=>{let{__scopeSelect:n,children:r,...i}=e;return(0,k.jsx)(u.span,{"aria-hidden":!0,...i,ref:t,children:r||`▼`})});oe.displayName=ae;var se=`SelectPortal`,ce=e=>(0,k.jsx)(p,{asChild:!0,...e});ce.displayName=se;var Y=`SelectContent`,le=O.forwardRef((e,t)=>{let n=G(Y,e.__scopeSelect),[r,i]=O.useState();if(x(()=>{i(new DocumentFragment)},[]),!n.open){let t=r;return t?D.createPortal((0,k.jsx)(ue,{scope:e.__scopeSelect,children:(0,k.jsx)(R.Slot,{scope:e.__scopeSelect,children:(0,k.jsx)(`div`,{children:e.children})})}),t):null}return(0,k.jsx)(pe,{...e,ref:t})});le.displayName=Y;var X=10,[ue,Z]=V(Y),de=`SelectContentImpl`,fe=f(`SelectContent.RemoveScroll`),pe=O.forwardRef((e,t)=>{let{__scopeSelect:n,position:r=`item-aligned`,onCloseAutoFocus:i,onEscapeKeyDown:s,onPointerDownOutside:l,side:u,sideOffset:d,align:f,alignOffset:p,arrowPadding:m,collisionBoundary:h,collisionPadding:_,sticky:v,hideWhenDetached:y,avoidCollisions:b,...x}=e,S=G(Y,n),[C,w]=O.useState(null),[D,A]=O.useState(null),j=c(t,e=>w(e)),[M,N]=O.useState(null),[P,F]=O.useState(null),I=z(n),[L,R]=O.useState(!1),B=O.useRef(!1);O.useEffect(()=>{if(C)return E(C)},[C]),T();let V=O.useCallback(e=>{let[t,...n]=I().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},[I,D]),H=O.useCallback(()=>V([M,C]),[V,M,C]);O.useEffect(()=>{L&&H()},[L,H]);let{onOpenChange:U,triggerPointerDownPosRef:W}=S;O.useEffect(()=>{if(C){let e={x:0,y:0},t=t=>{e={x:Math.abs(Math.round(t.pageX)-(W.current?.x??0)),y:Math.abs(Math.round(t.pageY)-(W.current?.y??0))}},n=n=>{e.x<=10&&e.y<=10?n.preventDefault():C.contains(n.target)||U(!1),document.removeEventListener(`pointermove`,t),W.current=null};return W.current!==null&&(document.addEventListener(`pointermove`,t),document.addEventListener(`pointerup`,n,{capture:!0,once:!0})),()=>{document.removeEventListener(`pointermove`,t),document.removeEventListener(`pointerup`,n,{capture:!0})}}},[C,U,W]),O.useEffect(()=>{let e=()=>U(!1);return window.addEventListener(`blur`,e),window.addEventListener(`resize`,e),()=>{window.removeEventListener(`blur`,e),window.removeEventListener(`resize`,e)}},[U]);let[te,ne]=Ke(e=>{let t=I().filter(e=>!e.disabled),n=qe(t,e,t.find(e=>e.ref.current===document.activeElement));n&&setTimeout(()=>n.ref.current.focus())}),K=O.useCallback((e,t,n)=>{let r=!B.current&&!n;(S.value!==void 0&&S.value===t||r)&&(N(e),r&&(B.current=!0))},[S.value]),q=O.useCallback(()=>C?.focus(),[C]),re=O.useCallback((e,t,n)=>{let r=!B.current&&!n;(S.value!==void 0&&S.value===t||r)&&F(e)},[S.value]),J=r===`popper`?_e:he,ie=J===_e?{side:u,sideOffset:d,align:f,alignOffset:p,arrowPadding:m,collisionBoundary:h,collisionPadding:_,sticky:v,hideWhenDetached:y,avoidCollisions:b}:{};return(0,k.jsx)(ue,{scope:n,content:C,viewport:D,onViewportChange:A,itemRefCallback:K,selectedItem:M,onItemLeave:q,itemTextRefCallback:re,focusSelectedItem:H,selectedItemText:P,position:r,isPositioned:L,searchRef:te,children:(0,k.jsx)(g,{as:fe,allowPinchZoom:!0,children:(0,k.jsx)(o,{asChild:!0,trapped:S.open,onMountAutoFocus:e=>{e.preventDefault()},onUnmountAutoFocus:a(i,e=>{S.trigger?.focus({preventScroll:!0}),e.preventDefault()}),children:(0,k.jsx)(ee,{asChild:!0,disableOutsidePointerEvents:!0,onEscapeKeyDown:s,onPointerDownOutside:l,onFocusOutside:e=>e.preventDefault(),onDismiss:()=>S.onOpenChange(!1),children:(0,k.jsx)(J,{role:`listbox`,id:S.contentId,"data-state":S.open?`open`:`closed`,dir:S.dir,onContextMenu:e=>e.preventDefault(),...x,...ie,onPlaced:()=>R(!0),ref:j,style:{display:`flex`,flexDirection:`column`,outline:`none`,...x.style},onKeyDown:a(x.onKeyDown,e=>{let t=e.ctrlKey||e.altKey||e.metaKey;if(e.key===`Tab`&&e.preventDefault(),!t&&e.key.length===1&&ne(e.key),[`ArrowUp`,`ArrowDown`,`Home`,`End`].includes(e.key)){let t=I().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(()=>V(t)),e.preventDefault()}})})})})})})});pe.displayName=de;var me=`SelectItemAlignedPosition`,he=O.forwardRef((e,t)=>{let{__scopeSelect:n,onPlaced:r,...i}=e,a=G(Y,n),o=Z(Y,n),[s,l]=O.useState(null),[d,f]=O.useState(null),p=c(t,e=>f(e)),m=z(n),h=O.useRef(!1),g=O.useRef(!0),{viewport:_,selectedItem:v,selectedItemText:y,focusSelectedItem:b}=o,S=O.useCallback(()=>{if(a.trigger&&a.valueNode&&s&&d&&_&&v&&y){let e=a.trigger.getBoundingClientRect(),t=d.getBoundingClientRect(),n=a.valueNode.getBoundingClientRect(),i=y.getBoundingClientRect();if(a.dir!==`rtl`){let r=i.left-t.left,a=n.left-r,o=e.left-a,c=e.width+o,l=Math.max(c,t.width),u=window.innerWidth-X,d=P(a,[X,Math.max(X,u-l)]);s.style.minWidth=c+`px`,s.style.left=d+`px`}else{let r=t.right-i.right,a=window.innerWidth-n.right-r,o=window.innerWidth-e.right-a,c=e.width+o,l=Math.max(c,t.width),u=window.innerWidth-X,d=P(a,[X,Math.max(X,u-l)]);s.style.minWidth=c+`px`,s.style.right=d+`px`}let o=m(),c=window.innerHeight-X*2,l=_.scrollHeight,u=window.getComputedStyle(d),f=parseInt(u.borderTopWidth,10),p=parseInt(u.paddingTop,10),g=parseInt(u.borderBottomWidth,10),b=parseInt(u.paddingBottom,10),x=f+p+l+b+g,S=Math.min(v.offsetHeight*5,x),C=window.getComputedStyle(_),w=parseInt(C.paddingTop,10),ee=parseInt(C.paddingBottom,10),T=e.top+e.height/2-X,E=c-T,D=v.offsetHeight/2,O=v.offsetTop+D,k=f+p+O,A=x-k;if(k<=T){let e=o.length>0&&v===o[o.length-1].ref.current;s.style.bottom=`0px`;let t=d.clientHeight-_.offsetTop-_.offsetHeight,n=k+Math.max(E,D+(e?ee:0)+t+g);s.style.height=n+`px`}else{let e=o.length>0&&v===o[0].ref.current;s.style.top=`0px`;let t=Math.max(T,f+_.offsetTop+(e?w:0)+D)+A;s.style.height=t+`px`,_.scrollTop=k-T+_.offsetTop}s.style.margin=`${X}px 0`,s.style.minHeight=S+`px`,s.style.maxHeight=c+`px`,r?.(),requestAnimationFrame(()=>h.current=!0)}},[m,a.trigger,a.valueNode,s,d,_,v,y,a.dir,r]);x(()=>S(),[S]);let[C,w]=O.useState();return x(()=>{d&&w(window.getComputedStyle(d).zIndex)},[d]),(0,k.jsx)(ve,{scope:n,contentWrapper:s,shouldExpandOnScrollRef:h,onScrollButtonChange:O.useCallback(e=>{e&&g.current===!0&&(S(),b?.(),g.current=!1)},[S,b]),children:(0,k.jsx)(`div`,{ref:l,style:{display:`flex`,flexDirection:`column`,position:`fixed`,zIndex:C},children:(0,k.jsx)(u.div,{...i,ref:p,style:{boxSizing:`border-box`,maxHeight:`100%`,...i.style}})})})});he.displayName=me;var ge=`SelectPopperPosition`,_e=O.forwardRef((e,t)=>{let{__scopeSelect:n,align:r=`start`,collisionPadding:i=X,...a}=e,o=U(n);return(0,k.jsx)(_,{...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)`}})});_e.displayName=ge;var[ve,ye]=V(Y,{}),be=`SelectViewport`,xe=O.forwardRef((e,t)=>{let{__scopeSelect:n,nonce:r,...i}=e,o=Z(be,n),s=ye(be,n),l=c(t,o.onViewportChange),d=O.useRef(0);return(0,k.jsxs)(k.Fragment,{children:[(0,k.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,k.jsx)(R.Slot,{scope:n,children:(0,k.jsx)(u.div,{"data-radix-select-viewport":``,role:`presentation`,...i,ref:l,style:{position:`relative`,flex:1,overflow:`hidden auto`,...i.style},onScroll:a(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-X*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})})})]})});xe.displayName=be;var Se=`SelectGroup`,[Ce,we]=V(Se),Te=O.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=s();return(0,k.jsx)(Ce,{scope:n,id:i,children:(0,k.jsx)(u.div,{role:`group`,"aria-labelledby":i,...r,ref:t})})});Te.displayName=Se;var Ee=`SelectLabel`,De=O.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=we(Ee,n);return(0,k.jsx)(u.div,{id:i.id,...r,ref:t})});De.displayName=Ee;var Q=`SelectItem`,[Oe,ke]=V(Q),Ae=O.forwardRef((e,t)=>{let{__scopeSelect:n,value:r,disabled:i=!1,textValue:o,...l}=e,d=G(Q,n),f=Z(Q,n),p=d.value===r,[m,h]=O.useState(o??``),[g,_]=O.useState(!1),v=c(t,e=>f.itemRefCallback?.(e,r,i)),y=s(),b=O.useRef(`touch`),x=()=>{i||(d.onValueChange(r),d.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,k.jsx)(Oe,{scope:n,value:r,disabled:i,textId:y,isSelected:p,onItemTextChange:O.useCallback(e=>{h(t=>t||(e?.textContent??``).trim())},[]),children:(0,k.jsx)(R.ItemSlot,{scope:n,value:r,disabled:i,textValue:m,children:(0,k.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,...l,ref:v,onFocus:a(l.onFocus,()=>_(!0)),onBlur:a(l.onBlur,()=>_(!1)),onClick:a(l.onClick,()=>{b.current!==`mouse`&&x()}),onPointerUp:a(l.onPointerUp,()=>{b.current===`mouse`&&x()}),onPointerDown:a(l.onPointerDown,e=>{b.current=e.pointerType}),onPointerMove:a(l.onPointerMove,e=>{b.current=e.pointerType,i?f.onItemLeave?.():b.current===`mouse`&&e.currentTarget.focus({preventScroll:!0})}),onPointerLeave:a(l.onPointerLeave,e=>{e.currentTarget===document.activeElement&&f.onItemLeave?.()}),onKeyDown:a(l.onKeyDown,e=>{f.searchRef?.current!==``&&e.key===` `||(I.includes(e.key)&&x(),e.key===` `&&e.preventDefault())})})})})});Ae.displayName=Q;var $=`SelectItemText`,je=O.forwardRef((e,t)=>{let{__scopeSelect:n,className:r,style:i,...a}=e,o=G($,n),s=Z($,n),l=ke($,n),d=ne($,n),[f,p]=O.useState(null),m=c(t,e=>p(e),l.onItemTextChange,e=>s.itemTextRefCallback?.(e,l.value,l.disabled)),h=f?.textContent,g=O.useMemo(()=>(0,k.jsx)(`option`,{value:l.value,disabled:l.disabled,children:h},l.value),[l.disabled,l.value,h]),{onNativeOptionAdd:_,onNativeOptionRemove:v}=d;return x(()=>(_(g),()=>v(g)),[_,v,g]),(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(u.span,{id:l.textId,...a,ref:m}),l.isSelected&&o.valueNode&&!o.valueNodeHasChildren?D.createPortal(a.children,o.valueNode):null]})});je.displayName=$;var Me=`SelectItemIndicator`,Ne=O.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e;return ke(Me,n).isSelected?(0,k.jsx)(u.span,{"aria-hidden":!0,...r,ref:t}):null});Ne.displayName=Me;var Pe=`SelectScrollUpButton`,Fe=O.forwardRef((e,t)=>{let n=Z(Pe,e.__scopeSelect),r=ye(Pe,e.__scopeSelect),[i,a]=O.useState(!1),o=c(t,r.onScrollButtonChange);return x(()=>{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,k.jsx)(Re,{...e,ref:o,onAutoScroll:()=>{let{viewport:e,selectedItem:t}=n;e&&t&&(e.scrollTop-=t.offsetHeight)}}):null});Fe.displayName=Pe;var Ie=`SelectScrollDownButton`,Le=O.forwardRef((e,t)=>{let n=Z(Ie,e.__scopeSelect),r=ye(Ie,e.__scopeSelect),[i,a]=O.useState(!1),o=c(t,r.onScrollButtonChange);return x(()=>{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,k.jsx)(Re,{...e,ref:o,onAutoScroll:()=>{let{viewport:e,selectedItem:t}=n;e&&t&&(e.scrollTop+=t.offsetHeight)}}):null});Le.displayName=Ie;var Re=O.forwardRef((e,t)=>{let{__scopeSelect:n,onAutoScroll:r,...i}=e,o=Z(`SelectScrollButton`,n),s=O.useRef(null),c=z(n),l=O.useCallback(()=>{s.current!==null&&(window.clearInterval(s.current),s.current=null)},[]);return O.useEffect(()=>()=>l(),[l]),x(()=>{c().find(e=>e.ref.current===document.activeElement)?.ref.current?.scrollIntoView({block:`nearest`})},[c]),(0,k.jsx)(u.div,{"aria-hidden":!0,...i,ref:t,style:{flexShrink:0,...i.style},onPointerDown:a(i.onPointerDown,()=>{s.current===null&&(s.current=window.setInterval(r,50))}),onPointerMove:a(i.onPointerMove,()=>{o.onItemLeave?.(),s.current===null&&(s.current=window.setInterval(r,50))}),onPointerLeave:a(i.onPointerLeave,()=>{l()})})}),ze=`SelectSeparator`,Be=O.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e;return(0,k.jsx)(u.div,{"aria-hidden":!0,...r,ref:t})});Be.displayName=ze;var Ve=`SelectArrow`,He=O.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=U(n),a=G(Ve,n),o=Z(Ve,n);return a.open&&o.position===`popper`?(0,k.jsx)(v,{...i,...r,ref:t}):null});He.displayName=Ve;var Ue=`SelectBubbleInput`,We=O.forwardRef(({__scopeSelect:e,value:t,...n},r)=>{let i=O.useRef(null),a=c(r,i),o=N(t);return O.useEffect(()=>{let e=i.current;if(!e)return;let n=window.HTMLSelectElement.prototype,r=Object.getOwnPropertyDescriptor(n,`value`).set;if(o!==t&&r){let n=new Event(`change`,{bubbles:!0});r.call(e,t),e.dispatchEvent(n)}},[o,t]),(0,k.jsx)(u.select,{...n,style:{...l,...n.style},ref:a,defaultValue:t})});We.displayName=Ue;function Ge(e){return e===``||e===void 0}function Ke(e){let t=m(e),n=O.useRef(``),r=O.useRef(0),i=O.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=O.useCallback(()=>{n.current=``,window.clearTimeout(r.current)},[]);return O.useEffect(()=>()=>window.clearTimeout(r.current),[]),[n,i,a]}function qe(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=Je(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 Je(e,t){return e.map((n,r)=>e[(t+r)%e.length])}var Ye=K,Xe=re,Ze=ie,Qe=oe,$e=ce,et=le,tt=xe,nt=Ae,rt=je,it=Ne,at=Fe,ot=Le;function st({...e}){return(0,k.jsx)(Ye,{"data-slot":`select`,...e})}function ct({...e}){return(0,k.jsx)(Ze,{"data-slot":`select-value`,...e})}function lt({className:e,size:t,children:n,...r}){return(0,k.jsxs)(Xe,{"data-slot":`select-trigger`,"data-size":t,className:C(`flex w-fit items-center justify-between gap-2 rounded-md border border-(--border-default) bg-[color-mix(in_srgb,var(--bg-input)_88%,var(--text-muted)_12%)] px-3 py-1 text-[13px] text-(--text-primary) whitespace-nowrap transition-colors outline-none hover:bg-[color-mix(in_srgb,var(--bg-input)_76%,var(--text-muted)_24%)] focus-visible:border-(--text-secondary) focus-visible:bg-(--bg-input) focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-(--text-muted) 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 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-(--text-muted)`,e),...r,children:[n,(0,k.jsx)(Qe,{asChild:!0,children:(0,k.jsx)(b,{className:`size-3.5 opacity-50`})})]})}function ut({className:e,children:t,position:n=`item-aligned`,align:r=`center`,...i}){return(0,k.jsx)($e,{children:(0,k.jsxs)(et,{"data-slot":`select-content`,className:C(`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-lg border border-(--border-default) bg-(--bg-primary) text-(--text-primary) 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,k.jsx)(ft,{}),(0,k.jsx)(tt,{className:C(`p-1`,n===`popper`&&`h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]`),children:t}),(0,k.jsx)(pt,{})]})})}function dt({className:e,children:t,...n}){return(0,k.jsxs)(nt,{"data-slot":`select-item`,className:C(`relative flex w-full cursor-pointer items-center gap-2 rounded-md py-1.5 pr-8 pl-2 text-[13px] outline-hidden select-none hover:bg-(--bg-hover) 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-(--text-muted) *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2`,e),...n,children:[(0,k.jsx)(`span`,{"data-slot":`select-item-indicator`,className:`absolute right-2 flex size-3.5 items-center justify-center`,children:(0,k.jsx)(it,{children:(0,k.jsx)(i,{className:`size-4`})})}),(0,k.jsx)(rt,{children:t})]})}function ft({className:e,...t}){return(0,k.jsx)(at,{"data-slot":`select-scroll-up-button`,className:C(`flex cursor-default items-center justify-center py-1`,e),...t,children:(0,k.jsx)(b,{className:`size-4 rotate-180`})})}function pt({className:e,...t}){return(0,k.jsx)(ot,{"data-slot":`select-scroll-down-button`,className:C(`flex cursor-default items-center justify-center py-1`,e),...t,children:(0,k.jsx)(b,{className:`size-4`})})}export{ct as a,lt as i,ut as n,P as o,dt as r,M as s,st as t};
@@ -1 +1 @@
1
- import{P as e}from"./index-CDXQGwPs.js";var t=e(`search`,[[`path`,{d:`m21 21-4.34-4.34`,key:`14j7rj`}],[`circle`,{cx:`11`,cy:`11`,r:`8`,key:`4ej97u`}]]),n=e(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]);export{t as n,n as t};
1
+ import{P as e}from"./index-DyIUhlc8.js";var t=e(`search`,[[`path`,{d:`m21 21-4.34-4.34`,key:`14j7rj`}],[`circle`,{cx:`11`,cy:`11`,r:`8`,key:`4ej97u`}]]),n=e(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]);export{t as n,n as t};
@@ -26,10 +26,10 @@
26
26
  }
27
27
  })();
28
28
  </script>
29
- <script type="module" crossorigin src="/assets/index-CDXQGwPs.js"></script>
29
+ <script type="module" crossorigin src="/assets/index-DyIUhlc8.js"></script>
30
30
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-S-ySWqyJ.js">
31
31
  <link rel="modulepreload" crossorigin href="/assets/bundle-mjs-C44PrJ2C.js">
32
- <link rel="stylesheet" crossorigin href="/assets/index-1xqD0R5t.css">
32
+ <link rel="stylesheet" crossorigin href="/assets/index-DF9s7Tuc.css">
33
33
  </head>
34
34
  <body class="font-sans antialiased">
35
35
  <div id="root"></div>
@@ -746,6 +746,13 @@ export class RuntimeBridge {
746
746
  return result || { error: true, message: 'Git change oplog is not available' };
747
747
  }
748
748
 
749
+ async undoChangeSets(ids) {
750
+ if (this.#busy) return { error: true, message: 'A request is already in progress' };
751
+ const result = await this.#runtime.undoChangeSets?.(ids);
752
+ this.#broadcast({ type: 'change:undone', result });
753
+ return result || { error: true, message: 'Git change oplog is not available' };
754
+ }
755
+
749
756
  async getUiMessages() {
750
757
  this.#resetUiTranscriptIfSessionChanged();
751
758
  if (this.#uiMessages.length > 0) return this.#uiMessages;
@@ -1165,7 +1165,7 @@ async function main() {
1165
1165
  }
1166
1166
  return;
1167
1167
  }
1168
- if (req.method === 'POST' && url.pathname.startsWith('/api/session-changes/') && url.pathname.endsWith('/undo')) {
1168
+ if (req.method === 'POST' && url.pathname !== '/api/session-changes/undo' && url.pathname.startsWith('/api/session-changes/') && url.pathname.endsWith('/undo')) {
1169
1169
  const id = decodeURIComponent(url.pathname.slice('/api/session-changes/'.length, -'/undo'.length));
1170
1170
  try {
1171
1171
  jsonResponse(res, await bridge.undoChangeSet(id));
@@ -1174,6 +1174,15 @@ async function main() {
1174
1174
  }
1175
1175
  return;
1176
1176
  }
1177
+ if (req.method === 'POST' && url.pathname === '/api/session-changes/undo') {
1178
+ const { ids } = await readBody(req);
1179
+ try {
1180
+ jsonResponse(res, await bridge.undoChangeSets(ids));
1181
+ } catch (err) {
1182
+ jsonResponse(res, { error: true, message: err?.message || 'Failed to undo changes' }, 409);
1183
+ }
1184
+ return;
1185
+ }
1177
1186
  if (req.method === 'POST' && url.pathname === '/api/git-batch') {
1178
1187
  const { dirs } = await readBody(req);
1179
1188
  const result = {};
@@ -1341,18 +1350,21 @@ async function main() {
1341
1350
  jsonResponse(res, { name: skill.name, content, scope: skill.scope });
1342
1351
  } catch (err) { jsonResponse(res, { error: true, message: err.message }, 500); }
1343
1352
  return;
1344
- }
1345
- if (req.method === 'POST' && url.pathname === '/api/skills/create') {
1346
- const { name, description, content, scope: rawScope } = await readBody(req);
1347
- if (!name || !content) { jsonResponse(res, { error: true, message: 'Missing name or content' }, 400); return; }
1348
- if (!isSafeSkillName(name)) { jsonResponse(res, { error: true, message: 'Invalid skill name' }, 400); return; }
1349
- try {
1350
- const scope = normalizeSkillScope(rawScope);
1351
- const skillBaseDir = skillBaseDirForScope(scope, currentProjectDir);
1352
- const skillDir = path.join(skillBaseDir, name);
1353
- await fs.mkdir(skillDir, { recursive: true });
1354
- const skillFile = path.join(skillDir, 'SKILL.md');
1355
- await fs.writeFile(skillFile, content, 'utf8');
1353
+ }
1354
+ if (req.method === 'POST' && url.pathname === '/api/skills/create') {
1355
+ const { name, description, content, scope: rawScope, projectDir } = await readBody(req);
1356
+ if (!name || !content) { jsonResponse(res, { error: true, message: 'Missing name or content' }, 400); return; }
1357
+ if (!isSafeSkillName(name)) { jsonResponse(res, { error: true, message: 'Invalid skill name' }, 400); return; }
1358
+ try {
1359
+ const scope = normalizeSkillScope(rawScope);
1360
+ const targetProjectDir = scope === 'project'
1361
+ ? await resolveRequestProjectDir(projectDir, currentProjectDir)
1362
+ : currentProjectDir;
1363
+ const skillBaseDir = skillBaseDirForScope(scope, targetProjectDir);
1364
+ const skillDir = path.join(skillBaseDir, name);
1365
+ await fs.mkdir(skillDir, { recursive: true });
1366
+ const skillFile = path.join(skillDir, 'SKILL.md');
1367
+ await fs.writeFile(skillFile, content, 'utf8');
1356
1368
  if (scope === 'global') {
1357
1369
  await upsertSkillRegistryEntry(undefined, {
1358
1370
  name,
@@ -1362,38 +1374,41 @@ async function main() {
1362
1374
  source: 'web-create',
1363
1375
  entryFile: 'SKILL.md',
1364
1376
  sha256: await computeFileSha256(skillFile),
1365
- installedAt: new Date().toISOString()
1366
- });
1367
- } else {
1368
- await upsertProjectSkillMetadata(currentProjectDir, name, {
1369
- description: description || '',
1370
- mode: 'agent_requested',
1371
- triggers: [],
1372
- enabled: true,
1377
+ installedAt: new Date().toISOString()
1378
+ });
1379
+ } else {
1380
+ await upsertProjectSkillMetadata(targetProjectDir, name, {
1381
+ description: description || '',
1382
+ mode: 'agent_requested',
1383
+ triggers: [],
1384
+ enabled: true,
1373
1385
  priority: 50
1374
1386
  });
1375
1387
  }
1376
1388
  const config = await loadConfig();
1377
1389
  config.skills = config.skills || {};
1378
1390
  config.skills.enabled = config.skills.enabled || {};
1379
- config.skills.enabled[name] = true;
1380
- await saveConfig(config);
1381
- await bridge.reloadCommandsAndSkills();
1382
- jsonResponse(res, { ok: true, name, scope });
1383
- } catch (err) { jsonResponse(res, { error: true, message: err.message }, 500); }
1384
- return;
1385
- }
1386
- if (req.method === 'POST' && url.pathname === '/api/skills/install') {
1387
- const { source, scope: rawScope } = await readBody(req);
1388
- if (!source) { jsonResponse(res, { error: true, message: 'Missing source' }, 400); return; }
1389
- try {
1390
- const scope = normalizeSkillScope(rawScope);
1391
- const installed = await installSkillSource(source, { scope, cwd: currentProjectDir });
1392
- await bridge.reloadCommandsAndSkills();
1393
- jsonResponse(res, { ok: true, installed, scope });
1394
- } catch (err) { jsonResponse(res, { error: true, message: err.message }, 500); }
1395
- return;
1396
- }
1391
+ config.skills.enabled[name] = true;
1392
+ await saveConfig(config);
1393
+ await bridge.reloadCommandsAndSkills();
1394
+ jsonResponse(res, { ok: true, name, scope, projectDir: scope === 'project' ? targetProjectDir : '' });
1395
+ } catch (err) { jsonResponse(res, { error: true, message: err.message }, 500); }
1396
+ return;
1397
+ }
1398
+ if (req.method === 'POST' && url.pathname === '/api/skills/install') {
1399
+ const { source, scope: rawScope, projectDir } = await readBody(req);
1400
+ if (!source) { jsonResponse(res, { error: true, message: 'Missing source' }, 400); return; }
1401
+ try {
1402
+ const scope = normalizeSkillScope(rawScope);
1403
+ const targetProjectDir = scope === 'project'
1404
+ ? await resolveRequestProjectDir(projectDir, currentProjectDir)
1405
+ : currentProjectDir;
1406
+ const installed = await installSkillSource(source, { scope, cwd: targetProjectDir });
1407
+ await bridge.reloadCommandsAndSkills();
1408
+ jsonResponse(res, { ok: true, installed, scope, projectDir: scope === 'project' ? targetProjectDir : '' });
1409
+ } catch (err) { jsonResponse(res, { error: true, message: err.message }, 500); }
1410
+ return;
1411
+ }
1397
1412
  if (req.method === 'PUT' && url.pathname.startsWith('/api/skills/') && url.pathname.endsWith('/content')) {
1398
1413
  const name = decodeURIComponent(url.pathname.slice('/api/skills/'.length, -'/content'.length));
1399
1414
  const { content, projectDir } = await readBody(req);
@@ -1439,27 +1454,34 @@ async function main() {
1439
1454
  }
1440
1455
  if (req.method === 'PUT' && url.pathname.startsWith('/api/skills/') && url.pathname.endsWith('/metadata')) {
1441
1456
  const name = decodeURIComponent(url.pathname.slice('/api/skills/'.length, -'/metadata'.length));
1442
- const body = await readBody(req);
1443
- try {
1444
- const targetProjectDir = await resolveRequestProjectDir(body?.projectDir, currentProjectDir);
1445
- const entries = await listSkillEntries({ scope: 'all', cwd: targetProjectDir });
1446
- const skill = entries.find(s => s.name === name);
1447
- if (!skill) { jsonResponse(res, { error: true, message: 'Skill not found' }, 404); return; }
1457
+ const body = await readBody(req);
1458
+ try {
1459
+ const targetProjectDir = await resolveRequestProjectDir(body?.projectDir, currentProjectDir);
1460
+ const requestedProjectDir = body?.targetProjectDir
1461
+ ? await resolveRequestProjectDir(body.targetProjectDir, currentProjectDir)
1462
+ : targetProjectDir;
1463
+ const entries = await listSkillEntries({ scope: 'all', cwd: targetProjectDir });
1464
+ const skill = entries.find(s => s.name === name);
1465
+ if (!skill) { jsonResponse(res, { error: true, message: 'Skill not found' }, 404); return; }
1448
1466
  if (skill.scope === 'builtin' && body?.scope && body.scope !== 'builtin') {
1449
1467
  jsonResponse(res, { error: true, message: 'Cannot move builtin skill' }, 403);
1450
1468
  return;
1451
1469
  }
1452
1470
  const metadataPatch = normalizeSkillMetadataPatch(body || {});
1453
- let metadata = metadataPatch;
1454
- const requestedScope = body?.scope ? normalizeSkillScope(body.scope) : skill.scope;
1455
- let nextScope = skill.scope;
1456
-
1457
- if (skill.scope !== 'builtin' && requestedScope !== skill.scope) {
1458
- const sourceDir = path.dirname(skill.path);
1459
- const targetBaseDir = skillBaseDirForScope(requestedScope, targetProjectDir);
1460
- const targetDir = path.join(targetBaseDir, name);
1461
- await fs.rm(targetDir, { recursive: true, force: true });
1462
- await fs.mkdir(path.dirname(targetDir), { recursive: true });
1471
+ let metadata = metadataPatch;
1472
+ const requestedScope = body?.scope ? normalizeSkillScope(body.scope) : skill.scope;
1473
+ let nextScope = skill.scope;
1474
+ let nextProjectDir = targetProjectDir;
1475
+
1476
+ if (
1477
+ skill.scope !== 'builtin' &&
1478
+ (requestedScope !== skill.scope || (requestedScope === 'project' && requestedProjectDir !== targetProjectDir))
1479
+ ) {
1480
+ const sourceDir = path.dirname(skill.path);
1481
+ const targetBaseDir = skillBaseDirForScope(requestedScope, requestedProjectDir);
1482
+ const targetDir = path.join(targetBaseDir, name);
1483
+ await fs.rm(targetDir, { recursive: true, force: true });
1484
+ await fs.mkdir(path.dirname(targetDir), { recursive: true });
1463
1485
  await fs.cp(sourceDir, targetDir, { recursive: true, force: true });
1464
1486
  await fs.rm(sourceDir, { recursive: true, force: true });
1465
1487
  if (requestedScope === 'global') {
@@ -1472,29 +1494,33 @@ async function main() {
1472
1494
  source: 'web-move',
1473
1495
  entryFile: 'SKILL.md',
1474
1496
  sha256: await computeFileSha256(path.join(targetDir, 'SKILL.md')),
1475
- installedAt: new Date().toISOString()
1476
- });
1477
- } else {
1478
- const registry = await readSkillRegistry();
1479
- registry.skills = (registry.skills || []).filter(s => s.name !== name);
1480
- await writeSkillRegistry(undefined, registry);
1481
- await deleteSkillCatalogMetadata(getSkillsDir(), name);
1482
- }
1483
- nextScope = requestedScope;
1484
- }
1485
-
1486
- if (nextScope === 'global') {
1497
+ installedAt: new Date().toISOString()
1498
+ });
1499
+ } else {
1500
+ const registry = await readSkillRegistry();
1501
+ registry.skills = (registry.skills || []).filter(s => s.name !== name);
1502
+ await writeSkillRegistry(undefined, registry);
1503
+ await deleteSkillCatalogMetadata(getSkillsDir(), name);
1504
+ if (requestedProjectDir !== targetProjectDir) {
1505
+ await deleteSkillCatalogMetadata(getProjectSkillsDir(targetProjectDir), name);
1506
+ }
1507
+ }
1508
+ nextScope = requestedScope;
1509
+ nextProjectDir = requestedScope === 'project' ? requestedProjectDir : targetProjectDir;
1510
+ }
1511
+
1512
+ if (nextScope === 'global') {
1487
1513
  await upsertSkillRegistryEntry(undefined, {
1488
1514
  name,
1489
1515
  ...(metadataPatch.description !== undefined ? { description: metadataPatch.description } : {}),
1490
1516
  ...(metadataPatch.enabled !== undefined ? { enabled: metadataPatch.enabled } : {})
1491
- });
1492
- metadata = await upsertSkillCatalogMetadata(getSkillsDir(), name, body || {});
1493
- } else if (nextScope === 'project') {
1494
- metadata = await upsertProjectSkillMetadata(targetProjectDir, name, body || {});
1495
- } else if (skill.scope !== 'builtin') {
1496
- metadata = await upsertProjectSkillMetadata(targetProjectDir, name, body || {});
1497
- } else {
1517
+ });
1518
+ metadata = await upsertSkillCatalogMetadata(getSkillsDir(), name, body || {});
1519
+ } else if (nextScope === 'project') {
1520
+ metadata = await upsertProjectSkillMetadata(nextProjectDir, name, body || {});
1521
+ } else if (skill.scope !== 'builtin') {
1522
+ metadata = await upsertProjectSkillMetadata(targetProjectDir, name, body || {});
1523
+ } else {
1498
1524
  metadata = await upsertProjectSkillMetadata(targetProjectDir, name, body || {});
1499
1525
  }
1500
1526
  if (skill.scope !== 'builtin' && body?.enabled !== undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codemini-cli",
3
- "version": "0.6.4",
3
+ "version": "0.6.6",
4
4
  "description": "An extremely restrained coding + tasks CLI. Every platform. Every terminal. Minimal by design.",
5
5
  "keywords": [
6
6
  "cli",
@@ -6,13 +6,15 @@ import { copyRecursive } from '../core/fs-utils.js';
6
6
  import { loadConfig, saveConfig } from '../core/config-store.js';
7
7
  import { loadCommandsAndSkills } from '../core/command-loader.js';
8
8
  import { getProjectSkillsDir, getSkillsDir } from '../core/paths.js';
9
- import {
10
- computeFileSha256,
11
- readSkillRegistry,
12
- upsertSkillRegistryEntry,
13
- writeSkillRegistry
14
- } from '../core/skill-registry.js';
15
-
9
+ import {
10
+ computeFileSha256,
11
+ readSkillRegistry,
12
+ upsertSkillRegistryEntry,
13
+ writeSkillRegistry
14
+ } from '../core/skill-registry.js';
15
+
16
+ const SKILL_CATALOG_FILE = 'codemini.skills.json';
17
+
16
18
  function parseScopeArgs(args = [], { defaultScope = 'project', allowAll = false } = {}) {
17
19
  let scope = defaultScope;
18
20
  const rest = [];
@@ -195,16 +197,132 @@ async function runTarExtract(tgzPath, destDir) {
195
197
  });
196
198
  }
197
199
 
198
- async function readManifestSafe(skillRoot) {
199
- const p = path.join(skillRoot, 'manifest.json');
200
- try {
201
- const raw = await fs.readFile(p, 'utf8');
202
- return JSON.parse(raw);
200
+ async function readManifestSafe(skillRoot) {
201
+ const p = path.join(skillRoot, 'manifest.json');
202
+ try {
203
+ const raw = await fs.readFile(p, 'utf8');
204
+ return JSON.parse(raw);
203
205
  } catch {
204
206
  return null;
205
- }
206
- }
207
-
207
+ }
208
+ }
209
+
210
+ function parseArrayText(value) {
211
+ const inner = value.slice(1, -1).trim();
212
+ if (!inner) return [];
213
+ return inner.split(',').map((item) => item.trim().replace(/^["']|["']$/g, ''));
214
+ }
215
+
216
+ function parseSkillFrontmatter(raw) {
217
+ const normalized = String(raw || '').replace(/\r\n/g, '\n');
218
+ if (!normalized.startsWith('---\n')) {
219
+ return { metadata: {}, content: normalized };
220
+ }
221
+ const end = normalized.indexOf('\n---\n', 4);
222
+ if (end === -1) {
223
+ return { metadata: {}, content: normalized };
224
+ }
225
+
226
+ const metadata = {};
227
+ const metaRaw = normalized.slice(4, end).trim();
228
+ for (const line of metaRaw.split('\n')) {
229
+ const idx = line.indexOf(':');
230
+ if (idx <= 0) continue;
231
+ const key = line.slice(0, idx).trim();
232
+ const value = line.slice(idx + 1).trim();
233
+ metadata[key] = value.startsWith('[') && value.endsWith(']')
234
+ ? parseArrayText(value)
235
+ : value.replace(/^["']|["']$/g, '');
236
+ }
237
+
238
+ return {
239
+ metadata,
240
+ content: normalized.slice(end + 5).trim()
241
+ };
242
+ }
243
+
244
+ function cleanDescriptionText(value) {
245
+ return String(value || '')
246
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
247
+ .replace(/[`*_~]/g, '')
248
+ .replace(/\s+/g, ' ')
249
+ .trim()
250
+ .slice(0, 240);
251
+ }
252
+
253
+ function inferDescriptionFromSkillMarkdown(content) {
254
+ const lines = String(content || '').replace(/\r\n/g, '\n').split('\n');
255
+ let inFence = false;
256
+ const paragraph = [];
257
+
258
+ for (const rawLine of lines) {
259
+ const trimmed = rawLine.trim();
260
+ if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) {
261
+ inFence = !inFence;
262
+ continue;
263
+ }
264
+ if (inFence) continue;
265
+
266
+ if (!trimmed) {
267
+ if (paragraph.length > 0) break;
268
+ continue;
269
+ }
270
+ if (/^#{1,6}\s+/.test(trimmed)) continue;
271
+ if (/^<!--/.test(trimmed)) continue;
272
+ if (/^[-*_]{3,}$/.test(trimmed)) continue;
273
+
274
+ const withoutListMarker = trimmed.replace(/^([-*+]|\d+[.)])\s+/, '');
275
+ if (/^(name|version|author|license|entry)\s*:/i.test(withoutListMarker)) continue;
276
+ paragraph.push(withoutListMarker);
277
+ }
278
+
279
+ return cleanDescriptionText(paragraph.join(' '));
280
+ }
281
+
282
+ async function readSkillDocumentMeta(skillRoot, entryFile = 'SKILL.md') {
283
+ const entryPath = path.join(skillRoot, entryFile || 'SKILL.md');
284
+ try {
285
+ const raw = await fs.readFile(entryPath, 'utf8');
286
+ const parsed = parseSkillFrontmatter(raw);
287
+ return {
288
+ version: parsed.metadata.version ? String(parsed.metadata.version) : '',
289
+ description: parsed.metadata.description
290
+ ? cleanDescriptionText(parsed.metadata.description)
291
+ : inferDescriptionFromSkillMarkdown(parsed.content)
292
+ };
293
+ } catch {
294
+ return { version: '', description: '' };
295
+ }
296
+ }
297
+
298
+ async function readSkillCatalogSafe(baseDir) {
299
+ const catalogPath = path.join(baseDir, SKILL_CATALOG_FILE);
300
+ try {
301
+ const parsed = JSON.parse(await fs.readFile(catalogPath, 'utf8'));
302
+ return parsed && typeof parsed === 'object' && parsed.skills && typeof parsed.skills === 'object'
303
+ ? parsed
304
+ : { version: 1, skills: {} };
305
+ } catch {
306
+ return { version: 1, skills: {} };
307
+ }
308
+ }
309
+
310
+ async function writeSkillCatalog(baseDir, catalog) {
311
+ await fs.mkdir(baseDir, { recursive: true });
312
+ await fs.writeFile(path.join(baseDir, SKILL_CATALOG_FILE), `${JSON.stringify(catalog, null, 2)}\n`, 'utf8');
313
+ }
314
+
315
+ async function upsertSkillCatalogEntry(baseDir, name, entry) {
316
+ const catalog = await readSkillCatalogSafe(baseDir);
317
+ catalog.version = catalog.version || 1;
318
+ catalog.skills = catalog.skills || {};
319
+ catalog.skills[name] = {
320
+ ...(catalog.skills[name] || {}),
321
+ ...entry
322
+ };
323
+ await writeSkillCatalog(baseDir, catalog);
324
+ }
325
+
208
326
  async function resolveSkillSourceDir(sourcePath) {
209
327
  const absSrc = path.resolve(sourcePath);
210
328
  const srcStat = await fs.stat(absSrc);
@@ -277,22 +395,30 @@ export async function installSkill(sourcePath, { scope = 'project', cwd = proces
277
395
 
278
396
  const entryFile = manifest?.entry || 'SKILL.md';
279
397
  const entryPath = path.join(targetDir, entryFile);
280
- await fs.access(entryPath);
281
-
282
- const hash = await computeFileSha256(entryPath);
283
- if (scope === 'global') {
284
- await upsertSkillRegistryEntry(undefined, {
398
+ await fs.access(entryPath);
399
+
400
+ const hash = await computeFileSha256(entryPath);
401
+ const documentMeta = await readSkillDocumentMeta(targetDir, entryFile);
402
+ const description = manifest?.description || documentMeta.description || '';
403
+ const version = manifest?.version || documentMeta.version || '0.0.0';
404
+ if (scope === 'global') {
405
+ await upsertSkillRegistryEntry(undefined, {
285
406
  name: folderName,
286
- version: manifest?.version || '0.0.0',
287
- description: manifest?.description || '',
407
+ version,
408
+ description,
288
409
  enabled: true,
289
410
  source: sourceLabel,
290
411
  entryFile,
291
412
  sha256: hash,
292
413
  installedAt: new Date().toISOString()
293
- });
294
- }
295
- await setSkillEnabledConfig(folderName, true);
414
+ });
415
+ } else {
416
+ await upsertSkillCatalogEntry(baseDirForScope(scope, cwd), folderName, {
417
+ description,
418
+ enabled: true
419
+ });
420
+ }
421
+ await setSkillEnabledConfig(folderName, true);
296
422
 
297
423
  if (resolved.cleanupDir) {
298
424
  await fs.rm(resolved.cleanupDir, { recursive: true, force: true });
@@ -387,37 +513,51 @@ async function reindexSkills({ scope = 'global', cwd = process.cwd() } = {}) {
387
513
  if (!entry.isDirectory()) continue;
388
514
  const name = entry.name;
389
515
  const dir = path.join(baseDir, name);
390
- const manifest = await readManifestSafe(dir);
391
- const entryFile = manifest?.entry || 'SKILL.md';
392
- const entryPath = path.join(dir, entryFile);
393
- try {
394
- await fs.access(entryPath);
516
+ const manifest = await readManifestSafe(dir);
517
+ const entryFile = manifest?.entry || 'SKILL.md';
518
+ const entryPath = path.join(dir, entryFile);
519
+ try {
520
+ await fs.access(entryPath);
395
521
  } catch {
396
522
  continue;
397
- }
398
- const hash = await computeFileSha256(entryPath);
399
- const prior = byName.get(name);
400
- rebuilt.push({
401
- name: manifest?.name || name,
402
- version: manifest?.version || prior?.version || '0.0.0',
403
- description: manifest?.description || prior?.description || '',
404
- enabled: prior?.enabled !== false,
405
- source: prior?.source || 'reindex',
406
- entryFile,
407
- sha256: hash,
408
- installedAt: prior?.installedAt || new Date().toISOString()
523
+ }
524
+ const hash = await computeFileSha256(entryPath);
525
+ const prior = byName.get(name);
526
+ const documentMeta = await readSkillDocumentMeta(dir, entryFile);
527
+ rebuilt.push({
528
+ name: manifest?.name || name,
529
+ version: manifest?.version || documentMeta.version || prior?.version || '0.0.0',
530
+ description: manifest?.description || documentMeta.description || prior?.description || '',
531
+ enabled: prior?.enabled !== false,
532
+ source: prior?.source || 'reindex',
533
+ entryFile,
534
+ sha256: hash,
535
+ installedAt: prior?.installedAt || new Date().toISOString()
409
536
  });
410
537
  }
411
538
 
412
539
  if (scope === 'global') {
413
540
  await writeSkillRegistry(undefined, {
414
541
  version: 1,
415
- skills: rebuilt
416
- });
417
- }
418
-
419
- return rebuilt.length;
420
- }
542
+ skills: rebuilt
543
+ });
544
+ } else if (scope === 'project') {
545
+ const catalog = await readSkillCatalogSafe(baseDir);
546
+ catalog.version = catalog.version || 1;
547
+ catalog.skills = catalog.skills || {};
548
+ for (const item of rebuilt) {
549
+ catalog.skills[item.name] = {
550
+ ...(catalog.skills[item.name] || {}),
551
+ description: item.description,
552
+ enabled: item.enabled !== false,
553
+ triggers: Array.isArray(catalog.skills[item.name]?.triggers) ? catalog.skills[item.name].triggers : []
554
+ };
555
+ }
556
+ await writeSkillCatalog(baseDir, catalog);
557
+ }
558
+
559
+ return rebuilt.length;
560
+ }
421
561
 
422
562
  function usage() {
423
563
  console.log(`Usage: