@arcteninc/core 0.0.27 → 0.0.30

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/index.cjs CHANGED
@@ -14,12 +14,32 @@ Please:
14
14
  import { toolMetadata } from './.arcten/tool-metadata';
15
15
  3. Pass it to useAgent/ArctenAgent:
16
16
  useAgent({ tools: [...], toolMetadata: toolMetadata.functions })
17
- `);return t.map(n=>{const s=n.name||"unnamed";if(!e[s])throw new Error(`❌ No metadata found for tool "${s}".
17
+ `);return t.map(n=>{const s=n.name||"unnamed";if(!e[s]){const i=n.length>0,r=i?`function ${s}(param1: string, param2?: number) { ... }`:`function ${s}() { ... }`,o=i?`function ${s}(param1, param2) { ... }`:`function ${s}() { ... }`;throw new Error(`❌ No metadata found for tool "${s}".
18
18
 
19
- Make sure:
20
- 1. The tool is exported from your tools file
21
- 2. You've run "arcten-extract-types ." recently
22
- 3. The tool is used in an ArctenAgent or useAgent component`);return{name:s,description:e[s].description,jsonSchema:e[s].parameters}})}function hh({toolName:t,description:e,args:n,onApprove:s,onDeny:i}){const r=Object.keys(n).length>0;return h.jsx("div",{className:"bg-stone-100 dark:bg-stone-800 border border-border rounded-lg px-3 py-2.5 my-1.5",children:h.jsxs("div",{className:"flex items-start gap-2",children:[h.jsxs("div",{className:"flex-1 min-w-0",children:[h.jsx("div",{className:"flex items-center gap-1.5 mb-1",children:h.jsx("span",{className:"text-sm font-medium text-foreground",children:t})}),r&&h.jsx("div",{className:"space-y-0.5 mb-1.5",children:Object.entries(n).map(([o,a])=>h.jsxs("div",{className:"flex items-start gap-1.5 text-xs",children:[h.jsxs("span",{className:"text-muted-foreground min-w-[60px]",children:[o,":"]}),h.jsx("span",{className:"font-mono text-foreground",children:typeof a=="string"?a:JSON.stringify(a)})]},o))})]}),h.jsxs("div",{className:"flex items-center gap-1 flex-shrink-0",children:[h.jsxs(He,{size:"sm",variant:"ghost",className:"h-6 px-2 text-xs",onClick:s,children:[h.jsx(X.Check,{className:"h-3 w-3 mr-1"}),"Approve"]}),h.jsx(He,{size:"sm",variant:"ghost",className:"h-6 px-2 text-xs text-muted-foreground",onClick:i,children:h.jsx(X.X,{className:"h-3 w-3"})})]})]})})}function fh({toolName:t,args:e,isDenied:n,isSafe:s}){const[i,r]=m.useState(!1);if(t==="fetchDocContent")return null;const o=["k","maxResults","_organizationId"];t==="searchDocs"&&o.push("filters");const a=Object.fromEntries(Object.entries(e).filter(([u])=>!o.includes(u))),l=Object.keys(a).length>0;return h.jsxs("div",{className:"my-1",children:[h.jsxs("button",{onClick:()=>l&&r(!i),className:`inline-flex items-center gap-1.5 text-xs rounded-md px-2 py-1 transition-colors ${n?"bg-red-100 dark:bg-red-950/30 text-red-700 dark:text-red-400":"bg-green-100 dark:bg-green-950/30 text-green-700 dark:text-green-400"} ${l?"cursor-pointer hover:bg-opacity-80":""}`,children:[l&&h.jsx("span",{className:"transition-transform duration-200",children:i?h.jsx(X.ChevronDown,{className:"h-3 w-3"}):h.jsx(X.ChevronRight,{className:"h-3 w-3"})}),n?h.jsx(X.X,{className:"h-3 w-3"}):s?h.jsx(X.Zap,{className:"h-3 w-3"}):h.jsx(X.Check,{className:"h-3 w-3"}),h.jsxs("span",{className:"font-medium",children:[n?"Denied":s?"Auto-executed":"Executed"," ",t]})]}),i&&l&&h.jsx("div",{className:"mt-1 ml-6 p-2 bg-stone-50 dark:bg-stone-900 rounded-md border border-border",children:h.jsx("div",{className:"space-y-0.5",children:Object.entries(a).map(([u,c])=>h.jsxs("div",{className:"flex items-start gap-1.5 text-xs",children:[h.jsxs("span",{className:"text-muted-foreground min-w-[60px]",children:[u,":"]}),h.jsx("span",{className:"font-mono text-foreground",children:typeof c=="string"?c:JSON.stringify(c)})]},u))})})]})}function mh({...t}){return h.jsx(qn.Root,{"data-slot":"collapsible",...t})}function ph({...t}){return h.jsx(qn.CollapsibleTrigger,{"data-slot":"collapsible-trigger",...t})}function gh({...t}){return h.jsx(qn.CollapsibleContent,{"data-slot":"collapsible-content",...t})}const yh=m.lazy(()=>import("streamdown").then(t=>({default:t.Streamdown}))),ks=m.memo(({className:t,...e})=>typeof window>"u"?null:h.jsx(m.Suspense,{fallback:null,children:h.jsx(yh,{className:Z("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",t),...e})}),(t,e)=>t.children===e.children);ks.displayName="Response";const xh=Object.freeze(Object.defineProperty({__proto__:null,Response:ks},Symbol.toStringTag,{value:"Module"})),vh=({children:t,as:e="p",className:n,duration:s=2,spread:i=2})=>{const r=ch.create(e),o=m.useMemo(()=>(t?.length??0)*i,[t,i]);return h.jsx(r,{animate:{backgroundPosition:"0% center"},className:Z("relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent","[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",n),initial:{backgroundPosition:"100% center"},style:{"--spread":`${o}px`,backgroundImage:"var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))"},transition:{repeat:Number.POSITIVE_INFINITY,duration:s,ease:"linear"},children:t})},bh=m.memo(vh),Gr=m.createContext(null),wh=()=>{const t=m.useContext(Gr);if(!t)throw new Error("Reasoning components must be used within Reasoning");return t},Th=1e3,Sh=1e3,qr=m.memo(({className:t,isStreaming:e=!1,open:n,defaultOpen:s=!0,onOpenChange:i,duration:r,children:o,...a})=>{const[l,u]=Ks.useControllableState({prop:n,defaultProp:s,onChange:i}),[c,d]=Ks.useControllableState({prop:r,defaultProp:0}),[f,g]=m.useState(!1),[y,v]=m.useState(null);m.useEffect(()=>{e?y===null&&v(Date.now()):y!==null&&(d(Math.ceil((Date.now()-y)/Sh)),v(null))},[e,y,d]),m.useEffect(()=>{if(s&&!e&&l&&!f){const x=setTimeout(()=>{u(!1),g(!0)},Th);return()=>clearTimeout(x)}},[e,l,s,u,f]);const w=x=>{u(x)};return h.jsx(Gr.Provider,{value:{isStreaming:e,isOpen:l,setIsOpen:u,duration:c},children:h.jsx(mh,{className:Z("not-prose mb-4",t),onOpenChange:w,open:l,...a,children:o})})}),Ch=(t,e)=>t||e===0?h.jsx(bh,{duration:1,children:"Thinking..."}):e===void 0?h.jsx("p",{children:"Thought for a few seconds"}):h.jsxs("p",{children:["Thought for ",e," seconds"]}),Zr=m.memo(({className:t,children:e,...n})=>{const{isStreaming:s,isOpen:i,duration:r}=wh();return h.jsx(ph,{className:Z("flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",t),...n,children:e??h.jsxs(h.Fragment,{children:[h.jsx(X.BrainIcon,{className:"size-4"}),Ch(s,r),h.jsx(X.ChevronDownIcon,{className:Z("size-4 transition-transform",i?"rotate-180":"rotate-0")})]})})}),Jr=m.memo(({className:t,children:e,...n})=>h.jsx(gh,{className:Z("mt-4 text-sm","data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",t),...n,children:h.jsx(ks,{className:"grid gap-2",children:e})}));qr.displayName="Reasoning";Zr.displayName="ReasoningTrigger";Jr.displayName="ReasoningContent";function Ah({theme:t="auto",layout:e="sidebar",model:n="auto",animated:s=!0,title:i="Chat",logo:r=void 0,defaultWidth:o=384,minWidth:a=300,maxWidth:l=800,initiallyExpanded:u=!1,tools:c=[],safeTools:d=[],toolMetadata:f,systemPrompt:g="",tokenEndpoint:y="/api/arcten/token",apiBaseUrl:v="https://api.arcten.com",user:w}){const[x,T]=m.useState(null),b=m.useRef(null),[E,A]=m.useState(null),[j,k]=m.useState(null),P=m.useRef(null),[N,W]=m.useState(u),[U,xt]=m.useState(o),[Tt,ft]=m.useState(600),[Et,St]=m.useState(!1),[V,Y]=m.useState(!1),[L,st]=m.useState(!1),[G,kt]=m.useState({x:100,y:100}),[je,Ct]=m.useState(!1),[Rt,Ve]=m.useState({x:0,y:0}),[nn,sn]=m.useState(!1),Xt=m.useRef(null),Yt=m.useRef(null),[D,R]=m.useState(""),[_,it]=m.useState(null),[tt,ct]=m.useState("Thinking..."),[on,rn]=m.useState(new Set),[Qr,ta]=m.useState(""),[Nt,ea]=m.useState([]),[an,Rs]=m.useState(!1),[ln,Ns]=m.useState([]),[Is,cn]=m.useState(()=>typeof window<"u"?crypto.randomUUID():null),[Gt,De]=m.useState(!1),[Mh,Ee]=m.useState(!1),[jh,ke]=m.useState([]),It=m.useMemo(()=>[...c,...d],[c,d]),Ls=m.useMemo(()=>Yr(It,f),[It,f]),Os=m.useMemo(()=>{const p=new Map;return It.forEach(C=>p.set(C.name,C)),p},[It]),Fs=m.useMemo(()=>new Set(d.map(p=>p.name)),[d]),Bs=["Thinking...","Pondering...","Contemplating...","Considering...","Analyzing...","Processing...","Reasoning...","Mulling it over...","Computing...","Cooking up a response...","Brewing ideas...","Connecting the dots...","Piecing it together...","Spinning up thoughts...","Loading brain cells...","Sharpening pencils...","Herding ideas...","Warming up neurons...","Stirring the think-pot...","Plotting a plan...","Wiggling the logic wires...","Rolling ideas around...","Charging the brainstorm...","Booting the brain...","Dusting off the cortex...","Running mental diagnostics...","Fetching cleverness...","Whisking up notions...","Tuning the idea radio...","Juggling possibilities...","Breathing in inspiration...","Squeezing the thought sponge...","Tickling the gray matter...","Bubbling up insights...","Spicing the soup of thought...","Lacing up hypotheses...","Winding the idea clock...","Casting the net for clues...","Polishing the crystal ball...","Mapping the maze...","Crunching the brain-biscuits...","Cueing the eureka moment...","Summoning the muse...","Knocking on insight’s door...","Combing the noodle...","Sailing the think-ship...","Scooping brain gelato...","Testing wild hunches...","Tick-tocking the neurons...","Planting idea seeds...","Shaking the thought snow globe...","Unlocking the mental toolbox...","Nudging the puzzle pieces...","Lighting the idea bulb...","Preheating the oven of insight...","Mixing the mental trail mix...","Spooling up reasoning reels...","Skimming the mind-palace index...","Surfing the thought waves...","Kicking the tires on ideas...","Rattling the idea can...","Waving the logic wand..."];m.useEffect(()=>{if(typeof window<"u"){const p=localStorage.getItem("arcten-sidebar-expanded");p&&W(JSON.parse(p));const C=localStorage.getItem("arcten-sidebar-width");C&&xt(parseInt(C));const I=localStorage.getItem("arcten-sidebar-height");I&&ft(parseInt(I));const S=localStorage.getItem("arcten-sidebar-detached");S&&Y(JSON.parse(S));const B=localStorage.getItem("arcten-sidebar-position");if(B){const At=JSON.parse(B),pt=50,Pt=Math.max(pt-o,Math.min(At.x,window.innerWidth-pt)),J=Math.max(0,Math.min(At.y,window.innerHeight-pt));kt({x:Pt,y:J})}const O=localStorage.getItem("arcten-sidebar-minimized");O&&st(JSON.parse(O)),sn(!0)}},[]),m.useEffect(()=>((async()=>{try{const C=await fetch(y,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(!C.ok)throw new Error("Failed to fetch token");const I=await C.json();T(I.clientToken),b.current=I.clientToken,k(I.expiresAt),A(null)}catch(C){A(C instanceof Error?C.message:"Failed to fetch token")}})(),()=>{P.current&&clearTimeout(P.current)}),[y,w]),m.useEffect(()=>{if(!j)return;P.current&&clearTimeout(P.current);const p=Math.floor(Date.now()/1e3),C=j-p,S=Math.max(0,C-5);return console.log(`Token expires at ${new Date(j*1e3).toISOString()}`),console.log(`Scheduling token refresh in ${S} seconds`),P.current=setTimeout(async()=>{console.log("Refreshing token...");try{const B=await fetch(y,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(!B.ok)throw new Error("Failed to refresh token");const O=await B.json();T(O.clientToken),b.current=O.clientToken,k(O.expiresAt),A(null),console.log("Token refreshed successfully")}catch(B){console.error("Token refresh failed:",B),A(B instanceof Error?B.message:"Failed to refresh token")}},S*1e3),()=>{P.current&&clearTimeout(P.current)}},[j,y,w]),m.useEffect(()=>{(async()=>{if(It.length!==0)try{const C=It.map(S=>({name:S.name,code:S.toString()})),I=await fetch(`${v}/tools/describe`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tools:C})});if(I.ok){const S=await I.json();ea(S.tools)}}catch(C){console.error("Failed to fetch tool descriptions:",C)}})()},[It]),m.useEffect(()=>{Promise.resolve().then(()=>xh).then(p=>{it(()=>p.Response)})},[]),m.useEffect(()=>{const p=()=>{ta(window.location.pathname)};p(),window.addEventListener("popstate",p);const C=setInterval(p,500);return()=>{window.removeEventListener("popstate",p),clearInterval(C)}},[]);async function $s(){if(!(!w?.id||!x)){Ee(!0);try{const C=await(await fetch(`${v}/conversations`,{headers:{Authorization:`Bearer ${x}`}})).json();Ns(C.conversations||[])}catch(p){console.error("Failed to fetch conversations:",p)}finally{Ee(!1)}}}m.useEffect(()=>{w?.id&&x&&$s()},[w,x]);function na(p){const C=Math.floor((Date.now()-p)/1e3);return C<60?"now":C<3600?`${Math.floor(C/60)}m`:C<86400?`${Math.floor(C/3600)}h`:`${Math.floor(C/86400)}d`}function sa(){const p=crypto.randomUUID();cn(p),Ne([]),ke([]),De(!1)}async function ia(p){if(x)try{await fetch(`${v}/conversations/${p}`,{method:"DELETE",headers:{Authorization:`Bearer ${x}`}}),Ns(ln.filter(C=>C._id!==p)),p===Is&&sa()}catch(C){console.error("Failed to delete conversation:",C)}}async function oa(p){cn(p.chatId),De(!1),Ee(!0);try{const C=await fetch(`${v}/conversations/${p.chatId}/messages`,{headers:{Authorization:`Bearer ${b.current}`}});if(!C.ok)throw new Error(`Failed to fetch messages: ${C.statusText}`);const S=(await C.json()).messages||[];Ne(S),ke(S)}catch(C){console.error("Failed to load conversation messages:",C);const I=p.messages||[];Ne(I),ke(I)}finally{Ee(!1)}}const ra=async(p,C={})=>{const I=C.headers?new Headers(C.headers):new Headers;return I.delete("user-agent"),I.delete("User-Agent"),fetch(p,{...C,headers:I})},{messages:ue,sendMessage:aa,status:mt,error:zs,stop:Re,addToolResult:de,setMessages:Ne}=lo.useChat({id:Is||void 0,transport:new Ke.DefaultChatTransport({api:`${v}/chat`,fetch:ra,headers:()=>{const p={};return b.current&&(p.Authorization=`Bearer ${b.current}`),p},body:()=>({tools:Ls.map(p=>({name:p.name,description:p.description,inputSchema:p.jsonSchema})),systemPrompt:g,currentRoute:Qr})}),sendAutomaticallyWhen:Ke.lastAssistantMessageIsCompleteWithToolCalls});m.useEffect(()=>{N&&Yt.current&&Yt.current.focus()},[N,ue]);function la(){W(!0),localStorage.setItem("arcten-sidebar-expanded","true")}function ca(){W(!1),localStorage.setItem("arcten-sidebar-expanded","false")}m.useEffect(()=>{},[N]),m.useEffect(()=>{Xt.current&&Xt.current.scrollIntoView({behavior:"smooth"})},[ue]),m.useEffect(()=>{function p(C){C.key==="Escape"&&(mt==="streaming"||mt==="submitted")&&(C.preventDefault(),Re())}return window.addEventListener("keydown",p),()=>window.removeEventListener("keydown",p)},[mt,Re]);function ua(){const p=crypto.randomUUID();cn(p),Ne([]),ke([]),De(!1)}function Us(p){if(p.preventDefault(),!D.trim())return;(mt==="streaming"||mt==="submitted")&&Re();const C=Bs[Math.floor(Math.random()*Bs.length)]||"Thinking...";ct(C),aa({text:D}),R("")}function da(p){const C=p.target.value;R(C)}m.useEffect(()=>{if(!Et)return;function p(I){if(V){const S=I.clientX-G.x,B=I.clientY-G.y;S>=a&&S<=l&&xt(S),B>=400&&B<=1e3&&ft(B)}else{const S=window.innerWidth-I.clientX;S>=a&&S<=l&&xt(S)}}function C(){St(!1),localStorage.setItem("arcten-sidebar-width",U.toString()),localStorage.setItem("arcten-sidebar-height",Tt.toString())}return window.addEventListener("mousemove",p),window.addEventListener("mouseup",C),()=>{window.removeEventListener("mousemove",p),window.removeEventListener("mouseup",C)}},[Et,U,Tt,V,G,a,l]);function ha(p){p.preventDefault(),St(!0)}function fa(){Y(!0),st(!1),localStorage.setItem("arcten-sidebar-detached","true"),localStorage.setItem("arcten-sidebar-minimized","false")}function ma(){Y(!1),st(!1),localStorage.setItem("arcten-sidebar-detached","false"),localStorage.setItem("arcten-sidebar-minimized","false")}function Ws(){st(!L),localStorage.setItem("arcten-sidebar-minimized",JSON.stringify(!L))}function pa(p){V&&(Ct(!0),Ve({x:p.clientX-G.x,y:p.clientY-G.y}))}return m.useEffect(()=>{if(!V)return;function p(){kt(C=>{const S=window.innerWidth-50,B=window.innerHeight-50,O=50-U,At=0,pt=Math.max(O,Math.min(C.x,S)),Pt=Math.max(At,Math.min(C.y,B));if(pt!==C.x||Pt!==C.y){const J={x:pt,y:Pt};return localStorage.setItem("arcten-sidebar-position",JSON.stringify(J)),J}return C})}return window.addEventListener("resize",p),()=>window.removeEventListener("resize",p)},[V,U]),m.useEffect(()=>{if(!je)return;function p(I){const S=I.clientX-Rt.x,B=I.clientY-Rt.y,O=50,At=window.innerWidth-O,pt=window.innerHeight-O,Pt=O-U,J=0,gt=Math.max(Pt,Math.min(S,At)),Lt=Math.max(J,Math.min(B,pt));kt({x:gt,y:Lt})}function C(){Ct(!1),localStorage.setItem("arcten-sidebar-position",JSON.stringify(G))}return window.addEventListener("mousemove",p),window.addEventListener("mouseup",C),()=>{window.removeEventListener("mousemove",p),window.removeEventListener("mouseup",C)}},[je,Rt,G,U]),nn?E?h.jsx("div",{className:"fixed right-0 top-0 h-screen w-96 flex items-center justify-center p-4 bg-stone-50 dark:bg-stone-900 border-l border-border",children:h.jsxs("div",{className:"p-4 bg-destructive/10 text-destructive text-sm rounded-lg",children:["Authentication error: ",E]})}):x?h.jsx(Nc,{features:uh,children:h.jsx(Be,{id:"arcten-sidebar","data-theme":t,"data-layout":e,"data-model":n,initial:V?{opacity:0,scale:.95,filter:"blur(4px)"}:!1,animate:V?{opacity:1,scale:1,filter:"blur(0px)"}:{},transition:{duration:.2,ease:"easeOut"},className:`
19
+ This usually means the tool wasn't discovered by the type extraction script.
20
+
21
+ To fix this:
22
+ `+(i?`1. Add TypeScript type annotations to your function parameters:
23
+ ${r}
24
+ // NOT: ${o} ❌
25
+
26
+ `:`1. Functions with no parameters are fine! Just make sure:
27
+ - The function is properly defined: ${r}
28
+ - It's used in ArctenAgent or useAgent (see step 2)
29
+
30
+ `)+`2. Make sure the tool is used in an ArctenAgent or useAgent component:
31
+ <ArctenAgent tools={[${s}]} />
32
+ // or
33
+ useAgent({ tools: [${s}] })
34
+
35
+ 3. Run the extraction script to generate metadata:
36
+ npx arcten-extract-types .
37
+
38
+ 4. Import and pass the metadata to your component:
39
+ import { toolMetadata } from './.arcten/tool-metadata';
40
+ useAgent({ tools: [${s}], toolMetadata: toolMetadata.functions })
41
+
42
+ 💡 Tip: ${i?"The script can only extract types from functions with explicit TypeScript type annotations on parameters.":"Functions with no parameters work fine - just make sure they're used in ArctenAgent or useAgent."}`)}return{name:s,description:e[s].description,jsonSchema:e[s].parameters}})}function hh({toolName:t,description:e,args:n,onApprove:s,onDeny:i}){const r=Object.keys(n).length>0;return h.jsx("div",{className:"bg-stone-100 dark:bg-stone-800 border border-border rounded-lg px-3 py-2.5 my-1.5",children:h.jsxs("div",{className:"flex items-start gap-2",children:[h.jsxs("div",{className:"flex-1 min-w-0",children:[h.jsx("div",{className:"flex items-center gap-1.5 mb-1",children:h.jsx("span",{className:"text-sm font-medium text-foreground",children:t})}),r&&h.jsx("div",{className:"space-y-0.5 mb-1.5",children:Object.entries(n).map(([o,a])=>h.jsxs("div",{className:"flex items-start gap-1.5 text-xs",children:[h.jsxs("span",{className:"text-muted-foreground min-w-[60px]",children:[o,":"]}),h.jsx("span",{className:"font-mono text-foreground",children:typeof a=="string"?a:JSON.stringify(a)})]},o))})]}),h.jsxs("div",{className:"flex items-center gap-1 flex-shrink-0",children:[h.jsxs(He,{size:"sm",variant:"ghost",className:"h-6 px-2 text-xs",onClick:s,children:[h.jsx(X.Check,{className:"h-3 w-3 mr-1"}),"Approve"]}),h.jsx(He,{size:"sm",variant:"ghost",className:"h-6 px-2 text-xs text-muted-foreground",onClick:i,children:h.jsx(X.X,{className:"h-3 w-3"})})]})]})})}function fh({toolName:t,args:e,isDenied:n,isSafe:s}){const[i,r]=m.useState(!1);if(t==="fetchDocContent")return null;const o=["k","maxResults","_organizationId"];t==="searchDocs"&&o.push("filters");const a=Object.fromEntries(Object.entries(e).filter(([u])=>!o.includes(u))),l=Object.keys(a).length>0;return h.jsxs("div",{className:"my-1",children:[h.jsxs("button",{onClick:()=>l&&r(!i),className:`inline-flex items-center gap-1.5 text-xs rounded-md px-2 py-1 transition-colors ${n?"bg-red-100 dark:bg-red-950/30 text-red-700 dark:text-red-400":"bg-green-100 dark:bg-green-950/30 text-green-700 dark:text-green-400"} ${l?"cursor-pointer hover:bg-opacity-80":""}`,children:[l&&h.jsx("span",{className:"transition-transform duration-200",children:i?h.jsx(X.ChevronDown,{className:"h-3 w-3"}):h.jsx(X.ChevronRight,{className:"h-3 w-3"})}),n?h.jsx(X.X,{className:"h-3 w-3"}):s?h.jsx(X.Zap,{className:"h-3 w-3"}):h.jsx(X.Check,{className:"h-3 w-3"}),h.jsxs("span",{className:"font-medium",children:[n?"Denied":s?"Auto-executed":"Executed"," ",t]})]}),i&&l&&h.jsx("div",{className:"mt-1 ml-6 p-2 bg-stone-50 dark:bg-stone-900 rounded-md border border-border",children:h.jsx("div",{className:"space-y-0.5",children:Object.entries(a).map(([u,c])=>h.jsxs("div",{className:"flex items-start gap-1.5 text-xs",children:[h.jsxs("span",{className:"text-muted-foreground min-w-[60px]",children:[u,":"]}),h.jsx("span",{className:"font-mono text-foreground",children:typeof c=="string"?c:JSON.stringify(c)})]},u))})})]})}function mh({...t}){return h.jsx(qn.Root,{"data-slot":"collapsible",...t})}function ph({...t}){return h.jsx(qn.CollapsibleTrigger,{"data-slot":"collapsible-trigger",...t})}function gh({...t}){return h.jsx(qn.CollapsibleContent,{"data-slot":"collapsible-content",...t})}const yh=m.lazy(()=>import("streamdown").then(t=>({default:t.Streamdown}))),ks=m.memo(({className:t,...e})=>typeof window>"u"?null:h.jsx(m.Suspense,{fallback:null,children:h.jsx(yh,{className:Z("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",t),...e})}),(t,e)=>t.children===e.children);ks.displayName="Response";const xh=Object.freeze(Object.defineProperty({__proto__:null,Response:ks},Symbol.toStringTag,{value:"Module"})),vh=({children:t,as:e="p",className:n,duration:s=2,spread:i=2})=>{const r=ch.create(e),o=m.useMemo(()=>(t?.length??0)*i,[t,i]);return h.jsx(r,{animate:{backgroundPosition:"0% center"},className:Z("relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent","[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",n),initial:{backgroundPosition:"100% center"},style:{"--spread":`${o}px`,backgroundImage:"var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))"},transition:{repeat:Number.POSITIVE_INFINITY,duration:s,ease:"linear"},children:t})},bh=m.memo(vh),Gr=m.createContext(null),wh=()=>{const t=m.useContext(Gr);if(!t)throw new Error("Reasoning components must be used within Reasoning");return t},Th=1e3,Sh=1e3,qr=m.memo(({className:t,isStreaming:e=!1,open:n,defaultOpen:s=!0,onOpenChange:i,duration:r,children:o,...a})=>{const[l,u]=Ks.useControllableState({prop:n,defaultProp:s,onChange:i}),[c,d]=Ks.useControllableState({prop:r,defaultProp:0}),[f,g]=m.useState(!1),[y,v]=m.useState(null);m.useEffect(()=>{e?y===null&&v(Date.now()):y!==null&&(d(Math.ceil((Date.now()-y)/Sh)),v(null))},[e,y,d]),m.useEffect(()=>{if(s&&!e&&l&&!f){const x=setTimeout(()=>{u(!1),g(!0)},Th);return()=>clearTimeout(x)}},[e,l,s,u,f]);const w=x=>{u(x)};return h.jsx(Gr.Provider,{value:{isStreaming:e,isOpen:l,setIsOpen:u,duration:c},children:h.jsx(mh,{className:Z("not-prose mb-4",t),onOpenChange:w,open:l,...a,children:o})})}),Ch=(t,e)=>t||e===0?h.jsx(bh,{duration:1,children:"Thinking..."}):e===void 0?h.jsx("p",{children:"Thought for a few seconds"}):h.jsxs("p",{children:["Thought for ",e," seconds"]}),Zr=m.memo(({className:t,children:e,...n})=>{const{isStreaming:s,isOpen:i,duration:r}=wh();return h.jsx(ph,{className:Z("flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",t),...n,children:e??h.jsxs(h.Fragment,{children:[h.jsx(X.BrainIcon,{className:"size-4"}),Ch(s,r),h.jsx(X.ChevronDownIcon,{className:Z("size-4 transition-transform",i?"rotate-180":"rotate-0")})]})})}),Jr=m.memo(({className:t,children:e,...n})=>h.jsx(gh,{className:Z("mt-4 text-sm","data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",t),...n,children:h.jsx(ks,{className:"grid gap-2",children:e})}));qr.displayName="Reasoning";Zr.displayName="ReasoningTrigger";Jr.displayName="ReasoningContent";function Ah({theme:t="auto",layout:e="sidebar",model:n="auto",animated:s=!0,title:i="Chat",logo:r=void 0,defaultWidth:o=384,minWidth:a=300,maxWidth:l=800,initiallyExpanded:u=!1,tools:c=[],safeTools:d=[],toolMetadata:f,systemPrompt:g="",tokenEndpoint:y="/api/arcten/token",apiBaseUrl:v="https://api.arcten.com",user:w}){const[x,T]=m.useState(null),b=m.useRef(null),[E,A]=m.useState(null),[j,k]=m.useState(null),P=m.useRef(null),[N,W]=m.useState(u),[U,xt]=m.useState(o),[Tt,ft]=m.useState(600),[Et,St]=m.useState(!1),[V,Y]=m.useState(!1),[L,st]=m.useState(!1),[G,kt]=m.useState({x:100,y:100}),[je,Ct]=m.useState(!1),[Rt,Ve]=m.useState({x:0,y:0}),[nn,sn]=m.useState(!1),Xt=m.useRef(null),Yt=m.useRef(null),[D,R]=m.useState(""),[_,it]=m.useState(null),[tt,ct]=m.useState("Thinking..."),[on,rn]=m.useState(new Set),[Qr,ta]=m.useState(""),[Nt,ea]=m.useState([]),[an,Rs]=m.useState(!1),[ln,Ns]=m.useState([]),[Is,cn]=m.useState(()=>typeof window<"u"?crypto.randomUUID():null),[Gt,De]=m.useState(!1),[Mh,Ee]=m.useState(!1),[jh,ke]=m.useState([]),It=m.useMemo(()=>[...c,...d],[c,d]),Ls=m.useMemo(()=>Yr(It,f),[It,f]),Os=m.useMemo(()=>{const p=new Map;return It.forEach(C=>p.set(C.name,C)),p},[It]),Fs=m.useMemo(()=>new Set(d.map(p=>p.name)),[d]),Bs=["Thinking...","Pondering...","Contemplating...","Considering...","Analyzing...","Processing...","Reasoning...","Mulling it over...","Computing...","Cooking up a response...","Brewing ideas...","Connecting the dots...","Piecing it together...","Spinning up thoughts...","Loading brain cells...","Sharpening pencils...","Herding ideas...","Warming up neurons...","Stirring the think-pot...","Plotting a plan...","Wiggling the logic wires...","Rolling ideas around...","Charging the brainstorm...","Booting the brain...","Dusting off the cortex...","Running mental diagnostics...","Fetching cleverness...","Whisking up notions...","Tuning the idea radio...","Juggling possibilities...","Breathing in inspiration...","Squeezing the thought sponge...","Tickling the gray matter...","Bubbling up insights...","Spicing the soup of thought...","Lacing up hypotheses...","Winding the idea clock...","Casting the net for clues...","Polishing the crystal ball...","Mapping the maze...","Crunching the brain-biscuits...","Cueing the eureka moment...","Summoning the muse...","Knocking on insight’s door...","Combing the noodle...","Sailing the think-ship...","Scooping brain gelato...","Testing wild hunches...","Tick-tocking the neurons...","Planting idea seeds...","Shaking the thought snow globe...","Unlocking the mental toolbox...","Nudging the puzzle pieces...","Lighting the idea bulb...","Preheating the oven of insight...","Mixing the mental trail mix...","Spooling up reasoning reels...","Skimming the mind-palace index...","Surfing the thought waves...","Kicking the tires on ideas...","Rattling the idea can...","Waving the logic wand..."];m.useEffect(()=>{if(typeof window<"u"){const p=localStorage.getItem("arcten-sidebar-expanded");p&&W(JSON.parse(p));const C=localStorage.getItem("arcten-sidebar-width");C&&xt(parseInt(C));const I=localStorage.getItem("arcten-sidebar-height");I&&ft(parseInt(I));const S=localStorage.getItem("arcten-sidebar-detached");S&&Y(JSON.parse(S));const B=localStorage.getItem("arcten-sidebar-position");if(B){const At=JSON.parse(B),pt=50,Pt=Math.max(pt-o,Math.min(At.x,window.innerWidth-pt)),J=Math.max(0,Math.min(At.y,window.innerHeight-pt));kt({x:Pt,y:J})}const O=localStorage.getItem("arcten-sidebar-minimized");O&&st(JSON.parse(O)),sn(!0)}},[]),m.useEffect(()=>((async()=>{try{const C=await fetch(y,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(!C.ok)throw new Error("Failed to fetch token");const I=await C.json();T(I.clientToken),b.current=I.clientToken,k(I.expiresAt),A(null)}catch(C){A(C instanceof Error?C.message:"Failed to fetch token")}})(),()=>{P.current&&clearTimeout(P.current)}),[y,w]),m.useEffect(()=>{if(!j)return;P.current&&clearTimeout(P.current);const p=Math.floor(Date.now()/1e3),C=j-p,S=Math.max(0,C-5);return console.log(`Token expires at ${new Date(j*1e3).toISOString()}`),console.log(`Scheduling token refresh in ${S} seconds`),P.current=setTimeout(async()=>{console.log("Refreshing token...");try{const B=await fetch(y,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(!B.ok)throw new Error("Failed to refresh token");const O=await B.json();T(O.clientToken),b.current=O.clientToken,k(O.expiresAt),A(null),console.log("Token refreshed successfully")}catch(B){console.error("Token refresh failed:",B),A(B instanceof Error?B.message:"Failed to refresh token")}},S*1e3),()=>{P.current&&clearTimeout(P.current)}},[j,y,w]),m.useEffect(()=>{(async()=>{if(It.length!==0)try{const C=It.map(S=>({name:S.name,code:S.toString()})),I=await fetch(`${v}/tools/describe`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tools:C})});if(I.ok){const S=await I.json();ea(S.tools)}}catch(C){console.error("Failed to fetch tool descriptions:",C)}})()},[It]),m.useEffect(()=>{Promise.resolve().then(()=>xh).then(p=>{it(()=>p.Response)})},[]),m.useEffect(()=>{const p=()=>{ta(window.location.pathname)};p(),window.addEventListener("popstate",p);const C=setInterval(p,500);return()=>{window.removeEventListener("popstate",p),clearInterval(C)}},[]);async function $s(){if(!(!w?.id||!x)){Ee(!0);try{const C=await(await fetch(`${v}/conversations`,{headers:{Authorization:`Bearer ${x}`}})).json();Ns(C.conversations||[])}catch(p){console.error("Failed to fetch conversations:",p)}finally{Ee(!1)}}}m.useEffect(()=>{w?.id&&x&&$s()},[w,x]);function na(p){const C=Math.floor((Date.now()-p)/1e3);return C<60?"now":C<3600?`${Math.floor(C/60)}m`:C<86400?`${Math.floor(C/3600)}h`:`${Math.floor(C/86400)}d`}function sa(){const p=crypto.randomUUID();cn(p),Ne([]),ke([]),De(!1)}async function ia(p){if(x)try{await fetch(`${v}/conversations/${p}`,{method:"DELETE",headers:{Authorization:`Bearer ${x}`}}),Ns(ln.filter(C=>C._id!==p)),p===Is&&sa()}catch(C){console.error("Failed to delete conversation:",C)}}async function oa(p){cn(p.chatId),De(!1),Ee(!0);try{const C=await fetch(`${v}/conversations/${p.chatId}/messages`,{headers:{Authorization:`Bearer ${b.current}`}});if(!C.ok)throw new Error(`Failed to fetch messages: ${C.statusText}`);const S=(await C.json()).messages||[];Ne(S),ke(S)}catch(C){console.error("Failed to load conversation messages:",C);const I=p.messages||[];Ne(I),ke(I)}finally{Ee(!1)}}const ra=async(p,C={})=>{const I=C.headers?new Headers(C.headers):new Headers;return I.delete("user-agent"),I.delete("User-Agent"),fetch(p,{...C,headers:I})},{messages:ue,sendMessage:aa,status:mt,error:zs,stop:Re,addToolResult:de,setMessages:Ne}=lo.useChat({id:Is||void 0,transport:new Ke.DefaultChatTransport({api:`${v}/chat`,fetch:ra,headers:()=>{const p={};return b.current&&(p.Authorization=`Bearer ${b.current}`),p},body:()=>({tools:Ls.map(p=>({name:p.name,description:p.description,inputSchema:p.jsonSchema})),systemPrompt:g,currentRoute:Qr})}),sendAutomaticallyWhen:Ke.lastAssistantMessageIsCompleteWithToolCalls});m.useEffect(()=>{N&&Yt.current&&Yt.current.focus()},[N,ue]);function la(){W(!0),localStorage.setItem("arcten-sidebar-expanded","true")}function ca(){W(!1),localStorage.setItem("arcten-sidebar-expanded","false")}m.useEffect(()=>{},[N]),m.useEffect(()=>{Xt.current&&Xt.current.scrollIntoView({behavior:"smooth"})},[ue]),m.useEffect(()=>{function p(C){C.key==="Escape"&&(mt==="streaming"||mt==="submitted")&&(C.preventDefault(),Re())}return window.addEventListener("keydown",p),()=>window.removeEventListener("keydown",p)},[mt,Re]);function ua(){const p=crypto.randomUUID();cn(p),Ne([]),ke([]),De(!1)}function Us(p){if(p.preventDefault(),!D.trim())return;(mt==="streaming"||mt==="submitted")&&Re();const C=Bs[Math.floor(Math.random()*Bs.length)]||"Thinking...";ct(C),aa({text:D}),R("")}function da(p){const C=p.target.value;R(C)}m.useEffect(()=>{if(!Et)return;function p(I){if(V){const S=I.clientX-G.x,B=I.clientY-G.y;S>=a&&S<=l&&xt(S),B>=400&&B<=1e3&&ft(B)}else{const S=window.innerWidth-I.clientX;S>=a&&S<=l&&xt(S)}}function C(){St(!1),localStorage.setItem("arcten-sidebar-width",U.toString()),localStorage.setItem("arcten-sidebar-height",Tt.toString())}return window.addEventListener("mousemove",p),window.addEventListener("mouseup",C),()=>{window.removeEventListener("mousemove",p),window.removeEventListener("mouseup",C)}},[Et,U,Tt,V,G,a,l]);function ha(p){p.preventDefault(),St(!0)}function fa(){Y(!0),st(!1),localStorage.setItem("arcten-sidebar-detached","true"),localStorage.setItem("arcten-sidebar-minimized","false")}function ma(){Y(!1),st(!1),localStorage.setItem("arcten-sidebar-detached","false"),localStorage.setItem("arcten-sidebar-minimized","false")}function Ws(){st(!L),localStorage.setItem("arcten-sidebar-minimized",JSON.stringify(!L))}function pa(p){V&&(Ct(!0),Ve({x:p.clientX-G.x,y:p.clientY-G.y}))}return m.useEffect(()=>{if(!V)return;function p(){kt(C=>{const S=window.innerWidth-50,B=window.innerHeight-50,O=50-U,At=0,pt=Math.max(O,Math.min(C.x,S)),Pt=Math.max(At,Math.min(C.y,B));if(pt!==C.x||Pt!==C.y){const J={x:pt,y:Pt};return localStorage.setItem("arcten-sidebar-position",JSON.stringify(J)),J}return C})}return window.addEventListener("resize",p),()=>window.removeEventListener("resize",p)},[V,U]),m.useEffect(()=>{if(!je)return;function p(I){const S=I.clientX-Rt.x,B=I.clientY-Rt.y,O=50,At=window.innerWidth-O,pt=window.innerHeight-O,Pt=O-U,J=0,gt=Math.max(Pt,Math.min(S,At)),Lt=Math.max(J,Math.min(B,pt));kt({x:gt,y:Lt})}function C(){Ct(!1),localStorage.setItem("arcten-sidebar-position",JSON.stringify(G))}return window.addEventListener("mousemove",p),window.addEventListener("mouseup",C),()=>{window.removeEventListener("mousemove",p),window.removeEventListener("mouseup",C)}},[je,Rt,G,U]),nn?E?h.jsx("div",{className:"fixed right-0 top-0 h-screen w-96 flex items-center justify-center p-4 bg-stone-50 dark:bg-stone-900 border-l border-border",children:h.jsxs("div",{className:"p-4 bg-destructive/10 text-destructive text-sm rounded-lg",children:["Authentication error: ",E]})}):x?h.jsx(Nc,{features:uh,children:h.jsx(Be,{id:"arcten-sidebar","data-theme":t,"data-layout":e,"data-model":n,initial:V?{opacity:0,scale:.95,filter:"blur(4px)"}:!1,animate:V?{opacity:1,scale:1,filter:"blur(0px)"}:{},transition:{duration:.2,ease:"easeOut"},className:`
23
43
  ${V?"fixed z-50 shadow-xl rounded-xl":"h-screen flex-shrink-0 relative rounded-l-2xl"}
