@cartanova/qgrid-cli 2.7.4 → 2.7.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 (47) hide show
  1. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +7 -3
  2. package/bundle/dist/application/qgrid/qgrid.frame.js +27 -11
  3. package/bundle/dist/application/qgrid/qgrid.types.js +2 -1
  4. package/bundle/dist/application/qgrid/token-subscriber.js +19 -1
  5. package/bundle/dist/application/qgrid/token-window-keepalive.js +153 -0
  6. package/bundle/dist/application/setting/setting.constant.js +11 -1
  7. package/bundle/dist/application/token/token.model.js +18 -1
  8. package/bundle/dist/migrations/20260819102011_alter_tokens_alter1.js +13 -0
  9. package/bundle/dist/sonamu.config.js +9 -1
  10. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +7 -4
  11. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +11 -3
  12. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +51 -0
  13. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +14 -4
  14. package/bundle/src/application/qgrid/qgrid.frame.test.ts +58 -0
  15. package/bundle/src/application/qgrid/qgrid.frame.ts +39 -12
  16. package/bundle/src/application/qgrid/qgrid.types.ts +2 -0
  17. package/bundle/src/application/qgrid/token-subscriber.test.ts +112 -0
  18. package/bundle/src/application/qgrid/token-subscriber.ts +35 -0
  19. package/bundle/src/application/qgrid/token-window-keepalive.test.ts +223 -0
  20. package/bundle/src/application/qgrid/token-window-keepalive.ts +227 -0
  21. package/bundle/src/application/setting/setting.constant.test.ts +10 -0
  22. package/bundle/src/application/setting/setting.constant.ts +11 -1
  23. package/bundle/src/application/sonamu.generated.http +2 -0
  24. package/bundle/src/application/token/token.entity.json +8 -1
  25. package/bundle/src/application/token/token.model.test.ts +37 -0
  26. package/bundle/src/application/token/token.model.ts +20 -0
  27. package/bundle/src/migrations/20260819102011_alter_tokens_alter1.ts +13 -0
  28. package/bundle/src/sonamu.config.ts +14 -0
  29. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +46 -0
  30. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +13 -4
  31. package/bundle/src/utils/providers/common/provider-dispatcher.ts +2 -0
  32. package/bundle/src/utils/providers/openai/openai-dispatcher.test.ts +30 -0
  33. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +17 -1
  34. package/bundle/web-dist/client/assets/index-BbOyk01G.js +106 -0
  35. package/bundle/web-dist/client/assets/{logs-UlTjUAUB.js → logs-B7Pc88bf.js} +1 -1
  36. package/bundle/web-dist/client/assets/{monit-CVNZnd8j.js → monit-CzMV4lZf.js} +1 -1
  37. package/bundle/web-dist/client/assets/{routes-CF7Jlmfi.js → routes-COWTRxZo.js} +1 -1
  38. package/bundle/web-dist/client/assets/settings-Dpaosy-o.js +1 -0
  39. package/bundle/web-dist/client/assets/{show-CGhg0fbn.js → show-YvdybkKd.js} +1 -1
  40. package/bundle/web-dist/client/assets/{tokens-DaEtcsoL.js → tokens-DynVDx0c.js} +1 -1
  41. package/bundle/web-dist/client/assets/{use-oauth-login-flow-Eovfx07A.js → use-oauth-login-flow-OzmHElsE.js} +1 -1
  42. package/bundle/web-dist/client/index.html +1 -1
  43. package/bundle/web-dist/server/assets/{settings-nCv71sax.js → settings-CIYR7h3G.js} +1 -0
  44. package/bundle/web-dist/server/entry-server.generated.js +96 -51
  45. package/package.json +3 -2
  46. package/bundle/web-dist/client/assets/index-CPYQIUqO.js +0 -106
  47. package/bundle/web-dist/client/assets/settings-N-8sXHl6.js +0 -1
