@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.
- package/CHANGELOG.md +6 -0
- package/dist/assets/{ChannelsList-DhvjpZcs.js → ChannelsList-DKD6Llid.js} +1 -1
- package/dist/assets/ChatPage-BK9X4Tin.js +38 -0
- package/dist/assets/{DocBrowser-LpzGe8An.js → DocBrowser-CVwUDJMO.js} +1 -1
- package/dist/assets/{LogoBadge-Be4lktJN.js → LogoBadge-CYQ_b7jk.js} +1 -1
- package/dist/assets/{MarketplacePage-Cx9AI3_h.js → MarketplacePage-B_2z3ii_.js} +1 -1
- package/dist/assets/{ModelConfig-DuImUHIX.js → ModelConfig-CsX-_fyy.js} +1 -1
- package/dist/assets/{ProvidersList-Ccleg25k.js → ProvidersList-CZstsyv7.js} +1 -1
- package/dist/assets/{RuntimeConfig-C6iqpJR_.js → RuntimeConfig-CX2TGEG1.js} +1 -1
- package/dist/assets/{SearchConfig-Dvp1TAXu.js → SearchConfig-C-WBTcWi.js} +1 -1
- package/dist/assets/{SecretsConfig-D5Ymlvt9.js → SecretsConfig-9kbR0ZCB.js} +1 -1
- package/dist/assets/{SessionsConfig-CIA_jA1P.js → SessionsConfig-Bohn3P1q.js} +1 -1
- package/dist/assets/{chat-message-B60Fh9kI.js → chat-message-AWIcksDK.js} +1 -1
- package/dist/assets/{index-BiPDnzv0.js → index-BEgClaDH.js} +2 -2
- package/dist/assets/{label-D4fGx6Wb.js → label-DD61y-4v.js} +1 -1
- package/dist/assets/{page-layout-twy8gmBE.js → page-layout-CfnoVycc.js} +1 -1
- package/dist/assets/{popover-DYbYpt1j.js → popover-DsugZ6rp.js} +1 -1
- package/dist/assets/{security-config-BcIZ4rpb.js → security-config-DIrf2Z0O.js} +1 -1
- package/dist/assets/{skeleton-DypBy7jp.js → skeleton-DJ-Wen2o.js} +1 -1
- package/dist/assets/{switch-DqA6r5XR.js → switch-NX5OmUXQ.js} +1 -1
- package/dist/assets/{tabs-custom-C6enKKs1.js → tabs-custom-9ihB5Jem.js} +1 -1
- package/dist/assets/{useConfirmDialog-CHBf5Of7.js → useConfirmDialog-BuQnVTeR.js} +1 -1
- package/dist/index.html +1 -1
- package/package.json +4 -4
- package/src/api/types.ts +63 -3
- package/src/components/chat/chat-page-data.ts +1 -15
- package/src/components/chat/chat-page-runtime.test.ts +26 -0
- package/src/components/chat/chat-page-runtime.ts +21 -4
- package/src/components/chat/legacy/LegacyChatPage.tsx +0 -15
- package/src/components/chat/ncp/NcpChatPage.tsx +0 -15
- package/src/components/chat/ncp/ncp-chat-page-data.ts +1 -15
- 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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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-
|
|
34
|
-
"@nextclaw/
|
|
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
|
|
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 (
|
|
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
|
-
}, [
|
|
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
|
};
|