24
44
  ${N?"bg-stone-50 dark:bg-stone-900":"bg-stone-100 dark:bg-stone-800 hover:bg-stone-200 dark:hover:bg-stone-700 transition-colors duration-200"}
25
45
  ${V?"border border-border":"border-l border-border"}
package/dist/index.mjs CHANGED
@@ -5030,15 +5030,37 @@ Please:
5030
5030
  );
5031
5031
  return t.map((n) => {
5032
5032
  const s = n.name || "unnamed";
5033
- if (!e[s])
5033
+ if (!e[s]) {
5034
+ const i = n.length > 0, r = i ? `function ${s}(param1: string, param2?: number) { ... }` : `function ${s}() { ... }`, o = i ? `function ${s}(param1, param2) { ... }` : `function ${s}() { ... }`;
5034
5035
  throw new Error(
5035
5036
  `❌ No metadata found for tool "${s}".
5036
5037
 
5037
- Make sure:
5038
- 1. The tool is exported from your tools file
5039
- 2. You've run "arcten-extract-types ." recently
5040
- 3. The tool is used in an ArctenAgent or useAgent component`
5038
+ This usually means the tool wasn't discovered by the type extraction script.
5039
+
5040
+ To fix this:
5041
+ ` + (i ? `1. Add TypeScript type annotations to your function parameters:
5042
+ ${r}
5043
+ // NOT: ${o} ❌
5044
+
5045
+ ` : `1. Functions with no parameters are fine! Just make sure:
5046
+ - The function is properly defined: ${r}
5047
+ - It's used in ArctenAgent or useAgent (see step 2)
5048
+
5049
+ `) + `2. Make sure the tool is used in an ArctenAgent or useAgent component:
5050
+ <ArctenAgent tools={[${s}]} />
5051
+ // or
5052
+ useAgent({ tools: [${s}] })
5053
+
5054
+ 3. Run the extraction script to generate metadata:
5055
+ npx arcten-extract-types .
5056
+
5057
+ 4. Import and pass the metadata to your component:
5058
+ import { toolMetadata } from './.arcten/tool-metadata';
5059
+ useAgent({ tools: [${s}], toolMetadata: toolMetadata.functions })
5060
+
5061
+ 💡 Tip: ${i ? "The script can only extract types from functions with explicit TypeScript type annotations on parameters." : "Functions with no parameters work fine - just make sure they're used in ArctenAgent or useAgent."}`
5041
5062
  );
5063
+ }
5042
5064
  return {
5043
5065
  name: s,
5044
5066
  description: e[s].description,
@@ -1 +1 @@
1
- {"version":3,"file":"extract-tool-metadata.d.ts","sourceRoot":"","sources":["../../src/utils/extract-tool-metadata.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,GAAG,CAAC;CACjB;AAGD,UAAU,yBAAyB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,GAAG,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,QAAQ,EAAE,EACrB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,IAAI,GAC/D,YAAY,EAAE,CAiChB"}
1
+ {"version":3,"file":"extract-tool-metadata.d.ts","sourceRoot":"","sources":["../../src/utils/extract-tool-metadata.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,GAAG,CAAC;CACjB;AAGD,UAAU,yBAAyB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,GAAG,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,QAAQ,EAAE,EACrB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,IAAI,GAC/D,YAAY,EAAE,CAyDhB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcteninc/core",
3
- "version": "0.0.27",
3
+ "version": "0.0.30",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -69,7 +69,7 @@
69
69
  "clsx": "^2.1.1",
70
70
  "cmdk": "^1.1.1",
71
71
  "glob": "^11.0.3",
72
- "lucide-react": "^0.552.0",
72
+ "lucide-react": "^0.553.0",
73
73
  "motion": "^12.23.24",
74
74
  "nanoid": "^5.1.6",
75
75
  "react-resizable-panels": "^3.0.6",
@@ -36,45 +36,45 @@ async function main() {
36
36
 
37
37
  const args = process.argv.slice(2);
38
38
 
39
- // Try tsx first (lightweight TypeScript runner for Node.js)
40
- // Use npx to run it without requiring installation
41
- const hasTsx = await checkCommand('npx');
39
+ // Check for bun first (faster and preferred if available)
40
+ const hasBun = await checkCommand('bun');
42
41
 
43
- if (hasTsx) {
44
- // Use tsx via npx - it's lightweight and works great with Node.js
45
- const tsxProcess = spawn('npx', ['-y', 'tsx', tsScript, ...args], {
42
+ if (hasBun) {
43
+ // Use bun directly - it's faster and can run TypeScript natively
44
+ const bunProcess = spawn('bun', [tsScript, ...args], {
46
45
  stdio: 'inherit',
47
46
  shell: true
48
47
  });
49
48
 
50
- tsxProcess.on('close', (code) => {
49
+ bunProcess.on('close', (code) => {
51
50
  process.exit(code || 0);
52
51
  });
53
52
 
54
- tsxProcess.on('error', (err) => {
55
- // If tsx fails, try bun as fallback
56
- tryBunFallback(args);
53
+ bunProcess.on('error', (err) => {
54
+ // If bun fails, try tsx as fallback
55
+ tryTsxFallback(args);
57
56
  });
58
57
  } else {
59
- // Fallback to bun if npx isn't available
60
- tryBunFallback(args);
58
+ // Fallback to tsx via npx if bun isn't available
59
+ tryTsxFallback(args);
61
60
  }
62
61
  }
63
62
 
64
- async function tryBunFallback(args) {
65
- const hasBun = await checkCommand('bun');
63
+ async function tryTsxFallback(args) {
64
+ const hasNpx = await checkCommand('npx');
66
65
 
67
- if (hasBun) {
68
- const bunProcess = spawn('bun', [tsScript, ...args], {
66
+ if (hasNpx) {
67
+ // Use tsx via npx - it's lightweight and works great with Node.js
68
+ const tsxProcess = spawn('npx', ['-y', 'tsx', tsScript, ...args], {
69
69
  stdio: 'inherit',
70
70
  shell: true
71
71
  });
72
72
 
73
- bunProcess.on('close', (code) => {
73
+ tsxProcess.on('close', (code) => {
74
74
  process.exit(code || 0);
75
75
  });
76
76
 
77
- bunProcess.on('error', (err) => {
77
+ tsxProcess.on('error', (err) => {
78
78
  console.error('❌ Error: Could not run script');
79
79
  console.error('Please ensure you have Node.js (with npx) or bun installed');
80
80
  process.exit(1);
@@ -83,8 +83,8 @@ async function tryBunFallback(args) {
83
83
  console.error('❌ Error: Could not find a TypeScript runner');
84
84
  console.error('');
85
85
  console.error('Please install one of the following:');
86
- console.error(' - Node.js (comes with npx) - recommended');
87
- console.error(' - bun: curl -fsSL https://bun.sh/install | bash');
86
+ console.error(' - bun: curl -fsSL https://bun.sh/install | bash (recommended)');
87
+ console.error(' - Node.js (comes with npx)');
88
88
  process.exit(1);
89
89
  }
90
90
  }