@@ -1 +1 @@
1
- import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{y as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{n as i,o as a}from"./services.generated-CA7oRRYY.js";import{i as o,u as s}from"./index-CPYQIUqO.js";import{n as c,r as l,t as u}from"./use-oauth-login-flow-Eovfx07A.js";import{t as d}from"./plus-DqBd6gHk.js";var f=e(n(),1),p=r();function m(){let[e,t]=(0,f.useState)(!1),[n,r]=(0,f.useState)(``),i=u(),a=()=>{t(!1),r(``),i.reset()},l=async e=>{await i.submitCode(e)&&a()};return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(`button`,{type:`button`,className:`px-3.5 py-1.5 text-[12px] font-medium rounded-lg bg-sienna-500 text-white hover:bg-sienna-600 disabled:opacity-50 transition-all duration-150 active:scale-[0.97] flex items-center gap-1.5 shadow-sm`,onClick:()=>t(!0),children:[(0,p.jsx)(d,{className:`size-3.5`}),`Add Token`]}),e&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:a,onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-md mx-4`,children:[(0,p.jsx)(`div`,{className:`px-5 py-4 border-b border-sand-100/50`,children:(0,p.jsx)(`h2`,{className:`text-base font-medium text-sand-900`,children:`Add Token`})}),(0,p.jsxs)(`div`,{className:`px-5 py-4 space-y-4`,children:[(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`label`,{htmlFor:`token-name`,className:`text-[10px] uppercase tracking-wider text-sand-500 font-medium`,children:`Name *`}),(0,p.jsx)(o,{value:n,onChange:e=>r(e.target.value),placeholder:`e.g. your-token-name`,className:`mt-1 w-full border border-sand-200 rounded-md px-3 py-2 text-sm text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`})]}),i.codeEntry?(0,p.jsx)(c,{isPending:i.completeMutation.isPending,isError:i.completeMutation.isError,onSubmit:e=>void l(e),onRestart:i.reset}):(0,p.jsxs)(`div`,{className:`space-y-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!n.trim()||i.loadingProvider!==null,onClick:()=>void i.start(`openai`,n),children:i.loadingProvider===`openai`?(0,p.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Waiting for login...`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(s,{className:`size-4`}),`Login with OpenAI`]})}),(0,p.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,p.jsx)(`div`,{className:`flex-1 h-px bg-sand-200`}),(0,p.jsx)(`span`,{className:`text-[10px] text-sand-400 uppercase`,children:`or`}),(0,p.jsx)(`div`,{className:`flex-1 h-px bg-sand-200`})]}),(0,p.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md border border-sand-300 text-sand-700 hover:bg-sand-100 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!n.trim()||i.loadingProvider!==null,onClick:()=>void i.start(`anthropic`,n),children:i.loadingProvider===`anthropic`?(0,p.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-sand-400 border-t-transparent rounded-full animate-spin`}),`Waiting for login...`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(s,{className:`size-4`}),`Login with Claude`]})})]})]}),(0,p.jsx)(`div`,{className:`px-5 py-3 border-t border-sand-100/50 flex items-center justify-end gap-2`,children:(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:a,children:`Cancel`})})]})]})]})}var h=e=>(0,p.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,p.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,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-.497zM15 5l4 4`})}),g=e=>(0,p.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,p.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,d:`M10 11v6m4-6v6m5-11v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`})});function _(e){let t=e.credentials;return`expiresAt`in t&&typeof t.expiresAt==`number`?t.expiresAt:`accessTokenExpiresAt`in t&&typeof t.accessTokenExpiresAt==`number`?t.accessTokenExpiresAt:null}function v(e){if(!e)return{text:``,color:``};let t=e-Date.now();if(t<=0)return{text:`expired`,color:`text-red-500`};let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4),i=n>0?`${n}h ${r}m`:`${r}m`;return t<36e5?{text:i,color:`text-amber-500`}:{text:i,color:`text-sand-400`}}function y(e){let t=e.credentials.accessToken;return t.length<=12?t:`${t.slice(0,8)}...${t.slice(-4)}`}function b({data:e,isLoading:n}){let[r,a]=(0,f.useState)(null),[s,c]=(0,f.useState)(null),[u,d]=(0,f.useState)(``),m=t(),b=i.useRemoveTokenMutation(),x=l(),S=i.useToggleTokenMutation(),C=()=>Promise.all([m.invalidateQueries({queryKey:[`Token`]}),m.invalidateQueries({queryKey:[`Qgrid`]})]),w=async e=>{await S.mutateAsync({id:e.id}),await C()},T=async()=>{r&&(await b.mutateAsync({id:r.id}),await C(),a(null))},E=e=>{c(e),d(e.name??``)},D=async()=>{s&&(await x.mutateAsync({id:s.id,name:u.trim()}),await C(),c(null))};if(n)return(0,p.jsx)(`div`,{className:`space-y-2`,children:Array.from({length:3}).map((e,t)=>(0,p.jsx)(`div`,{className:`h-12 bg-sand-100 rounded-md animate-pulse`},`skeleton-${t}`))});let O=e??[];return O.length===0?(0,p.jsxs)(`div`,{className:`text-sand-400 text-center py-16 text-sm`,children:[`No tokens registered. Click `,(0,p.jsx)(`strong`,{className:`text-sand-600`,children:`Add Token`}),` to get started.`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(`div`,{className:`panel overflow-hidden`,children:(0,p.jsx)(`div`,{className:`overflow-x-auto`,children:(0,p.jsxs)(`table`,{className:`w-full min-w-[640px] text-[13px]`,children:[(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{className:`panel-header`,children:[(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Provider`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Name`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Token`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Status`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Expires`}),(0,p.jsx)(`th`,{className:`w-20 px-3 py-2.5`})]})}),(0,p.jsx)(`tbody`,{className:`divide-y divide-sand-100/80`,children:O.map(e=>{let t=v(_(e));return(0,p.jsxs)(`tr`,{className:`transition-colors duration-150 hover:bg-sand-100/60 ${e.active?``:`opacity-50`}`,children:[(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`span`,{className:`text-xs font-medium text-sand-500 uppercase`,children:e.provider})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:e.name?(0,p.jsx)(`span`,{className:`text-sm text-sand-700`,children:e.name}):(0,p.jsx)(`span`,{className:`text-[11px] text-sand-400`,children:`—`})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`code`,{className:`text-[13px] font-mono text-sand-800`,children:y(e)})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`button`,{type:`button`,className:`relative inline-flex h-5 w-9 items-center rounded-full transition-colors duration-200 ${e.active?`bg-sage-400`:`bg-sand-300`}`,onClick:()=>w(e),disabled:S.isPending,children:(0,p.jsx)(`span`,{className:`inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform duration-200 ${e.active?`translate-x-4.5`:`translate-x-0.5`}`})})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:t.text&&(0,p.jsx)(`span`,{className:`text-xs ${t.color}`,children:t.text})}),(0,p.jsx)(`td`,{className:`px-3 py-3`,children:(0,p.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,p.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-sienna-500 transition-colors duration-150`,onClick:()=>E(e),children:(0,p.jsx)(h,{className:`size-4`})}),(0,p.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-red-500 transition-colors duration-150`,onClick:()=>a(e),children:(0,p.jsx)(g,{className:`size-4`})})]})})]},e.id)})})]})})}),s&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:()=>c(null),onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-sm mx-4`,children:[(0,p.jsx)(`div`,{className:`px-5 py-4 border-b border-sand-100/60`,children:(0,p.jsx)(`h3`,{className:`text-base font-medium text-sand-900`,children:`Edit Token`})}),(0,p.jsx)(`div`,{className:`px-5 py-4 space-y-3`,children:(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`label`,{htmlFor:`token-name`,className:`text-[10px] uppercase tracking-wider text-sand-500 font-medium`,children:`Name`}),(0,p.jsx)(o,{value:u,onChange:e=>d(e.target.value),placeholder:`e.g. prod, dev, team-a`,className:`mt-1 w-full border border-sand-200 rounded-md px-3 py-2 text-sm text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`})]})}),(0,p.jsxs)(`div`,{className:`px-5 py-3 border-t border-sand-100/60 flex items-center justify-end gap-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:()=>c(null),children:`Cancel`}),(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md bg-sienna-400 text-white hover:bg-sienna-500 disabled:opacity-50 transition-colors duration-150`,disabled:x.isPending,onClick:D,children:x.isPending?`Saving...`:`Save`})]})]})]}),r&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:()=>a(null),onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-sm mx-4`,children:[(0,p.jsxs)(`div`,{className:`px-5 py-4`,children:[(0,p.jsx)(`h3`,{className:`text-base font-medium text-sand-900`,children:`Remove Token`}),(0,p.jsxs)(`p`,{className:`text-sm text-sand-700 mt-2`,children:[`Are you sure you want to remove`,` `,(0,p.jsx)(`code`,{className:`text-[13px] font-mono text-sand-800`,children:y(r)}),r.name&&(0,p.jsxs)(`span`,{className:`text-sand-500`,children:[` (`,r.name,`)`]}),`?`]})]}),(0,p.jsxs)(`div`,{className:`px-5 py-3 border-t border-sand-100/60 flex items-center justify-end gap-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:()=>a(null),children:`Cancel`}),(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 transition-colors duration-150`,disabled:b.isPending,onClick:T,children:b.isPending?`Removing...`:`Remove`})]})]})]})]})}function x(){let{data:e,isLoading:t}=a.useTokens(`A`);return(0,p.jsxs)(`div`,{className:`max-w-6xl mx-auto space-y-4`,children:[(0,p.jsx)(`div`,{className:`flex items-center justify-end`,children:(0,p.jsx)(m,{})}),(0,p.jsx)(b,{data:e?.rows,isLoading:t})]})}export{x as component};
1
+ import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{y as t}from"./vendor-tanstack-DJRQAbrY.js";import{i as n,r}from"./vendor-react-DH4kUfK2.js";import{n as i,o as a}from"./services.generated-CA7oRRYY.js";import{i as o,u as s}from"./index-BbOyk01G.js";import{n as c,r as l,t as u}from"./use-oauth-login-flow-OzmHElsE.js";import{t as d}from"./plus-DqBd6gHk.js";var f=e(n(),1),p=r();function m(){let[e,t]=(0,f.useState)(!1),[n,r]=(0,f.useState)(``),i=u(),a=()=>{t(!1),r(``),i.reset()},l=async e=>{await i.submitCode(e)&&a()};return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(`button`,{type:`button`,className:`px-3.5 py-1.5 text-[12px] font-medium rounded-lg bg-sienna-500 text-white hover:bg-sienna-600 disabled:opacity-50 transition-all duration-150 active:scale-[0.97] flex items-center gap-1.5 shadow-sm`,onClick:()=>t(!0),children:[(0,p.jsx)(d,{className:`size-3.5`}),`Add Token`]}),e&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:a,onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-md mx-4`,children:[(0,p.jsx)(`div`,{className:`px-5 py-4 border-b border-sand-100/50`,children:(0,p.jsx)(`h2`,{className:`text-base font-medium text-sand-900`,children:`Add Token`})}),(0,p.jsxs)(`div`,{className:`px-5 py-4 space-y-4`,children:[(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`label`,{htmlFor:`token-name`,className:`text-[10px] uppercase tracking-wider text-sand-500 font-medium`,children:`Name *`}),(0,p.jsx)(o,{value:n,onChange:e=>r(e.target.value),placeholder:`e.g. your-token-name`,className:`mt-1 w-full border border-sand-200 rounded-md px-3 py-2 text-sm text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`})]}),i.codeEntry?(0,p.jsx)(c,{isPending:i.completeMutation.isPending,isError:i.completeMutation.isError,onSubmit:e=>void l(e),onRestart:i.reset}):(0,p.jsxs)(`div`,{className:`space-y-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!n.trim()||i.loadingProvider!==null,onClick:()=>void i.start(`openai`,n),children:i.loadingProvider===`openai`?(0,p.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Waiting for login...`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(s,{className:`size-4`}),`Login with OpenAI`]})}),(0,p.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,p.jsx)(`div`,{className:`flex-1 h-px bg-sand-200`}),(0,p.jsx)(`span`,{className:`text-[10px] text-sand-400 uppercase`,children:`or`}),(0,p.jsx)(`div`,{className:`flex-1 h-px bg-sand-200`})]}),(0,p.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md border border-sand-300 text-sand-700 hover:bg-sand-100 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!n.trim()||i.loadingProvider!==null,onClick:()=>void i.start(`anthropic`,n),children:i.loadingProvider===`anthropic`?(0,p.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,p.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-sand-400 border-t-transparent rounded-full animate-spin`}),`Waiting for login...`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(s,{className:`size-4`}),`Login with Claude`]})})]})]}),(0,p.jsx)(`div`,{className:`px-5 py-3 border-t border-sand-100/50 flex items-center justify-end gap-2`,children:(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:a,children:`Cancel`})})]})]})]})}var h=e=>(0,p.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,p.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,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-.497zM15 5l4 4`})}),g=e=>(0,p.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`1.2em`,height:`1.2em`,...e,children:(0,p.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:2,d:`M10 11v6m4-6v6m5-11v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`})});function _(e){let t=e.credentials;return`expiresAt`in t&&typeof t.expiresAt==`number`?t.expiresAt:`accessTokenExpiresAt`in t&&typeof t.accessTokenExpiresAt==`number`?t.accessTokenExpiresAt:null}function v(e){if(!e)return{text:``,color:``};let t=e-Date.now();if(t<=0)return{text:`expired`,color:`text-red-500`};let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4),i=n>0?`${n}h ${r}m`:`${r}m`;return t<36e5?{text:i,color:`text-amber-500`}:{text:i,color:`text-sand-400`}}function y(e){let t=e.credentials.accessToken;return t.length<=12?t:`${t.slice(0,8)}...${t.slice(-4)}`}function b({data:e,isLoading:n}){let[r,a]=(0,f.useState)(null),[s,c]=(0,f.useState)(null),[u,d]=(0,f.useState)(``),m=t(),b=i.useRemoveTokenMutation(),x=l(),S=i.useToggleTokenMutation(),C=()=>Promise.all([m.invalidateQueries({queryKey:[`Token`]}),m.invalidateQueries({queryKey:[`Qgrid`]})]),w=async e=>{await S.mutateAsync({id:e.id}),await C()},T=async()=>{r&&(await b.mutateAsync({id:r.id}),await C(),a(null))},E=e=>{c(e),d(e.name??``)},D=async()=>{s&&(await x.mutateAsync({id:s.id,name:u.trim()}),await C(),c(null))};if(n)return(0,p.jsx)(`div`,{className:`space-y-2`,children:Array.from({length:3}).map((e,t)=>(0,p.jsx)(`div`,{className:`h-12 bg-sand-100 rounded-md animate-pulse`},`skeleton-${t}`))});let O=e??[];return O.length===0?(0,p.jsxs)(`div`,{className:`text-sand-400 text-center py-16 text-sm`,children:[`No tokens registered. Click `,(0,p.jsx)(`strong`,{className:`text-sand-600`,children:`Add Token`}),` to get started.`]}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(`div`,{className:`panel overflow-hidden`,children:(0,p.jsx)(`div`,{className:`overflow-x-auto`,children:(0,p.jsxs)(`table`,{className:`w-full min-w-[640px] text-[13px]`,children:[(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{className:`panel-header`,children:[(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Provider`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Name`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Token`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Status`}),(0,p.jsx)(`th`,{className:`text-left px-5 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium`,children:`Expires`}),(0,p.jsx)(`th`,{className:`w-20 px-3 py-2.5`})]})}),(0,p.jsx)(`tbody`,{className:`divide-y divide-sand-100/80`,children:O.map(e=>{let t=v(_(e));return(0,p.jsxs)(`tr`,{className:`transition-colors duration-150 hover:bg-sand-100/60 ${e.active?``:`opacity-50`}`,children:[(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`span`,{className:`text-xs font-medium text-sand-500 uppercase`,children:e.provider})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:e.name?(0,p.jsx)(`span`,{className:`text-sm text-sand-700`,children:e.name}):(0,p.jsx)(`span`,{className:`text-[11px] text-sand-400`,children:`—`})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`code`,{className:`text-[13px] font-mono text-sand-800`,children:y(e)})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:(0,p.jsx)(`button`,{type:`button`,className:`relative inline-flex h-5 w-9 items-center rounded-full transition-colors duration-200 ${e.active?`bg-sage-400`:`bg-sand-300`}`,onClick:()=>w(e),disabled:S.isPending,children:(0,p.jsx)(`span`,{className:`inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform duration-200 ${e.active?`translate-x-4.5`:`translate-x-0.5`}`})})}),(0,p.jsx)(`td`,{className:`px-5 py-3`,children:t.text&&(0,p.jsx)(`span`,{className:`text-xs ${t.color}`,children:t.text})}),(0,p.jsx)(`td`,{className:`px-3 py-3`,children:(0,p.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,p.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-sienna-500 transition-colors duration-150`,onClick:()=>E(e),children:(0,p.jsx)(h,{className:`size-4`})}),(0,p.jsx)(`button`,{type:`button`,className:`p-1 rounded text-sand-400 hover:text-red-500 transition-colors duration-150`,onClick:()=>a(e),children:(0,p.jsx)(g,{className:`size-4`})})]})})]},e.id)})})]})})}),s&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:()=>c(null),onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-sm mx-4`,children:[(0,p.jsx)(`div`,{className:`px-5 py-4 border-b border-sand-100/60`,children:(0,p.jsx)(`h3`,{className:`text-base font-medium text-sand-900`,children:`Edit Token`})}),(0,p.jsx)(`div`,{className:`px-5 py-4 space-y-3`,children:(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`label`,{htmlFor:`token-name`,className:`text-[10px] uppercase tracking-wider text-sand-500 font-medium`,children:`Name`}),(0,p.jsx)(o,{value:u,onChange:e=>d(e.target.value),placeholder:`e.g. prod, dev, team-a`,className:`mt-1 w-full border border-sand-200 rounded-md px-3 py-2 text-sm text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`})]})}),(0,p.jsxs)(`div`,{className:`px-5 py-3 border-t border-sand-100/60 flex items-center justify-end gap-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:()=>c(null),children:`Cancel`}),(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md bg-sienna-400 text-white hover:bg-sienna-500 disabled:opacity-50 transition-colors duration-150`,disabled:x.isPending,onClick:D,children:x.isPending?`Saving...`:`Save`})]})]})]}),r&&(0,p.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-start justify-center pt-[15vh]`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-sand-900/8 backdrop-blur-sm`,onClick:()=>a(null),onKeyDown:()=>{}}),(0,p.jsxs)(`div`,{className:`relative panel shadow-xl w-full max-w-sm mx-4`,children:[(0,p.jsxs)(`div`,{className:`px-5 py-4`,children:[(0,p.jsx)(`h3`,{className:`text-base font-medium text-sand-900`,children:`Remove Token`}),(0,p.jsxs)(`p`,{className:`text-sm text-sand-700 mt-2`,children:[`Are you sure you want to remove`,` `,(0,p.jsx)(`code`,{className:`text-[13px] font-mono text-sand-800`,children:y(r)}),r.name&&(0,p.jsxs)(`span`,{className:`text-sand-500`,children:[` (`,r.name,`)`]}),`?`]})]}),(0,p.jsxs)(`div`,{className:`px-5 py-3 border-t border-sand-100/60 flex items-center justify-end gap-2`,children:[(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md border border-sand-200 text-sand-600 hover:bg-sand-100 transition-colors duration-150`,onClick:()=>a(null),children:`Cancel`}),(0,p.jsx)(`button`,{type:`button`,className:`px-3 py-1 text-xs font-medium rounded-md bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 transition-colors duration-150`,disabled:b.isPending,onClick:T,children:b.isPending?`Removing...`:`Remove`})]})]})]})]})}function x(){let{data:e,isLoading:t}=a.useTokens(`A`);return(0,p.jsxs)(`div`,{className:`max-w-6xl mx-auto space-y-4`,children:[(0,p.jsx)(`div`,{className:`flex items-center justify-end`,children:(0,p.jsx)(m,{})}),(0,p.jsx)(b,{data:e?.rows,isLoading:t})]})}export{x as component};
@@ -1 +1 @@
1
- import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{m as t,y as n}from"./vendor-tanstack-DJRQAbrY.js";import{i as r,r as i}from"./vendor-react-DH4kUfK2.js";import{n as a}from"./services.generated-CA7oRRYY.js";import{i as o}from"./index-CPYQIUqO.js";function s(){return t({mutationFn:({id:e,name:t,quotaThreshold:n,weight:r})=>a.updateToken(e,t,n,r)})}var c=e(r(),1),l=i();function u({isPending:e,isError:t,onSubmit:n,onRestart:r}){let[i,a]=(0,c.useState)(``);return(0,l.jsxs)(`div`,{className:`space-y-2`,children:[(0,l.jsx)(`p`,{className:`text-[12px] text-sand-600 leading-relaxed`,children:`새 탭에서 Claude 로그인을 완료하면 코드가 표시됩니다. 코드 전체를 아래에 붙여넣으세요.`}),(0,l.jsx)(o,{value:i,onChange:e=>a(e.target.value),placeholder:`code#state`,className:`w-full border border-sand-200 rounded-md px-3 py-2 text-sm font-mono text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`}),t&&(0,l.jsx)(`p`,{className:`text-[11px] text-red-500`,children:`코드 확인에 실패했습니다 — 표시된 코드 전체를 다시 붙여넣거나 로그인을 다시 시작하세요.`}),(0,l.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!i.trim()||e,onClick:()=>n(i),children:e?(0,l.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,l.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Verifying...`]}):`Complete login`}),(0,l.jsx)(`button`,{type:`button`,className:`w-full py-1.5 text-[12px] text-sand-500 hover:text-sand-700 transition-colors duration-150`,onClick:()=>{a(``),r()},children:`처음부터 다시 시작`})]})}var d=3e3,f=3e5;function p(e){let t=0;for(let n of e.getQueryCache().findAll({queryKey:[`Token`]})){let e=n.state.data?.rows;Array.isArray(e)&&(t=Math.max(t,e.length))}return t}function m(){let[e,t]=(0,c.useState)(null),[r,i]=(0,c.useState)(!1),o=n(),s=a.useOauthStartMutation(),l=a.useOauthStartOpenAIMutation(),u=a.useOauthCompleteMutation(),m=(0,c.useRef)({}),h=()=>{m.current.interval!==void 0&&clearInterval(m.current.interval),m.current.timeout!==void 0&&clearTimeout(m.current.timeout),m.current={}};(0,c.useEffect)(()=>h,[]);let g=()=>Promise.all([o.invalidateQueries({queryKey:[`Token`]}),o.invalidateQueries({queryKey:[`Qgrid`]})]);return{loadingProvider:e,codeEntry:r,start:async(e,n)=>{let r=n.trim();if(!r)return;let a=window.open(`about:blank`,`_blank`);t(e);try{if(e===`openai`){let{authUrl:e}=await l.mutateAsync({name:r});a?a.location.href=e:window.open(e,`_blank`);let n=p(o);h(),m.current.interval=window.setInterval(()=>{g().then(()=>{p(o)>n&&(h(),t(null))})},d),m.current.timeout=window.setTimeout(()=>{h(),t(null)},f);return}let{authUrl:n,mode:c}=await s.mutateAsync({name:r});c===`code`?(a?a.location.href=n:window.open(n,`_blank`),i(!0),t(null)):(a?.close(),window.location.href=n)}catch(e){a?.close(),console.error(`OAuth start failed:`,e),t(null)}},submitCode:async e=>{let t=e.trim();if(!t)return!1;try{await u.mutateAsync({pastedCode:t})}catch(e){return console.error(`OAuth complete failed:`,e),!1}return await g(),!0},reset:()=>{h(),t(null),i(!1),u.reset()},completeMutation:u}}export{u as n,s as r,m as t};
1
+ import{r as e}from"./rolldown-runtime-Dw2cE7zH.js";import{m as t,y as n}from"./vendor-tanstack-DJRQAbrY.js";import{i as r,r as i}from"./vendor-react-DH4kUfK2.js";import{n as a}from"./services.generated-CA7oRRYY.js";import{i as o}from"./index-BbOyk01G.js";function s(){return t({mutationFn:({id:e,name:t,quotaThreshold:n,weight:r})=>a.updateToken(e,t,n,r)})}var c=e(r(),1),l=i();function u({isPending:e,isError:t,onSubmit:n,onRestart:r}){let[i,a]=(0,c.useState)(``);return(0,l.jsxs)(`div`,{className:`space-y-2`,children:[(0,l.jsx)(`p`,{className:`text-[12px] text-sand-600 leading-relaxed`,children:`새 탭에서 Claude 로그인을 완료하면 코드가 표시됩니다. 코드 전체를 아래에 붙여넣으세요.`}),(0,l.jsx)(o,{value:i,onChange:e=>a(e.target.value),placeholder:`code#state`,className:`w-full border border-sand-200 rounded-md px-3 py-2 text-sm font-mono text-sand-900 bg-white placeholder:text-sand-300 focus:outline-none focus:border-sienna-300`}),t&&(0,l.jsx)(`p`,{className:`text-[11px] text-red-500`,children:`코드 확인에 실패했습니다 — 표시된 코드 전체를 다시 붙여넣거나 로그인을 다시 시작하세요.`}),(0,l.jsx)(`button`,{type:`button`,className:`w-full py-2.5 text-sm font-medium rounded-md bg-sand-900 text-white hover:bg-sand-800 disabled:opacity-50 transition-colors duration-150 flex items-center justify-center gap-2`,disabled:!i.trim()||e,onClick:()=>n(i),children:e?(0,l.jsxs)(`span`,{className:`flex items-center gap-1.5`,children:[(0,l.jsx)(`span`,{className:`w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin`}),`Verifying...`]}):`Complete login`}),(0,l.jsx)(`button`,{type:`button`,className:`w-full py-1.5 text-[12px] text-sand-500 hover:text-sand-700 transition-colors duration-150`,onClick:()=>{a(``),r()},children:`처음부터 다시 시작`})]})}var d=3e3,f=3e5;function p(e){let t=0;for(let n of e.getQueryCache().findAll({queryKey:[`Token`]})){let e=n.state.data?.rows;Array.isArray(e)&&(t=Math.max(t,e.length))}return t}function m(){let[e,t]=(0,c.useState)(null),[r,i]=(0,c.useState)(!1),o=n(),s=a.useOauthStartMutation(),l=a.useOauthStartOpenAIMutation(),u=a.useOauthCompleteMutation(),m=(0,c.useRef)({}),h=()=>{m.current.interval!==void 0&&clearInterval(m.current.interval),m.current.timeout!==void 0&&clearTimeout(m.current.timeout),m.current={}};(0,c.useEffect)(()=>h,[]);let g=()=>Promise.all([o.invalidateQueries({queryKey:[`Token`]}),o.invalidateQueries({queryKey:[`Qgrid`]})]);return{loadingProvider:e,codeEntry:r,start:async(e,n)=>{let r=n.trim();if(!r)return;let a=window.open(`about:blank`,`_blank`);t(e);try{if(e===`openai`){let{authUrl:e}=await l.mutateAsync({name:r});a?a.location.href=e:window.open(e,`_blank`);let n=p(o);h(),m.current.interval=window.setInterval(()=>{g().then(()=>{p(o)>n&&(h(),t(null))})},d),m.current.timeout=window.setTimeout(()=>{h(),t(null)},f);return}let{authUrl:n,mode:c}=await s.mutateAsync({name:r});c===`code`?(a?a.location.href=n:window.open(n,`_blank`),i(!0),t(null)):(a?.close(),window.location.href=n)}catch(e){a?.close(),console.error(`OAuth start failed:`,e),t(null)}},submitCode:async e=>{let t=e.trim();if(!t)return!1;try{await u.mutateAsync({pastedCode:t})}catch(e){return console.error(`OAuth complete failed:`,e),!1}return await g(),!0},reset:()=>{h(),t(null),i(!1),u.reset()},completeMutation:u}}export{u as n,s as r,m as t};
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/sonamu.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Qgrid</title>
8
- <script type="module" crossorigin src="/assets/index-CPYQIUqO.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-BbOyk01G.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-Dw2cE7zH.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-ca-nBW7U.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-DH4kUfK2.js">
@@ -57,6 +57,7 @@ var lucideMinus = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg",
57
57
  //#endregion
58
58
  //#region src/components/qgrid/SettingsPanel.tsx
59
59
  var GROUP_LABELS = {
60
+ qgrid: "Qgrid",
60
61
  slack: "Slack 알림",
61
62
  slackConnection: "Slack 연결"
62
63
  };
@@ -1,4 +1,4 @@
1
- import { A as matchMutation, B as __require, C as infiniteQueryBehavior, D as functionalUpdate, E as notifyManager, F as skipToken, I as focusManager, L as Subscribable, M as noop$1, N as partialMatchKey, O as hashKey, P as resolveStaleTime, R as __commonJSMin, S as Mutation, T as onlineManager, V as __toESM, _ as useQuery, b as require_jsx_runtime, c as SD, d as _enum, f as number$1, j as matchQuery, k as hashQueryKeyByOptions, l as SUPPORTED_LOCALES, m as string$2, n as QgridService, p as object, u as setLocale, v as QueryClientProvider, w as Query, x as require_react, z as __exportAll } from "./assets/services.generated-B5UkNmgc.js";
1
+ import { A as matchMutation, B as __require, C as infiniteQueryBehavior, D as functionalUpdate, E as notifyManager, F as skipToken, I as focusManager, L as Subscribable, M as noop$1, N as partialMatchKey, O as hashKey, P as resolveStaleTime, R as __commonJSMin, S as Mutation, T as onlineManager, V as __toESM, b as require_jsx_runtime, c as SD, d as _enum, f as number$1, j as matchQuery, k as hashQueryKeyByOptions, l as SUPPORTED_LOCALES, m as string$2, n as QgridService, o as TokenService, p as object, u as setLocale, v as QueryClientProvider, w as Query, x as require_react, z as __exportAll } from "./assets/services.generated-B5UkNmgc.js";
2
2
  import { A as decodePath, C as findRouteMatch, D as createLRUCache, E as processRouteTree, F as last, I as replaceEqualDeep, M as findLast, N as functionalUpdate$1, O as invariant, P as isPromise, S as findFlatMatch, T as processRouteMasks, _ as interpolatePath, a as Link$1, b as trimPath, c as usePrevious$1, d as useRouter, f as getRouterContext, g as cleanPath, h as isNotFound, i as createRootRouteWithContext, j as deepEqual$2, k as createControlledPromise, l as matchContext, m as rootRouteId, n as createFileRoute, p as warning, r as createLazyFileRoute, s as useLayoutEffect$3, t as lazyRouteComponent, u as useRouterState, v as joinPaths, w as findSingleMatch, x as trimPathRight, y as resolvePath } from "./assets/lazyRouteComponent-tS-rTksX.js";
3
3
  import { n as require_shim, t as require_react_dom } from "./assets/react-dom-7_SqhNWR.js";
4
4
  import minpath from "node:path";
@@ -46060,6 +46060,24 @@ var lucideX = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
46060
46060
  //#region src/assets/chat-icon.png
46061
46061
  var chat_icon_default = "/assets/chat-icon-JYfue7fB.png";
46062
46062
  //#endregion
46063
+ //#region src/components/qgrid/chat-token-selection.ts
46064
+ function chatTokenOptions(tokens, provider) {
46065
+ return tokens.filter((token) => token.active && token.provider === provider).toSorted((a, b) => a.ord - b.ord || a.name.localeCompare(b.name));
46066
+ }
46067
+ function providerTokenMissing(tokens, provider) {
46068
+ return provider !== void 0 && !tokens.some((token) => token.active && token.provider === provider);
46069
+ }
46070
+ function resolvedTokenName(tokenName, options, tokenListLoaded) {
46071
+ if (!tokenName || !tokenListLoaded) return tokenName;
46072
+ return options.some((token) => token.name === tokenName) ? tokenName : "";
46073
+ }
46074
+ function chatConfigChanged(previous, current) {
46075
+ return previous.model !== current.model || previous.system !== current.system || previous.tokenName !== current.tokenName;
46076
+ }
46077
+ function tokenTargetPayload(tokenName) {
46078
+ return tokenName ? { tokenName } : {};
46079
+ }
46080
+ //#endregion
46063
46081
  //#region src/components/qgrid/ChatWidget.tsx
46064
46082
  var CHAT_PROJECT_NAME = "qgrid_chat";
46065
46083
  var DEFAULT_MODEL = "openai/gpt-5.6-terra";
@@ -46104,9 +46122,9 @@ var PROVIDER_LABELS = {
46104
46122
  openai: "OpenAI",
46105
46123
  anthropic: "Anthropic"
46106
46124
  };
46107
- function humanizeError(message, provider, stats) {
46108
- const providerTokenMissing = provider !== void 0 && stats !== void 0 && !stats.some((t) => t.provider === provider);
46109
- if (/NO_OPENAI_WORKERS|no ready openai workers|no anthropic tokens available/i.test(message) || providerTokenMissing && /기동 중입니다/.test(message)) return `사용 가능한 ${provider ? PROVIDER_LABELS[provider] ?? provider : ""} 토큰이 없습니다. Tokens 페이지에서 토큰을 추가해주세요.`;
46125
+ function humanizeError(message, provider, tokens) {
46126
+ const missing = tokens !== void 0 && providerTokenMissing(tokens, provider);
46127
+ if (/NO_OPENAI_WORKERS|no ready openai workers|no anthropic tokens available/i.test(message) || missing && /기동 중입니다/.test(message)) return `사용 가능한 ${provider ? PROVIDER_LABELS[provider] ?? provider : ""} 토큰이 없습니다. Tokens 페이지에서 토큰을 추가해주세요.`;
46110
46128
  return message;
46111
46129
  }
46112
46130
  function formatCost(costUsd) {
@@ -46130,6 +46148,7 @@ function ChatWidget() {
46130
46148
  const [messages, setMessages] = (0, import_react.useState)([]);
46131
46149
  const [draft, setDraft] = (0, import_react.useState)("");
46132
46150
  const [model, setModel] = (0, import_react.useState)(DEFAULT_MODEL);
46151
+ const [tokenName, setTokenName] = (0, import_react.useState)("");
46133
46152
  const [effort, setEffort] = (0, import_react.useState)("");
46134
46153
  const [system, setSystem] = (0, import_react.useState)("");
46135
46154
  const [settingsOpen, setSettingsOpen] = (0, import_react.useState)(false);
@@ -46143,19 +46162,20 @@ function ChatWidget() {
46143
46162
  const fileInputRef = (0, import_react.useRef)(null);
46144
46163
  const provider = model.split("/")[0];
46145
46164
  const supportsImages = provider === "openai";
46146
- const { data: tokenStats } = useQuery({
46147
- ...QgridService.statsQueryOptions(),
46148
- enabled: open,
46149
- staleTime: 15e3
46150
- });
46151
- const statsRef = (0, import_react.useRef)(void 0);
46165
+ const { data: tokensData } = TokenService.useTokens("A", { orderBy: "ord-asc" }, { enabled: open });
46166
+ const tokenOptions = (0, import_react.useMemo)(() => chatTokenOptions(tokensData?.rows ?? [], provider), [provider, tokensData?.rows]);
46167
+ const tokenListLoaded = tokensData?.rows !== void 0;
46168
+ const tokensRef = (0, import_react.useRef)(void 0);
46152
46169
  (0, import_react.useEffect)(() => {
46153
- statsRef.current = tokenStats;
46154
- }, [tokenStats]);
46155
- const providerTokenMissing = tokenStats !== void 0 && !tokenStats.some((t) => t.provider === provider);
46170
+ tokensRef.current = tokensData?.rows;
46171
+ }, [tokensData?.rows]);
46172
+ const selectedProviderMissing = tokensData?.rows !== void 0 && providerTokenMissing(tokensData.rows, provider);
46156
46173
  (0, import_react.useEffect)(() => {
46157
46174
  if (!supportsImages) setAttachments([]);
46158
46175
  }, [supportsImages]);
46176
+ (0, import_react.useEffect)(() => {
46177
+ setTokenName((current) => resolvedTokenName(current, tokenOptions, tokenListLoaded));
46178
+ }, [tokenListLoaded, tokenOptions]);
46159
46179
  const addAttachments = async (files) => {
46160
46180
  if (!files) return;
46161
46181
  const slots = MAX_ATTACHMENTS - attachments.length;
@@ -46170,7 +46190,7 @@ function ChatWidget() {
46170
46190
  });
46171
46191
  };
46172
46192
  const failStreaming = (message) => {
46173
- const friendly = humanizeError(message, lastConfigRef.current?.model.split("/")[0], statsRef.current);
46193
+ const friendly = humanizeError(message, lastConfigRef.current?.model.split("/")[0], tokensRef.current);
46174
46194
  patchLastAssistant((m) => m.status === "streaming" ? {
46175
46195
  ...m,
46176
46196
  status: "error",
@@ -46234,11 +46254,14 @@ function ChatWidget() {
46234
46254
  const prompt = draft.trim();
46235
46255
  if (!prompt || busy) return;
46236
46256
  const sys = system.trim();
46237
- if (lastConfigRef.current && (lastConfigRef.current.model !== model || lastConfigRef.current.system !== sys)) threadCoordRef.current = void 0;
46238
- lastConfigRef.current = {
46257
+ const selectedTokenName = resolvedTokenName(tokenName, tokenOptions, tokenListLoaded);
46258
+ const currentConfig = {
46239
46259
  model,
46240
- system: sys
46260
+ system: sys,
46261
+ tokenName: selectedTokenName
46241
46262
  };
46263
+ if (lastConfigRef.current && chatConfigChanged(lastConfigRef.current, currentConfig)) threadCoordRef.current = void 0;
46264
+ lastConfigRef.current = currentConfig;
46242
46265
  const images = supportsImages ? attachments : [];
46243
46266
  const history = buildHistory(messages);
46244
46267
  setMessages((prev) => [
@@ -46262,6 +46285,7 @@ function ChatWidget() {
46262
46285
  prompt,
46263
46286
  model,
46264
46287
  projectName: CHAT_PROJECT_NAME,
46288
+ ...tokenTargetPayload(selectedTokenName),
46265
46289
  ...sys ? { system: sys } : {},
46266
46290
  ...effort ? { effort } : {},
46267
46291
  ...images.length > 0 ? { input: images.map((url) => ({
@@ -46317,7 +46341,11 @@ function ChatWidget() {
46317
46341
  children: "채팅"
46318
46342
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
46319
46343
  className: "text-[11px] text-sand-400 truncate leading-tight",
46320
- children: [model, effort ? ` · ${effort}` : ""]
46344
+ children: [
46345
+ model,
46346
+ effort ? ` · ${effort}` : "",
46347
+ tokenName ? ` · ${tokenName}` : ""
46348
+ ]
46321
46349
  })]
46322
46350
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
46323
46351
  className: "ml-auto flex items-center gap-0.5",
@@ -46325,7 +46353,7 @@ function ChatWidget() {
46325
46353
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
46326
46354
  type: "button",
46327
46355
  onClick: () => setSettingsOpen((v) => !v),
46328
- title: "모델·effort·system prompt 설정",
46356
+ title: "모델·토큰·effort·system prompt 설정",
46329
46357
  className: `size-8 grid place-items-center rounded-full transition-colors duration-150 ${settingsOpen ? "text-sienna-500 bg-sienna-50" : "text-sand-500 hover:text-sand-700 hover:bg-sand-100"}`,
46330
46358
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideSlidersHorizontal, { className: "size-4" })
46331
46359
  }),
@@ -46349,38 +46377,55 @@ function ChatWidget() {
46349
46377
  }),
46350
46378
  settingsOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
46351
46379
  className: "px-4 py-2.5 border-b border-sand-100 bg-sand-50/60 shrink-0 flex flex-col gap-1.5",
46352
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
46353
- className: "flex items-center gap-1.5",
46354
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", {
46355
- value: model,
46356
- onChange: (e) => setModel(e.target.value),
46357
- disabled: busy,
46358
- className: "min-w-0 flex-1 rounded-xl border border-sand-200/80 bg-white px-2 py-1.5 text-[12px] text-sand-800 focus:outline-none focus:border-sienna-300 disabled:opacity-50",
46359
- children: MODEL_PRESETS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
46360
- value: m,
46361
- children: m
46362
- }, m))
46363
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
46364
- value: effort,
46365
- onChange: (e) => setEffort(e.target.value),
46380
+ children: [
46381
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
46382
+ className: "flex items-center gap-1.5",
46383
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", {
46384
+ value: model,
46385
+ onChange: (e) => setModel(e.target.value),
46386
+ disabled: busy,
46387
+ className: "min-w-0 flex-1 rounded-xl border border-sand-200/80 bg-white px-2 py-1.5 text-[12px] text-sand-800 focus:outline-none focus:border-sienna-300 disabled:opacity-50",
46388
+ children: MODEL_PRESETS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
46389
+ value: m,
46390
+ children: m
46391
+ }, m))
46392
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
46393
+ value: effort,
46394
+ onChange: (e) => setEffort(e.target.value),
46395
+ disabled: busy,
46396
+ className: "rounded-xl border border-sand-200/80 bg-white px-2 py-1.5 text-[12px] text-sand-600 focus:outline-none focus:border-sienna-300 disabled:opacity-50",
46397
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
46398
+ value: "",
46399
+ children: "effort 기본"
46400
+ }), EFFORT_PRESETS.map((v) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
46401
+ value: v,
46402
+ children: v
46403
+ }, v))]
46404
+ })]
46405
+ }),
46406
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
46407
+ value: tokenName,
46408
+ onChange: (e) => setTokenName(e.target.value),
46366
46409
  disabled: busy,
