@nextclaw/ui 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/assets/{ChannelsList-DhvjpZcs.js → ChannelsList-DKD6Llid.js} +1 -1
  3. package/dist/assets/ChatPage-BK9X4Tin.js +38 -0
  4. package/dist/assets/{DocBrowser-LpzGe8An.js → DocBrowser-CVwUDJMO.js} +1 -1
  5. package/dist/assets/{LogoBadge-Be4lktJN.js → LogoBadge-CYQ_b7jk.js} +1 -1
  6. package/dist/assets/{MarketplacePage-Cx9AI3_h.js → MarketplacePage-B_2z3ii_.js} +1 -1
  7. package/dist/assets/{ModelConfig-DuImUHIX.js → ModelConfig-CsX-_fyy.js} +1 -1
  8. package/dist/assets/{ProvidersList-Ccleg25k.js → ProvidersList-CZstsyv7.js} +1 -1
  9. package/dist/assets/{RuntimeConfig-C6iqpJR_.js → RuntimeConfig-CX2TGEG1.js} +1 -1
  10. package/dist/assets/{SearchConfig-Dvp1TAXu.js → SearchConfig-C-WBTcWi.js} +1 -1
  11. package/dist/assets/{SecretsConfig-D5Ymlvt9.js → SecretsConfig-9kbR0ZCB.js} +1 -1
  12. package/dist/assets/{SessionsConfig-CIA_jA1P.js → SessionsConfig-Bohn3P1q.js} +1 -1
  13. package/dist/assets/{chat-message-B60Fh9kI.js → chat-message-AWIcksDK.js} +1 -1
  14. package/dist/assets/{index-BiPDnzv0.js → index-BEgClaDH.js} +2 -2
  15. package/dist/assets/{label-D4fGx6Wb.js → label-DD61y-4v.js} +1 -1
  16. package/dist/assets/{page-layout-twy8gmBE.js → page-layout-CfnoVycc.js} +1 -1
  17. package/dist/assets/{popover-DYbYpt1j.js → popover-DsugZ6rp.js} +1 -1
  18. package/dist/assets/{security-config-BcIZ4rpb.js → security-config-DIrf2Z0O.js} +1 -1
  19. package/dist/assets/{skeleton-DypBy7jp.js → skeleton-DJ-Wen2o.js} +1 -1
  20. package/dist/assets/{switch-DqA6r5XR.js → switch-NX5OmUXQ.js} +1 -1
  21. package/dist/assets/{tabs-custom-C6enKKs1.js → tabs-custom-9ihB5Jem.js} +1 -1
  22. package/dist/assets/{useConfirmDialog-CHBf5Of7.js → useConfirmDialog-BuQnVTeR.js} +1 -1
  23. package/dist/index.html +1 -1
  24. package/package.json +4 -4
  25. package/src/api/types.ts +63 -3
  26. package/src/components/chat/chat-page-data.ts +1 -15
  27. package/src/components/chat/chat-page-runtime.test.ts +26 -0
  28. package/src/components/chat/chat-page-runtime.ts +21 -4
  29. package/src/components/chat/legacy/LegacyChatPage.tsx +0 -15
  30. package/src/components/chat/ncp/NcpChatPage.tsx +0 -15
  31. package/src/components/chat/ncp/ncp-chat-page-data.ts +1 -15
  32. package/dist/assets/ChatPage-B8VBaMQm.js +0 -38