46367
- className: "rounded-xl border border-sand-200/80 bg-white px-2 py-1.5 text-[12px] text-sand-600 focus:outline-none focus:border-sienna-300 disabled:opacity-50",
46410
+ "aria-label": "요청 토큰",
46411
+ className: "w-full rounded-xl border border-sand-200/80 bg-white px-2 py-1.5 text-[12px] text-sand-700 focus:outline-none focus:border-sienna-300 disabled:opacity-50",
46368
46412
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
46369
46413
  value: "",
46370
- children: "effort 기본"
46371
- }), EFFORT_PRESETS.map((v) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
46372
- value: v,
46373
- children: v
46374
- }, v))]
46375
- })]
46376
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
46377
- value: system,
46378
- onChange: (e) => setSystem(e.target.value),
46379
- disabled: busy,
46380
- placeholder: "system prompt (선택)",
46381
- rows: 2,
46382
- className: "w-full resize-none rounded-xl border border-sand-200/80 bg-white px-2.5 py-1.5 text-[12px] text-sand-800 placeholder:text-sand-400 focus:outline-none focus:border-sienna-300 disabled:opacity-50"
46383
- })]
46414
+ children: "토큰 자동 분배"
46415
+ }), tokenOptions.map((token) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
46416
+ value: token.name,
46417
+ children: token.name
46418
+ }, token.name))]
46419
+ }),
46420
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
46421
+ value: system,
46422
+ onChange: (e) => setSystem(e.target.value),
46423
+ disabled: busy,
46424
+ placeholder: "system prompt (선택)",
46425
+ rows: 2,
46426
+ className: "w-full resize-none rounded-xl border border-sand-200/80 bg-white px-2.5 py-1.5 text-[12px] text-sand-800 placeholder:text-sand-400 focus:outline-none focus:border-sienna-300 disabled:opacity-50"
46427
+ })
46428
+ ]
46384
46429
  }),
46385
46430
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
46386
46431
  ref: scrollRef,
@@ -46480,7 +46525,7 @@ function ChatWidget() {
46480
46525
  }, i))
46481
46526
  })
46482
46527
  }),
46483
- providerTokenMissing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
46528
+ selectedProviderMissing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
46484
46529
  className: "px-4 py-1.5 border-t border-caution-400/30 bg-caution-400/10 text-[11px] text-caution-500 shrink-0",
46485
46530
  children: [
46486
46531
  PROVIDER_LABELS[provider] ?? provider,
@@ -46580,7 +46625,7 @@ function ChatWidget() {
46580
46625
  }
46581
46626
  //#endregion
46582
46627
  //#region src/components/Sidebar.tsx
46583
- var qgridVersion = "2.7.4";
46628
+ var qgridVersion = "2.7.6";
46584
46629
  function Sidebar({ className }) {
46585
46630
  const pathname = useRouterState({ select: (s) => s.location.pathname });
46586
46631
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
@@ -68469,7 +68514,7 @@ var $$splitComponentImporter$5 = () => import("./assets/tokens-BwlkZELV.js");
68469
68514
  var Route$5 = createFileRoute("/tokens")({ component: lazyRouteComponent($$splitComponentImporter$5, "component") });
68470
68515
  //#endregion
68471
68516
  //#region src/routes/settings.tsx
68472
- var $$splitComponentImporter$4 = () => import("./assets/settings-nCv71sax.js");
68517
+ var $$splitComponentImporter$4 = () => import("./assets/settings-CIYR7h3G.js");
68473
68518
  var Route$4 = createFileRoute("/settings")({ component: lazyRouteComponent($$splitComponentImporter$4, "component") });
68474
68519
  //#endregion
68475
68520
  //#region src/routes/monit.tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cartanova/qgrid-cli",
3
- "version": "2.7.4",
3
+ "version": "2.7.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cartanova-ai/qgrid"
@@ -21,6 +21,7 @@
21
21
  "@ai-sdk/provider": "^3.0.0",
22
22
  "@ai-sdk/provider-utils": "^4.0.0",
23
23
  "@anthropic-ai/sdk": "^0.81.0",
24
+ "@better-auth/core": "~1.6.0",
24
25
  "@better-auth/passkey": "~1.6.0",
25
26
  "@better-auth/sso": "~1.6.0",
26
27
  "@logtape/logtape": "2.0.0",
@@ -29,7 +30,7 @@
29
30
  "@oxc-project/runtime": "^0.79.0",
30
31
  "ai": "^6.0.1",
31
32
  "bcrypt": "^6.0.0",
32
- "better-auth": "^1.6.0",
33
+ "better-auth": "~1.6.0",
33
34
  "chalk": "^4.1.2",
34
35
  "commander": "^13.0.0",
35
36
  "date-fns": "^4.1.0",