@@ -1 +1 @@
1
- import{r as c,j as e,e as M}from"./vendor-DKBNiC31.js";import{a6 as O,a7 as R,a8 as I,a9 as B,aa as _,C as u,a3 as h,a4 as x,t as s,a5 as m,z as p,B as j,I as l}from"./index-BiPDnzv0.js";import{L as o}from"./label-D4fGx6Wb.js";import{S as z}from"./switch-DqA6r5XR.js";import{P as G,a as V}from"./page-layout-twy8gmBE.js";const W=8;function A(r){return r.trim().length>=W}function L(r,n){return r!==n?(M.error(s("authPasswordMismatch")),!1):!0}function q(){const r=O(),n=R(),S=I(),g=B(),y=_(),[f,U]=c.useState(""),[i,N]=c.useState(""),[w,b]=c.useState(""),[d,v]=c.useState(""),[P,C]=c.useState(""),t=r.data,E=f.trim().length>0&&A(i)&&i===w&&!n.isPending,D=A(d)&&d===P&&!g.isPending,T=async()=>{if(L(i,w))try{await n.mutateAsync({username:f.trim(),password:i}),N(""),b("")}catch{}},F=async()=>{if(L(d,P))try{await g.mutateAsync({password:d}),v(""),C("")}catch{}},H=async a=>{try{await S.mutateAsync({enabled:a})}catch{}},k=async()=>{try{await y.mutateAsync()}catch{}};return r.isLoading&&!t?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsx(p,{className:"text-sm text-gray-500",children:s("loading")})]}):r.isError||!t?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-gray-500",children:s("authStatusLoadFailed")}),e.jsx(j,{variant:"outline",onClick:()=>{r.refetch()},children:s("authRetryStatus")})]})]}):t.configured?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-6",children:[e.jsxs("div",{className:"rounded-xl border border-gray-200 p-4",children:[e.jsxs("div",{className:"flex flex-col gap-4 md:flex-row md:items-start md:justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authStatusLabel")}),e.jsx("p",{className:"text-sm text-gray-600",children:s("authStatusConfiguredUser").replace("{username}",t.username??"")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authUsernameFixedHelp")})]}),e.jsx("span",{className:"inline-flex items-center rounded-full bg-gray-100 px-3 py-1 text-xs font-medium text-gray-700",children:t.enabled?s("enabled"):s("disabled")})]}),e.jsxs("div",{className:"mt-4 flex flex-col gap-4 border-t border-gray-200 pt-4 md:flex-row md:items-center md:justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authEnableLabel")}),e.jsx("p",{className:"text-xs text-gray-500",children:t.enabled?s("authEnableOnHelp"):s("authEnableOffHelp")})]}),e.jsx(z,{checked:t.enabled,disabled:S.isPending,onCheckedChange:a=>{H(a)}})]})]}),e.jsxs("div",{className:"rounded-xl border border-gray-200 p-4 space-y-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authPasswordSectionTitle")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authPasswordSectionDescription")})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-password-next",children:s("authPassword")}),e.jsx(l,{id:"auth-password-next",type:"password",value:d,onChange:a=>v(a.target.value),placeholder:s("authPasswordPlaceholder")})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-password-confirm",children:s("authConfirmPassword")}),e.jsx(l,{id:"auth-password-confirm",type:"password",value:P,onChange:a=>C(a.target.value),placeholder:s("authConfirmPasswordPlaceholder")})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx(j,{type:"button",disabled:!D,onClick:()=>void F(),children:g.isPending?s("authPasswordUpdating"):s("authPasswordAction")}),t.enabled&&t.authenticated?e.jsx(j,{type:"button",variant:"outline",disabled:y.isPending,onClick:()=>void k(),children:y.isPending?s("authLoggingOut"):s("authLogoutAction")}):null]}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authSessionMemoryNotice")})]})]})]}):e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-5",children:[e.jsxs("div",{className:"rounded-xl border border-dashed border-gray-200 bg-gray-50/70 p-4",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authSetupTitle")}),e.jsx("p",{className:"mt-1 text-sm text-gray-500",children:s("authSetupDescription")})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-username",children:s("authUsername")}),e.jsx(l,{id:"auth-setup-username",value:f,onChange:a=>U(a.target.value),placeholder:s("authUsernamePlaceholder")})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-password",children:s("authPassword")}),e.jsx(l,{id:"auth-setup-password",type:"password",value:i,onChange:a=>N(a.target.value),placeholder:s("authPasswordPlaceholder")})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-confirm",children:s("authConfirmPassword")}),e.jsx(l,{id:"auth-setup-confirm",type:"password",value:w,onChange:a=>b(a.target.value),placeholder:s("authConfirmPasswordPlaceholder")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authPasswordMinLengthHint")})]}),e.jsx(j,{type:"button",disabled:!E,onClick:()=>void T(),children:n.isPending?s("authSettingUp"):s("authSetupAction")})]})]})}function Z(){return e.jsxs(G,{className:"space-y-6",children:[e.jsx(V,{title:s("authSecurityTitle"),description:s("authSecurityDescription")}),e.jsx(q,{})]})}export{Z as SecurityConfig};
1
+ import{r as c,j as e,e as M}from"./vendor-DKBNiC31.js";import{a6 as O,a7 as R,a8 as I,a9 as B,aa as _,C as u,a3 as h,a4 as x,t as s,a5 as m,z as p,B as j,I as l}from"./index-BEgClaDH.js";import{L as o}from"./label-DD61y-4v.js";import{S as z}from"./switch-NX5OmUXQ.js";import{P as G,a as V}from"./page-layout-CfnoVycc.js";const W=8;function A(r){return r.trim().length>=W}function L(r,n){return r!==n?(M.error(s("authPasswordMismatch")),!1):!0}function q(){const r=O(),n=R(),S=I(),g=B(),y=_(),[f,U]=c.useState(""),[i,N]=c.useState(""),[w,b]=c.useState(""),[d,v]=c.useState(""),[P,C]=c.useState(""),t=r.data,E=f.trim().length>0&&A(i)&&i===w&&!n.isPending,D=A(d)&&d===P&&!g.isPending,T=async()=>{if(L(i,w))try{await n.mutateAsync({username:f.trim(),password:i}),N(""),b("")}catch{}},F=async()=>{if(L(d,P))try{await g.mutateAsync({password:d}),v(""),C("")}catch{}},H=async a=>{try{await S.mutateAsync({enabled:a})}catch{}},k=async()=>{try{await y.mutateAsync()}catch{}};return r.isLoading&&!t?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsx(p,{className:"text-sm text-gray-500",children:s("loading")})]}):r.isError||!t?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-gray-500",children:s("authStatusLoadFailed")}),e.jsx(j,{variant:"outline",onClick:()=>{r.refetch()},children:s("authRetryStatus")})]})]}):t.configured?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-6",children:[e.jsxs("div",{className:"rounded-xl border border-gray-200 p-4",children:[e.jsxs("div",{className:"flex flex-col gap-4 md:flex-row md:items-start md:justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authStatusLabel")}),e.jsx("p",{className:"text-sm text-gray-600",children:s("authStatusConfiguredUser").replace("{username}",t.username??"")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authUsernameFixedHelp")})]}),e.jsx("span",{className:"inline-flex items-center rounded-full bg-gray-100 px-3 py-1 text-xs font-medium text-gray-700",children:t.enabled?s("enabled"):s("disabled")})]}),e.jsxs("div",{className:"mt-4 flex flex-col gap-4 border-t border-gray-200 pt-4 md:flex-row md:items-center md:justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authEnableLabel")}),e.jsx("p",{className:"text-xs text-gray-500",children:t.enabled?s("authEnableOnHelp"):s("authEnableOffHelp")})]}),e.jsx(z,{checked:t.enabled,disabled:S.isPending,onCheckedChange:a=>{H(a)}})]})]}),e.jsxs("div",{className:"rounded-xl border border-gray-200 p-4 space-y-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authPasswordSectionTitle")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authPasswordSectionDescription")})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-password-next",children:s("authPassword")}),e.jsx(l,{id:"auth-password-next",type:"password",value:d,onChange:a=>v(a.target.value),placeholder:s("authPasswordPlaceholder")})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-password-confirm",children:s("authConfirmPassword")}),e.jsx(l,{id:"auth-password-confirm",type:"password",value:P,onChange:a=>C(a.target.value),placeholder:s("authConfirmPasswordPlaceholder")})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx(j,{type:"button",disabled:!D,onClick:()=>void F(),children:g.isPending?s("authPasswordUpdating"):s("authPasswordAction")}),t.enabled&&t.authenticated?e.jsx(j,{type:"button",variant:"outline",disabled:y.isPending,onClick:()=>void k(),children:y.isPending?s("authLoggingOut"):s("authLogoutAction")}):null]}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authSessionMemoryNotice")})]})]})]}):e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-5",children:[e.jsxs("div",{className:"rounded-xl border border-dashed border-gray-200 bg-gray-50/70 p-4",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authSetupTitle")}),e.jsx("p",{className:"mt-1 text-sm text-gray-500",children:s("authSetupDescription")})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-username",children:s("authUsername")}),e.jsx(l,{id:"auth-setup-username",value:f,onChange:a=>U(a.target.value),placeholder:s("authUsernamePlaceholder")})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-password",children:s("authPassword")}),e.jsx(l,{id:"auth-setup-password",type:"password",value:i,onChange:a=>N(a.target.value),placeholder:s("authPasswordPlaceholder")})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-confirm",children:s("authConfirmPassword")}),e.jsx(l,{id:"auth-setup-confirm",type:"password",value:w,onChange:a=>b(a.target.value),placeholder:s("authConfirmPasswordPlaceholder")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authPasswordMinLengthHint")})]}),e.jsx(j,{type:"button",disabled:!E,onClick:()=>void T(),children:n.isPending?s("authSettingUp"):s("authSetupAction")})]})]})}function Z(){return e.jsxs(G,{className:"space-y-6",children:[e.jsx(V,{title:s("authSecurityTitle"),description:s("authSecurityDescription")}),e.jsx(q,{})]})}export{Z as SecurityConfig};
@@ -1 +1 @@
1
- import{j as t}from"./vendor-DKBNiC31.js";import{c as o}from"./index-BiPDnzv0.js";function m({className:e,...s}){return t.jsx("div",{className:o("animate-pulse rounded-md bg-slate-200",e),...s})}export{m as S};
1
+ import{j as t}from"./vendor-DKBNiC31.js";import{c as o}from"./index-BEgClaDH.js";function m({className:e,...s}){return t.jsx("div",{className:o("animate-pulse rounded-md bg-slate-200",e),...s})}export{m as S};
@@ -1 +1 @@
1
- import{r as e,j as i}from"./vendor-DKBNiC31.js";import{c as t}from"./index-BiPDnzv0.js";const l=e.forwardRef(({className:o,checked:r=!1,onCheckedChange:s,...a},n)=>i.jsx("button",{type:"button",role:"switch","aria-checked":r,ref:n,className:t("peer inline-flex h-[22px] w-10 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-fast focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-50",r?"bg-primary":"bg-gray-200/80 hover:bg-gray-300/80",o),onClick:()=>s==null?void 0:s(!r),...a,children:i.jsx("span",{className:t("pointer-events-none block h-5 w-5 rounded-full bg-white shadow-md ring-0 transition-transform duration-fast",r?"translate-x-5":"translate-x-0")})}));l.displayName="Switch";export{l as S};
1
+ import{r as e,j as i}from"./vendor-DKBNiC31.js";import{c as t}from"./index-BEgClaDH.js";const l=e.forwardRef(({className:o,checked:r=!1,onCheckedChange:s,...a},n)=>i.jsx("button",{type:"button",role:"switch","aria-checked":r,ref:n,className:t("peer inline-flex h-[22px] w-10 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-fast focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-50",r?"bg-primary":"bg-gray-200/80 hover:bg-gray-300/80",o),onClick:()=>s==null?void 0:s(!r),...a,children:i.jsx("span",{className:t("pointer-events-none block h-5 w-5 rounded-full bg-white shadow-md ring-0 transition-transform duration-fast",r?"translate-x-5":"translate-x-0")})}));l.displayName="Switch";export{l as S};
@@ -1 +1 @@
1
- import{j as e}from"./vendor-DKBNiC31.js";import{ag as m,c as a}from"./index-BiPDnzv0.js";function c({tabs:s,activeTab:i,onChange:o,className:n}){return e.jsx("div",{className:a("flex items-center gap-6 border-b border-gray-200/60 mb-6",n),children:s.map(t=>{const r=i===t.id;return e.jsxs("button",{onClick:()=>o(t.id),className:a("relative pb-3 text-[14px] font-medium transition-all duration-fast flex items-center gap-1.5",r?"text-gray-900":"text-gray-600 hover:text-gray-900"),children:[t.label,t.count!==void 0&&e.jsx("span",{className:a("text-[11px] font-medium","text-gray-500"),children:m(t.count)}),r&&e.jsx("div",{className:"absolute bottom-0 left-0 right-0 h-[2px] bg-primary rounded-full"})]},t.id)})})}export{c as T};
1
+ import{j as e}from"./vendor-DKBNiC31.js";import{ag as m,c as a}from"./index-BEgClaDH.js";function c({tabs:s,activeTab:i,onChange:o,className:n}){return e.jsx("div",{className:a("flex items-center gap-6 border-b border-gray-200/60 mb-6",n),children:s.map(t=>{const r=i===t.id;return e.jsxs("button",{onClick:()=>o(t.id),className:a("relative pb-3 text-[14px] font-medium transition-all duration-fast flex items-center gap-1.5",r?"text-gray-900":"text-gray-600 hover:text-gray-900"),children:[t.label,t.count!==void 0&&e.jsx("span",{className:a("text-[11px] font-medium","text-gray-500"),children:m(t.count)}),r&&e.jsx("div",{className:"absolute bottom-0 left-0 right-0 h-[2px] bg-primary rounded-full"})]},t.id)})})}export{c as T};
@@ -1,4 +1,4 @@
1
- import{r as i,az as ee,j as a,aB as N,aH as te,aD as D,aE as v,aI as oe,aC as b,aJ as ae,aK as ne,aM as re,aN as se,aO as ie,aL as le,a_ as ce,aw as de}from"./vendor-DKBNiC31.js";import{P as R}from"./index-CPDASUXh.js";import{c as m,B as P,t as p}from"./index-BiPDnzv0.js";var C="Dialog",[O]=oe(C),[ue,u]=O(C),I=e=>{const{__scopeDialog:o,children:n,open:r,defaultOpen:s,onOpenChange:t,modal:l=!0}=e,c=i.useRef(null),d=i.useRef(null),[f,x]=ee({prop:r,defaultProp:s??!1,onChange:t,caller:C});return a.jsx(ue,{scope:o,triggerRef:c,contentRef:d,contentId:N(),titleId:N(),descriptionId:N(),open:f,onOpenChange:x,onOpenToggle:i.useCallback(()=>x(y=>!y),[x]),modal:l,children:n})};I.displayName=C;var w="DialogTrigger",fe=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u(w,n),t=b(o,s.triggerRef);return a.jsx(D.button,{type:"button","aria-haspopup":"dialog","aria-expanded":s.open,"aria-controls":s.contentId,"data-state":E(s.open),...r,ref:t,onClick:v(e.onClick,s.onOpenToggle)})});fe.displayName=w;var j="DialogPortal",[ge,A]=O(j,{forceMount:void 0}),T=e=>{const{__scopeDialog:o,forceMount:n,children:r,container:s}=e,t=u(j,o);return a.jsx(ge,{scope:o,forceMount:n,children:i.Children.map(r,l=>a.jsx(R,{present:n||t.open,children:a.jsx(te,{asChild:!0,container:s,children:l})}))})};T.displayName=j;var h="DialogOverlay",M=i.forwardRef((e,o)=>{const n=A(h,e.__scopeDialog),{forceMount:r=n.forceMount,...s}=e,t=u(h,e.__scopeDialog);return t.modal?a.jsx(R,{present:r||t.open,children:a.jsx(me,{...s,ref:o})}):null});M.displayName=h;var pe=le("DialogOverlay.RemoveScroll"),me=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u(h,n);return a.jsx(ne,{as:pe,allowPinchZoom:!0,shards:[s.contentRef],children:a.jsx(D.div,{"data-state":E(s.open),...r,ref:o,style:{pointerEvents:"auto",...r.style}})})}),g="DialogContent",F=i.forwardRef((e,o)=>{const n=A(g,e.__scopeDialog),{forceMount:r=n.forceMount,...s}=e,t=u(g,e.__scopeDialog);return a.jsx(R,{present:r||t.open,children:t.modal?a.jsx(xe,{...s,ref:o}):a.jsx(ve,{...s,ref:o})})});F.displayName=g;var xe=i.forwardRef((e,o)=>{const n=u(g,e.__scopeDialog),r=i.useRef(null),s=b(o,n.contentRef,r);return i.useEffect(()=>{const t=r.current;if(t)return ae(t)},[]),a.jsx(L,{...e,ref:s,trapFocus:n.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:v(e.onCloseAutoFocus,t=>{var l;t.preventDefault(),(l=n.triggerRef.current)==null||l.focus()}),onPointerDownOutside:v(e.onPointerDownOutside,t=>{const l=t.detail.originalEvent,c=l.button===0&&l.ctrlKey===!0;(l.button===2||c)&&t.preventDefault()}),onFocusOutside:v(e.onFocusOutside,t=>t.preventDefault())})}),ve=i.forwardRef((e,o)=>{const n=u(g,e.__scopeDialog),r=i.useRef(!1),s=i.useRef(!1);return a.jsx(L,{...e,ref:o,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{var l,c;(l=e.onCloseAutoFocus)==null||l.call(e,t),t.defaultPrevented||(r.current||(c=n.triggerRef.current)==null||c.focus(),t.preventDefault()),r.current=!1,s.current=!1},onInteractOutside:t=>{var d,f;(d=e.onInteractOutside)==null||d.call(e,t),t.defaultPrevented||(r.current=!0,t.detail.originalEvent.type==="pointerdown"&&(s.current=!0));const l=t.target;((f=n.triggerRef.current)==null?void 0:f.contains(l))&&t.preventDefault(),t.detail.originalEvent.type==="focusin"&&s.current&&t.preventDefault()}})}),L=i.forwardRef((e,o)=>{const{__scopeDialog:n,trapFocus:r,onOpenAutoFocus:s,onCloseAutoFocus:t,...l}=e,c=u(g,n),d=i.useRef(null),f=b(o,d);return re(),a.jsxs(a.Fragment,{children:[a.jsx(se,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:s,onUnmountAutoFocus:t,children:a.jsx(ie,{role:"dialog",id:c.contentId,"aria-describedby":c.descriptionId,"aria-labelledby":c.titleId,"data-state":E(c.open),...l,ref:f,onDismiss:()=>c.onOpenChange(!1)})}),a.jsxs(a.Fragment,{children:[a.jsx(De,{titleId:c.titleId}),a.jsx(Ce,{contentRef:d,descriptionId:c.descriptionId})]})]})}),_="DialogTitle",S=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u(_,n);return a.jsx(D.h2,{id:s.titleId,...r,ref:o})});S.displayName=_;var k="DialogDescription",W=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u(k,n);return a.jsx(D.p,{id:s.descriptionId,...r,ref:o})});W.displayName=k;var $="DialogClose",G=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u($,n);return a.jsx(D.button,{type:"button",...r,ref:o,onClick:v(e.onClick,()=>s.onOpenChange(!1))})});G.displayName=$;function E(e){return e?"open":"closed"}var B="DialogTitleWarning",[we,z]=ce(B,{contentName:g,titleName:_,docsSlug:"dialog"}),De=({titleId:e})=>{const o=z(B),n=`\`${o.contentName}\` requires a \`${o.titleName}\` for the component to be accessible for screen reader users.
1
+ import{r as i,az as ee,j as a,aB as N,aH as te,aD as D,aE as v,aI as oe,aC as b,aJ as ae,aK as ne,aM as re,aN as se,aO as ie,aL as le,a_ as ce,aw as de}from"./vendor-DKBNiC31.js";import{P as R}from"./index-CPDASUXh.js";import{c as m,B as P,t as p}from"./index-BEgClaDH.js";var C="Dialog",[O]=oe(C),[ue,u]=O(C),I=e=>{const{__scopeDialog:o,children:n,open:r,defaultOpen:s,onOpenChange:t,modal:l=!0}=e,c=i.useRef(null),d=i.useRef(null),[f,x]=ee({prop:r,defaultProp:s??!1,onChange:t,caller:C});return a.jsx(ue,{scope:o,triggerRef:c,contentRef:d,contentId:N(),titleId:N(),descriptionId:N(),open:f,onOpenChange:x,onOpenToggle:i.useCallback(()=>x(y=>!y),[x]),modal:l,children:n})};I.displayName=C;var w="DialogTrigger",fe=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u(w,n),t=b(o,s.triggerRef);return a.jsx(D.button,{type:"button","aria-haspopup":"dialog","aria-expanded":s.open,"aria-controls":s.contentId,"data-state":E(s.open),...r,ref:t,onClick:v(e.onClick,s.onOpenToggle)})});fe.displayName=w;var j="DialogPortal",[ge,A]=O(j,{forceMount:void 0}),T=e=>{const{__scopeDialog:o,forceMount:n,children:r,container:s}=e,t=u(j,o);return a.jsx(ge,{scope:o,forceMount:n,children:i.Children.map(r,l=>a.jsx(R,{present:n||t.open,children:a.jsx(te,{asChild:!0,container:s,children:l})}))})};T.displayName=j;var h="DialogOverlay",M=i.forwardRef((e,o)=>{const n=A(h,e.__scopeDialog),{forceMount:r=n.forceMount,...s}=e,t=u(h,e.__scopeDialog);return t.modal?a.jsx(R,{present:r||t.open,children:a.jsx(me,{...s,ref:o})}):null});M.displayName=h;var pe=le("DialogOverlay.RemoveScroll"),me=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u(h,n);return a.jsx(ne,{as:pe,allowPinchZoom:!0,shards:[s.contentRef],children:a.jsx(D.div,{"data-state":E(s.open),...r,ref:o,style:{pointerEvents:"auto",...r.style}})})}),g="DialogContent",F=i.forwardRef((e,o)=>{const n=A(g,e.__scopeDialog),{forceMount:r=n.forceMount,...s}=e,t=u(g,e.__scopeDialog);return a.jsx(R,{present:r||t.open,children:t.modal?a.jsx(xe,{...s,ref:o}):a.jsx(ve,{...s,ref:o})})});F.displayName=g;var xe=i.forwardRef((e,o)=>{const n=u(g,e.__scopeDialog),r=i.useRef(null),s=b(o,n.contentRef,r);return i.useEffect(()=>{const t=r.current;if(t)return ae(t)},[]),a.jsx(L,{...e,ref:s,trapFocus:n.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:v(e.onCloseAutoFocus,t=>{var l;t.preventDefault(),(l=n.triggerRef.current)==null||l.focus()}),onPointerDownOutside:v(e.onPointerDownOutside,t=>{const l=t.detail.originalEvent,c=l.button===0&&l.ctrlKey===!0;(l.button===2||c)&&t.preventDefault()}),onFocusOutside:v(e.onFocusOutside,t=>t.preventDefault())})}),ve=i.forwardRef((e,o)=>{const n=u(g,e.__scopeDialog),r=i.useRef(!1),s=i.useRef(!1);return a.jsx(L,{...e,ref:o,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{var l,c;(l=e.onCloseAutoFocus)==null||l.call(e,t),t.defaultPrevented||(r.current||(c=n.triggerRef.current)==null||c.focus(),t.preventDefault()),r.current=!1,s.current=!1},onInteractOutside:t=>{var d,f;(d=e.onInteractOutside)==null||d.call(e,t),t.defaultPrevented||(r.current=!0,t.detail.originalEvent.type==="pointerdown"&&(s.current=!0));const l=t.target;((f=n.triggerRef.current)==null?void 0:f.contains(l))&&t.preventDefault(),t.detail.originalEvent.type==="focusin"&&s.current&&t.preventDefault()}})}),L=i.forwardRef((e,o)=>{const{__scopeDialog:n,trapFocus:r,onOpenAutoFocus:s,onCloseAutoFocus:t,...l}=e,c=u(g,n),d=i.useRef(null),f=b(o,d);return re(),a.jsxs(a.Fragment,{children:[a.jsx(se,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:s,onUnmountAutoFocus:t,children:a.jsx(ie,{role:"dialog",id:c.contentId,"aria-describedby":c.descriptionId,"aria-labelledby":c.titleId,"data-state":E(c.open),...l,ref:f,onDismiss:()=>c.onOpenChange(!1)})}),a.jsxs(a.Fragment,{children:[a.jsx(De,{titleId:c.titleId}),a.jsx(Ce,{contentRef:d,descriptionId:c.descriptionId})]})]})}),_="DialogTitle",S=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u(_,n);return a.jsx(D.h2,{id:s.titleId,...r,ref:o})});S.displayName=_;var k="DialogDescription",W=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u(k,n);return a.jsx(D.p,{id:s.descriptionId,...r,ref:o})});W.displayName=k;var $="DialogClose",G=i.forwardRef((e,o)=>{const{__scopeDialog:n,...r}=e,s=u($,n);return a.jsx(D.button,{type:"button",...r,ref:o,onClick:v(e.onClick,()=>s.onOpenChange(!1))})});G.displayName=$;function E(e){return e?"open":"closed"}var B="DialogTitleWarning",[we,z]=ce(B,{contentName:g,titleName:_,docsSlug:"dialog"}),De=({titleId:e})=>{const o=z(B),n=`\`${o.contentName}\` requires a \`${o.titleName}\` for the component to be accessible for screen reader users.
2
2
 
3
3
  If you want to hide the \`${o.titleName}\`, you can wrap it with our VisuallyHidden component.
4
4
 
package/dist/index.html CHANGED
@@ -6,7 +6,7 @@
6
6
  <link rel="icon" type="image/svg+xml" href="/logo.svg" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
  <title>NextClaw - 系统配置</title>
9
- <script type="module" crossorigin src="/assets/index-BiPDnzv0.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-BEgClaDH.js"></script>
10
10
  <link rel="modulepreload" crossorigin href="/assets/vendor-DKBNiC31.js">
11
11
  <link rel="stylesheet" crossorigin href="/assets/index-C8GsgIUn.css">
12
12
  </head>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/ui",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,11 +27,11 @@
27
27
  "tailwind-merge": "^2.5.4",
28
28
  "zod": "^3.23.8",
29
29
  "zustand": "^5.0.2",
30
- "@nextclaw/agent-chat": "0.1.1",
31
30
  "@nextclaw/agent-chat-ui": "0.2.1",
32
31
  "@nextclaw/ncp": "0.3.1",
33
- "@nextclaw/ncp-http-agent-client": "0.3.1",
34
- "@nextclaw/ncp-react": "0.3.2"
32
+ "@nextclaw/ncp-react": "0.3.2",
33
+ "@nextclaw/agent-chat": "0.1.1",
34
+ "@nextclaw/ncp-http-agent-client": "0.3.1"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@testing-library/react": "^16.3.0",
package/src/api/types.ts CHANGED
@@ -703,13 +703,14 @@ export type WsEvent =
703
703
  | { type: 'connection.close'; payload?: Record<string, unknown> }
704
704
  | { type: 'connection.error'; payload?: { message?: string } };
705
705
 
706
- export type MarketplaceItemType = 'plugin' | 'skill';
706
+ export type MarketplaceItemType = 'plugin' | 'skill' | 'mcp';
707
707
 
708
708
  export type MarketplaceSort = 'relevance' | 'updated';
709
709
 
710
710
  export type MarketplacePluginInstallKind = 'npm';
711
711
  export type MarketplaceSkillInstallKind = 'builtin' | 'marketplace';
712
- export type MarketplaceInstallKind = MarketplacePluginInstallKind | MarketplaceSkillInstallKind;
712
+ export type MarketplaceMcpInstallKind = 'template';
713
+ export type MarketplaceInstallKind = MarketplacePluginInstallKind | MarketplaceSkillInstallKind | MarketplaceMcpInstallKind;
713
714
 
714
715
  export type MarketplaceInstallSpec = {
715
716
  kind: MarketplaceInstallKind;
@@ -717,6 +718,23 @@ export type MarketplaceInstallSpec = {
717
718
  command: string;
718
719
  };
719
720
 
721
+ export type MarketplaceMcpTemplateInput = {
722
+ id: string;
723
+ label: string;
724
+ description?: string;
725
+ required?: boolean;
726
+ secret?: boolean;
727
+ defaultValue?: string;
728
+ };
729
+
730
+ export type MarketplaceMcpInstallSpec = MarketplaceInstallSpec & {
731
+ kind: 'template';
732
+ defaultName: string;
733
+ transportTypes: Array<'stdio' | 'http' | 'sse'>;
734
+ template: Record<string, unknown>;
735
+ inputs: MarketplaceMcpTemplateInput[];
736
+ };
737
+
720
738
  export type MarketplaceLocalizedTextMap = Record<string, string>;
721
739
 
722
740
  export type MarketplaceItemSummary = {
@@ -764,6 +782,18 @@ export type MarketplacePluginContentView = {
764
782
  sourceUrl?: string;
765
783
  };
766
784
 
785
+ export type MarketplaceMcpContentView = {
786
+ type: 'mcp';
787
+ slug: string;
788
+ name: string;
789
+ install: MarketplaceMcpInstallSpec;
790
+ source: 'marketplace' | 'remote';
791
+ raw: string;
792
+ metadataRaw?: string;
793
+ bodyRaw: string;
794
+ sourceUrl?: string;
795
+ };
796
+
767
797
  export type MarketplaceListView = {
768
798
  total: number;
769
799
  page: number;
@@ -796,6 +826,21 @@ export type MarketplaceInstalledRecord = {
796
826
  runtimeStatus?: string;
797
827
  origin?: string;
798
828
  installPath?: string;
829
+ transport?: 'stdio' | 'http' | 'sse';
830
+ scope?: {
831
+ allAgents: boolean;
832
+ agents: string[];
833
+ };
834
+ catalogSlug?: string;
835
+ vendor?: string;
836
+ docsUrl?: string;
837
+ homepage?: string;
838
+ trustLevel?: 'official' | 'verified' | 'community';
839
+ toolCount?: number;
840
+ accessible?: boolean;
841
+ lastReadyAt?: string;
842
+ lastDoctorAt?: string;
843
+ lastError?: string;
799
844
  };
800
845
 
801
846
  export type MarketplaceInstalledView = {
@@ -812,6 +857,11 @@ export type MarketplaceInstallRequest = {
812
857
  skill?: string;
813
858
  installPath?: string;
814
859
  force?: boolean;
860
+ name?: string;
861
+ enabled?: boolean;
862
+ allAgents?: boolean;
863
+ agents?: string[];
864
+ inputs?: Record<string, string>;
815
865
  };
816
866
 
817
867
  export type MarketplaceInstallResult = {
@@ -819,9 +869,10 @@ export type MarketplaceInstallResult = {
819
869
  spec: string;
820
870
  message: string;
821
871
  output?: string;
872
+ name?: string;
822
873
  };
823
874
 
824
- export type MarketplaceManageAction = 'enable' | 'disable' | 'uninstall';
875
+ export type MarketplaceManageAction = 'enable' | 'disable' | 'uninstall' | 'remove';
825
876
 
826
877
  export type MarketplaceManageRequest = {
827
878
  type: MarketplaceItemType;
@@ -837,3 +888,12 @@ export type MarketplaceManageResult = {
837
888
  message: string;
838
889
  output?: string;
839
890
  };
891
+
892
+ export type MarketplaceMcpDoctorResult = {
893
+ name: string;
894
+ enabled: boolean;
895
+ transport: 'stdio' | 'http' | 'sse';
896
+ accessible: boolean;
897
+ toolCount: number;
898
+ error?: string;
899
+ };
@@ -4,7 +4,6 @@ import type { SessionEntryView, ThinkingLevel } from '@/api/types';
4
4
  import type { ChatModelOption } from '@/components/chat/chat-input.types';
5
5
  import { useChatSessionTypeState } from '@/components/chat/useChatSessionTypeState';
6
6
  import {
7
- resolveSelectedModelValue,
8
7
  resolveRecentSessionPreferredModel,
9
8
  useSyncSelectedModel
10
9
  } from '@/components/chat/chat-page-runtime';
@@ -115,25 +114,13 @@ export function useChatPageData(params: UseChatPageDataParams) {
115
114
  useSyncSelectedModel({
116
115
  modelOptions,
117
116
  selectedSessionKey: params.selectedSessionKey,
117
+ selectedSessionExists: Boolean(selectedSession),
118
118
  selectedSessionPreferredModel: selectedSession?.preferredModel,
119
119
  fallbackPreferredModel: recentSessionPreferredModel,
120
120
  defaultModel: configQuery.data?.agents.defaults.model,
121
121
  setSelectedModel: params.setSelectedModel
122
122
  });
123
123
 
124
- const hydratedSessionModel = useMemo(
125
- () =>
126
- resolveSelectedModelValue({
127
- currentSelectedModel: '',
128
- modelOptions,
129
- selectedSessionPreferredModel: selectedSession?.preferredModel,
130
- fallbackPreferredModel: recentSessionPreferredModel,
131
- defaultModel: configQuery.data?.agents.defaults.model,
132
- preferSessionPreferredModel: true
133
- }),
134
- [configQuery.data?.agents.defaults.model, modelOptions, recentSessionPreferredModel, selectedSession?.preferredModel]
135
- );
136
-
137
124
  const historyMessages = useMemo(() => historyQuery.data?.messages ?? [], [historyQuery.data?.messages]);
138
125
  const selectedSessionThinkingLevel = useMemo(() => {
139
126
  if (!params.selectedSessionKey) {
@@ -171,7 +158,6 @@ export function useChatPageData(params: UseChatPageDataParams) {
171
158
  sessions,
172
159
  skillRecords,
173
160
  selectedSession,
174
- hydratedSessionModel,
175
161
  historyMessages,
176
162
  selectedSessionThinkingLevel,
177
163
  ...sessionTypeState
@@ -82,6 +82,32 @@ describe('resolveSelectedModelValue', () => {
82
82
  ).toBe('openai/gpt-5');
83
83
  });
84
84
 
85
+ it('preserves the current valid model when a draft session materializes before the new session metadata exists', () => {
86
+ expect(
87
+ resolveSelectedModelValue({
88
+ currentSelectedModel: 'openai/gpt-5',
89
+ modelOptions,
90
+ fallbackPreferredModel: 'anthropic/claude-sonnet-4',
91
+ defaultModel: 'anthropic/claude-sonnet-4',
92
+ preferSessionPreferredModel: true,
93
+ preserveCurrentSelectedModelOnSessionChange: true
94
+ })
95
+ ).toBe('openai/gpt-5');
96
+ });
97
+
98
+ it('still falls back when the current model is no longer valid during draft session materialization', () => {
99
+ expect(
100
+ resolveSelectedModelValue({
101
+ currentSelectedModel: 'missing/model',
102
+ modelOptions,
103
+ fallbackPreferredModel: 'openai/gpt-5',
104
+ defaultModel: 'anthropic/claude-sonnet-4',
105
+ preferSessionPreferredModel: true,
106
+ preserveCurrentSelectedModelOnSessionChange: true
107
+ })
108
+ ).toBe('openai/gpt-5');
109
+ });
110
+
85
111
  it('uses the recent same-runtime model when the current session has no valid preferred model', () => {
86
112
  expect(
87
113
  resolveSelectedModelValue({
@@ -27,6 +27,7 @@ export function resolveSelectedModelValue(params: {
27
27
  fallbackPreferredModel?: string;
28
28
  defaultModel?: string;
29
29
  preferSessionPreferredModel?: boolean;
30
+ preserveCurrentSelectedModelOnSessionChange?: boolean;
30
31
  }): string {
31
32
  const {
32
33
  currentSelectedModel,
@@ -34,12 +35,16 @@ export function resolveSelectedModelValue(params: {
34
35
  selectedSessionPreferredModel,
35
36
  fallbackPreferredModel,
36
37
  defaultModel,
37
- preferSessionPreferredModel = false
38
+ preferSessionPreferredModel = false,
39
+ preserveCurrentSelectedModelOnSessionChange = false
38
40
  } = params;
39
41
  if (modelOptions.length === 0) {
40
42
  return '';
41
43
  }
42
- if (!preferSessionPreferredModel && hasModelOption(modelOptions, currentSelectedModel)) {
44
+ if (
45
+ hasModelOption(modelOptions, currentSelectedModel) &&
46
+ (!preferSessionPreferredModel || preserveCurrentSelectedModelOnSessionChange)
47
+ ) {
43
48
  return currentSelectedModel.trim();
44
49
  }
45
50
  if (hasModelOption(modelOptions, selectedSessionPreferredModel)) {
@@ -86,6 +91,7 @@ export function resolveRecentSessionPreferredModel(params: {
86
91
  export function useSyncSelectedModel(params: {
87
92
  modelOptions: ChatModelOption[];
88
93
  selectedSessionKey?: string | null;
94
+ selectedSessionExists?: boolean;
89
95
  selectedSessionPreferredModel?: string;
90
96
  fallbackPreferredModel?: string;
91
97
  defaultModel?: string;
@@ -94,6 +100,7 @@ export function useSyncSelectedModel(params: {
94
100
  const {
95
101
  modelOptions,
96
102
  selectedSessionKey,
103
+ selectedSessionExists = false,
97
104
  selectedSessionPreferredModel,
98
105
  fallbackPreferredModel,
99
106
  defaultModel,
@@ -115,11 +122,21 @@ export function useSyncSelectedModel(params: {
115
122
  selectedSessionPreferredModel,
116
123
  fallbackPreferredModel,
117
124
  defaultModel,
118
- preferSessionPreferredModel: sessionChanged
125
+ preferSessionPreferredModel: sessionChanged,
126
+ preserveCurrentSelectedModelOnSessionChange:
127
+ sessionChanged && Boolean(selectedSessionKey) && !selectedSessionExists
119
128
  });
120
129
  });
121
130
  previousSessionKeyRef.current = selectedSessionKey;
122
- }, [defaultModel, fallbackPreferredModel, modelOptions, selectedSessionKey, selectedSessionPreferredModel, setSelectedModel]);
131
+ }, [
132
+ defaultModel,
133
+ fallbackPreferredModel,
134
+ modelOptions,
135
+ selectedSessionExists,
136
+ selectedSessionKey,
137
+ selectedSessionPreferredModel,
138
+ setSelectedModel
139
+ ]);
123
140
  }
124
141
 
125
142
  export function useSessionRunStatus(params: {
@@ -24,7 +24,6 @@ export function LegacyChatPage({ view }: ChatPageProps) {
24
24
  const { sessionId: routeSessionIdParam } = useParams<{ sessionId?: string }>();
25
25
  const threadRef = useRef<HTMLDivElement | null>(null);
26
26
  const selectedSessionKeyRef = useRef<string | null>(selectedSessionKey);
27
- const modelHydratedSessionKeyRef = useRef<string | null>(null);
28
27
  const thinkingHydratedSessionKeyRef = useRef<string | null>(null);
29
28
  const routeSessionKey = useMemo(
30
29
  () => parseSessionKeyFromRoute(routeSessionIdParam),
@@ -40,7 +39,6 @@ export function LegacyChatPage({ view }: ChatPageProps) {
40
39
  sessions,
41
40
  skillRecords,
42
41
  selectedSession,
43
- hydratedSessionModel,
44
42
  historyMessages,
45
43
  selectedSessionThinkingLevel,
46
44
  sessionTypeOptions,
@@ -140,13 +138,6 @@ export function LegacyChatPage({ view }: ChatPageProps) {
140
138
  }, [presenter, sessionsQuery.refetch]);
141
139
 
142
140
  useEffect(() => {
143
- const shouldHydrateModelFromSession =
144
- !isSending &&
145
- !isAwaitingAssistantOutput &&
146
- !sessionsQuery.isLoading &&
147
- isProviderStateResolved &&
148
- modelOptions.length > 0 &&
149
- selectedSessionKey !== modelHydratedSessionKeyRef.current;
150
141
  const shouldHydrateThinkingFromHistory =
151
142
  !isSending &&
152
143
  !isAwaitingAssistantOutput &&
@@ -165,7 +156,6 @@ export function LegacyChatPage({ view }: ChatPageProps) {
165
156
  sendError: lastSendError,
166
157
  isSending,
167
158
  modelOptions,
168
- ...(shouldHydrateModelFromSession ? { selectedModel: hydratedSessionModel } : {}),
169
159
  sessionTypeOptions,
170
160
  selectedSessionType,
171
161
  ...(shouldHydrateThinkingFromHistory ? { selectedThinkingLevel: selectedSessionThinkingLevel } : {}),
@@ -174,14 +164,10 @@ export function LegacyChatPage({ view }: ChatPageProps) {
174
164
  skillRecords,
175
165
  isSkillsLoading: installedSkillsQuery.isLoading
176
166
  });
177
- if (shouldHydrateModelFromSession) {
178
- modelHydratedSessionKeyRef.current = selectedSessionKey;
179
- }
180
167
  if (shouldHydrateThinkingFromHistory) {
181
168
  thinkingHydratedSessionKeyRef.current = selectedSessionKey;
182
169
  }
183
170
  if (!selectedSessionKey) {
184
- modelHydratedSessionKeyRef.current = null;
185
171
  thinkingHydratedSessionKeyRef.current = null;
186
172
  }
187
173
  presenter.chatSessionListManager.syncSnapshot({
@@ -221,7 +207,6 @@ export function LegacyChatPage({ view }: ChatPageProps) {
221
207
  historyQuery.isLoading,
222
208
  installedSkillsQuery.isLoading,
223
209
  isAwaitingAssistantOutput,
224
- hydratedSessionModel,
225
210
  isProviderStateResolved,
226
211
  isSending,
227
212
  lastSendError,
@@ -71,7 +71,6 @@ export function NcpChatPage({ view }: ChatPageProps) {
71
71
  const { sessionId: routeSessionIdParam } = useParams<{ sessionId?: string }>();
72
72
  const threadRef = useRef<HTMLDivElement | null>(null);
73
73
  const selectedSessionKeyRef = useRef<string | null>(selectedSessionKey);
74
- const modelHydratedSessionKeyRef = useRef<string | null>(null);
75
74
  const thinkingHydratedSessionKeyRef = useRef<string | null>(null);
76
75
  const routeSessionKey = useMemo(
77
76
  () => parseSessionKeyFromRoute(routeSessionIdParam),
@@ -86,7 +85,6 @@ export function NcpChatPage({ view }: ChatPageProps) {
86
85
  sessions,
87
86
  skillRecords,
88
87
  selectedSession,
89
- hydratedSessionModel,
90
88
  selectedSessionThinkingLevel,
91
89
  sessionTypeOptions,
92
90
  defaultSessionType,
@@ -278,13 +276,6 @@ export function NcpChatPage({ view }: ChatPageProps) {
278
276
  }, [presenter, sessionsQuery.refetch]);
279
277
 
280
278
  useEffect(() => {
281
- const shouldHydrateModelFromSession =
282
- !isSending &&
283
- !isAwaitingAssistantOutput &&
284
- !sessionsQuery.isLoading &&
285
- isProviderStateResolved &&
286
- modelOptions.length > 0 &&
287
- selectedSessionKey !== modelHydratedSessionKeyRef.current;
288
279
  const shouldHydrateThinkingFromSession =
289
280
  !isSending &&
290
281
  !isAwaitingAssistantOutput &&
@@ -303,7 +294,6 @@ export function NcpChatPage({ view }: ChatPageProps) {
303
294
  sendError: lastSendError,
304
295
  isSending,
305
296
  modelOptions,
306
- ...(shouldHydrateModelFromSession ? { selectedModel: hydratedSessionModel } : {}),
307
297
  sessionTypeOptions,
308
298
  selectedSessionType,
309
299
  ...(shouldHydrateThinkingFromSession ? { selectedThinkingLevel: selectedSessionThinkingLevel } : {}),
@@ -312,14 +302,10 @@ export function NcpChatPage({ view }: ChatPageProps) {
312
302
  skillRecords,
313
303
  isSkillsLoading: installedSkillsQuery.isLoading
314
304
  });
315
- if (shouldHydrateModelFromSession) {
316
- modelHydratedSessionKeyRef.current = selectedSessionKey;
317
- }
318
305
  if (shouldHydrateThinkingFromSession) {
319
306
  thinkingHydratedSessionKeyRef.current = selectedSessionKey;
320
307
  }
321
308
  if (!selectedSessionKey) {
322
- modelHydratedSessionKeyRef.current = null;
323
309
  thinkingHydratedSessionKeyRef.current = null;
324
310
  }
325
311
  presenter.chatSessionListManager.syncSnapshot({
@@ -357,7 +343,6 @@ export function NcpChatPage({ view }: ChatPageProps) {
357
343
  defaultSessionType,
358
344
  installedSkillsQuery.isLoading,
359
345
  isAwaitingAssistantOutput,
360
- hydratedSessionModel,
361
346
  isProviderStateResolved,
362
347
  isSending,
363
348
  lastSendError,
@@ -8,7 +8,6 @@ import {
8
8
  } from '@/components/chat/ncp/ncp-session-adapter';
9
9
  import { useChatSessionTypeState } from '@/components/chat/useChatSessionTypeState';
10
10
  import {
11
- resolveSelectedModelValue,
12
11
  resolveRecentSessionPreferredModel,
13
12
  useSyncSelectedModel
14
13
  } from '@/components/chat/chat-page-runtime';
@@ -128,25 +127,13 @@ export function useNcpChatPageData(params: UseNcpChatPageDataParams) {
128
127
  useSyncSelectedModel({
129
128
  modelOptions,
130
129
  selectedSessionKey: params.selectedSessionKey,
130
+ selectedSessionExists: Boolean(selectedSession),
131
131
  selectedSessionPreferredModel: selectedSession?.preferredModel,
132
132
  fallbackPreferredModel: recentSessionPreferredModel,
133
133
  defaultModel: configQuery.data?.agents.defaults.model,
134
134
  setSelectedModel: params.setSelectedModel
135
135
  });
136
136
 
137
- const hydratedSessionModel = useMemo(
138
- () =>
139
- resolveSelectedModelValue({
140
- currentSelectedModel: '',
141
- modelOptions,
142
- selectedSessionPreferredModel: selectedSession?.preferredModel,
143
- fallbackPreferredModel: recentSessionPreferredModel,
144
- defaultModel: configQuery.data?.agents.defaults.model,
145
- preferSessionPreferredModel: true
146
- }),
147
- [configQuery.data?.agents.defaults.model, modelOptions, recentSessionPreferredModel, selectedSession?.preferredModel]
148
- );
149
-
150
137
  return {
151
138
  configQuery,
152
139
  configMetaQuery,
@@ -159,7 +146,6 @@ export function useNcpChatPageData(params: UseNcpChatPageDataParams) {
159
146
  sessions,
160
147
  skillRecords,
161
148
  selectedSession,
162
- hydratedSessionModel,
163
149
  selectedSessionThinkingLevel,
164
150
  ...sessionTypeState
165
151
  };