@nextclaw/ui 0.27.4 → 0.27.5-beta.1
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 +17 -0
- package/dist/.vite/manifest.json +95 -95
- package/dist/assets/{account-panel-Cfx3ocPY.js → account-panel-C83GDFuy.js} +1 -1
- package/dist/assets/agents-CJA15zzv.js +1 -0
- package/dist/assets/{agents-BdeFtIOV.js → agents-Dr2KkEp2.js} +1 -1
- package/dist/assets/{app-presenter-provider-BB3Xl8b0.js → app-presenter-provider-Cx9MwMtb.js} +17 -16
- package/dist/assets/{appearance-settings-page-DiSRSDN3.js → appearance-settings-page-3IfIzjic.js} +1 -1
- package/dist/assets/apps-CvIlb9Rn.js +1 -0
- package/dist/assets/{confirm-dialog-jz2cQKId.js → confirm-dialog-D30HJBXN.js} +1 -1
- package/dist/assets/{context-menu-C0qywo73.js → context-menu-C6m-WNpl.js} +65 -65
- package/dist/assets/cron-BWZWu80t.js +1 -0
- package/dist/assets/{dialog-DMKYZDFu.js → dialog-DB_l9LK0.js} +1 -1
- package/dist/assets/doc-browser-DQDsmRlr.js +1 -0
- package/dist/assets/inbox-CIsD65lW.js +1 -0
- package/dist/assets/{keyboard-shortcuts-settings-page-BFBXVf20.js → keyboard-shortcuts-settings-page-L4kLGuB8.js} +1 -1
- package/dist/assets/{main-Bp1iozNB.js → main-BNWRrWc_.js} +2 -2
- package/dist/assets/{marketplace-BTDWnHP7.js → marketplace-BH1Sq8dL.js} +1 -1
- package/dist/assets/mcp-marketplace-page-BA-InAbJ.js +1 -0
- package/dist/assets/{model-config-page-CeVvZ29o.js → model-config-page-zqVWyIT0.js} +1 -1
- package/dist/assets/panel-apps-CMX4iWwQ.js +1 -0
- package/dist/assets/{panelStandalone-DomappXm.js → panelStandalone-C38o5B4Q.js} +1 -1
- package/dist/assets/{projects-fPTOn2Wz.js → projects-DNe43T2d.js} +1 -1
- package/dist/assets/{provider-models-D8WOdsdu.js → provider-models-zGsDUBHG.js} +1 -1
- package/dist/assets/{provider-scoped-model-input-BOPkUOtD.js → provider-scoped-model-input-DpEyP1h8.js} +1 -1
- package/dist/assets/{providers-config-page-BilPL0kF.js → providers-config-page-J-1auWPu.js} +1 -1
- package/dist/assets/{pwa-Cp7pPvsZ.js → pwa-jmuWbrqH.js} +1 -1
- package/dist/assets/remote-C7H2o46-.js +1 -0
- package/dist/assets/{runtime-config-page-P5RUq3YK.js → runtime-config-page-CJhqeDcu.js} +1 -1
- package/dist/assets/{service-apps-panel-BReYr_ni.js → service-apps-panel-Dj9okUgp.js} +1 -1
- package/dist/assets/{theme-provider-BsJ6HxeX.js → theme-provider-D4rd-tCP.js} +1 -1
- package/dist/index.html +10 -10
- package/dist/panel-standalone.html +4 -4
- package/package.json +7 -7
- package/src/features/chat/features/message/utils/__tests__/chat-message-timeline.utils.test.ts +16 -0
- package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +17 -0
- package/src/features/chat/features/message/utils/chat-message-timeline.utils.ts +3 -3
- package/src/features/chat/features/message/utils/chat-message.utils.ts +11 -4
- package/src/features/chat/features/message/utils/chat-user-question-timeline.utils.ts +42 -0
- package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +2 -0
- package/src/features/panel-apps/components/panel-app-runtime-surface.tsx +3 -1
- package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +25 -10
- package/src/features/right-panel-resources/components/__tests__/system-object-resource.test.tsx +25 -3
- package/src/features/right-panel-resources/components/native-object-resource.tsx +3 -1
- package/src/features/right-panel-resources/components/system-object-resource.tsx +15 -1
- package/src/features/right-panel-resources/pages/resource-page.tsx +29 -2
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +16 -13
- package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +3 -0
- package/src/shared/components/doc-browser/doc-browser.tsx +7 -1
- package/src/shared/components/ui/context-menu/context-menu-items.tsx +1 -0
- package/src/shared/components/ui/context-menu/context-menu.tsx +9 -0
- package/dist/assets/agents-p_wcGhC3.js +0 -1
- package/dist/assets/apps-CKFrWb00.js +0 -1
- package/dist/assets/cron-UqsFT41c.js +0 -1
- package/dist/assets/doc-browser-2VjSkax1.js +0 -1
- package/dist/assets/inbox-D62apR2j.js +0 -1
- package/dist/assets/mcp-marketplace-page-oHCbBkS-.js +0 -1
- package/dist/assets/panel-apps-CniMi7QW.js +0 -1
- package/dist/assets/remote-CsJMF8OR.js +0 -1
- package/src/features/panel-apps/components/__tests__/panel-app-toolbar.test.tsx +0 -108
- package/src/features/panel-apps/components/panel-app-toolbar.tsx +0 -89
|
@@ -1 +1 @@
|
|
|
1
|
-
import{i as e}from"./chunk-DF37yw5_.js";import{Lt as t,Qn as n,Sn as r,Xn as i,Yt as a,Zn as o,fn as s,hn as c,lr as l,ur as ee,xr as u}from"./api-CXWxExzS.js";import{t as d}from"./createLucideIcon-C3LSyx-e.js";import{J as te}from"./context-menu-C0qywo73.js";import{d as ne,f as re,l as f,p,s as m}from"./i18n-ByVUrt9w.js";import{a as ie,i as ae,n as oe,o as h,r as se,t as ce}from"./dialog-DMKYZDFu.js";import{n as g}from"./navigation-history-CCnxsAKR.js";var _=`nextclaw.ui.theme`,v=`default`,le=`plain-paper`;function y(e){return e===`default`?le:e}var b=[{value:`default`,labelKey:`themeDefault`,appearance:`light`},{value:`plain-paper`,labelKey:`themePlainPaper`,appearance:`light`},{value:`paper-ink`,labelKey:`themePaperInk`,appearance:`light`},{value:`work`,labelKey:`themeWork`,appearance:`light`},{value:`night`,labelKey:`themeNight`,appearance:`dark`},{value:`charcoal`,labelKey:`themeCharcoal`,appearance:`dark`},{value:`island`,labelKey:`themeIsland`,appearance:`light`},{value:`natural`,labelKey:`themeNatural`,appearance:`light`},{value:`minimal`,labelKey:`themeMinimal`,appearance:`light`},{value:`warm`,labelKey:`themeWarm`,appearance:`light`},{value:`cool`,labelKey:`themeCool`,appearance:`light`},{value:`dawn`,labelKey:`themeDawn`,appearance:`light`},{value:`graphite`,labelKey:`themeGraphite`,appearance:`light`},{value:`probe`,labelKey:`themeProbe`,appearance:`light`}],ue=b.map(({value:e})=>e),de=b.map(({value:e,labelKey:t})=>({value:e,labelKey:t}));function x(e){return typeof e==`string`?ue.includes(e)?e:e===`leaf`?`warm`:null:null}function S(e){return b.find(t=>t.value===y(e))?.appearance??`light`}var C=new class{constructor(){this.activeTheme=v,this.initialized=!1,this.listeners=new Set,this.resolveInitialTheme=()=>{if(typeof window>`u`)return v;try{let e=x(window.localStorage.getItem(_));if(e)return e}catch{}return v},this.initializeTheme=()=>(this.initialized||=(this.activeTheme=this.resolveInitialTheme(),this.applyThemeAttribute(this.activeTheme),!0),this.activeTheme),this.getTheme=()=>this.initialized?this.activeTheme:this.initializeTheme(),this.setTheme=e=>{this.initializeTheme(),e!==this.activeTheme&&(this.activeTheme=e,this.applyThemeAttribute(this.activeTheme),this.saveTheme(this.activeTheme),this.listeners.forEach(e=>e(this.activeTheme)))},this.subscribeThemeChange=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)}),this.applyThemeAttribute=e=>{if(typeof document>`u`)return;let t=S(e);document.documentElement.setAttribute(`data-theme`,y(e)),document.documentElement.setAttribute(`data-theme-appearance`,t),document.documentElement.style.colorScheme=t},this.saveTheme=e=>{if(!(typeof window>`u`))try{window.localStorage.setItem(_,e)}catch{}}}};function w(){return C.initializeTheme()}function fe(){return C.getTheme()}function pe(e){C.setTheme(e)}function me(e){return C.subscribeThemeChange(e)}var T=d(`Boxes`,[[`path`,{d:`M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z`,key:`lc1i9w`}],[`path`,{d:`m7 16.5-4.74-2.85`,key:`1o9zyk`}],[`path`,{d:`m7 16.5 5-3`,key:`va8pkn`}],[`path`,{d:`M7 16.5v5.17`,key:`jnp8gn`}],[`path`,{d:`M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z`,key:`8zsnat`}],[`path`,{d:`m17 16.5-5-3`,key:`8arw3v`}],[`path`,{d:`m17 16.5 4.74-2.85`,key:`8rfmw`}],[`path`,{d:`M17 16.5v5.17`,key:`k6z78m`}],[`path`,{d:`M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z`,key:`1xygjf`}],[`path`,{d:`M12 8 7.26 5.15`,key:`1vbdud`}],[`path`,{d:`m12 8 4.74-2.85`,key:`3rx089`}],[`path`,{d:`M12 13.5V8`,key:`1io7kd`}]]),E=d(`ShieldAlert`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M12 16h.01`,key:`1drbdi`}]]),D=class{constructor(e){this.authorizationManager=e,this.handleIframeMessage=({event:e,iframe:t})=>{this.isBridgeRequest(e.data)&&(!t?.contentWindow||e.source!==t.contentWindow||this.handleBridgeRequest({event:e,iframe:t},e.data))},this.handleBridgeRequest=async(e,t)=>{try{let n=this.getBridgeContext(t),r=await this.dispatchRequest(n,t);this.postResponse(e,{type:`nextclaw:panel-app-service-actions:response`,requestId:t.requestId,ok:!0,data:r})}catch(n){this.postResponse(e,{type:`nextclaw:panel-app-service-actions:response`,requestId:t.requestId,ok:!1,error:this.toBridgeError(n)})}},this.dispatchRequest=async(e,n)=>{switch(n.method){case`list`:return await t.serviceApps.listServiceActions({bridgeSessionToken:e.token});case`requestGrant`:return await this.confirmAndGrant(e,this.requireActionId(n));case`revokeGrant`:return await t.serviceApps.revokeServiceAction(this.requireActionId(n),{bridgeSessionToken:e.token});case`invoke`:return await this.invokeWithAuthorization(e,n);case`agent.send`:return await this.sendAgentMessageWithAuthorization(e,n);case`agent.generateObject`:return await this.generateAgentObjectWithAuthorization(e,n);case`verification.list`:return await t.serviceApps.listVerificationRecords({acceptanceId:n.payload?.acceptanceId,appId:n.payload?.appId,limit:n.payload?.limit,bridgeSessionToken:e.token});case`acceptance.status`:return await t.serviceApps.getPortableRuntimeAcceptanceStatus({appId:n.payload?.appId,locale:n.payload?.locale,bridgeSessionToken:e.token});case`acceptance.export`:return await t.serviceApps.exportPortableRuntimeAcceptance({appId:n.payload?.appId,locale:n.payload?.locale,bridgeSessionToken:e.token});default:throw Error(`Unsupported panel bridge method: ${String(n.method)}`)}},this.invokeWithAuthorization=async(e,n)=>{let r=this.requireActionId(n);try{return await t.serviceApps.invokeServiceAction(r,this.readOptionalRecord(n.payload?.input),{bridgeSessionToken:e.token})}catch(i){if(!(i instanceof c)||i.code!==`AUTHORIZATION_REQUIRED`)throw i;return await this.confirmAndGrant(e,r,this.readOptionalRecord(n.payload?.input)),await t.serviceApps.invokeServiceAction(r,this.readOptionalRecord(n.payload?.input),{bridgeSessionToken:e.token})}},this.sendAgentMessageWithAuthorization=async(e,n)=>{try{return await t.panelApps.sendAgentMessage(this.readAgentSendRequest(n),{bridgeSessionToken:e.token})}catch(r){if(!(r instanceof c)||r.code!==`AUTHORIZATION_REQUIRED`)throw r;return await this.confirmAndGrantAgentCapability(e,`agent:send`),await t.panelApps.sendAgentMessage(this.readAgentSendRequest(n),{bridgeSessionToken:e.token})}},this.generateAgentObjectWithAuthorization=async(e,n)=>{try{return await t.panelApps.generateAgentObject(this.readGenerateObjectRequest(n),{bridgeSessionToken:e.token})}catch(r){if(!(r instanceof c)||r.code!==`AUTHORIZATION_REQUIRED`)throw r;return await this.confirmAndGrantAgentCapability(e,`agent:generateObject`),await t.panelApps.generateAgentObject(this.readGenerateObjectRequest(n),{bridgeSessionToken:e.token})}},this.confirmAndGrantAgentCapability=async(e,n)=>{if(!await this.authorizationManager.requestAuthorization({panelAppId:e.appId,actions:[{actionId:n,actionTitle:n===`agent:send`?`Send agent message`:`Generate object`,actionDescription:n===`agent:send`?`Send a message to a NextClaw Agent session.`:`Send context to a NextClaw Agent session and receive a structured object.`,risk:`write`}]}))throw new c({code:`AUTHORIZATION_REJECTED`,message:`Permission rejected for ${n}.`});return await t.panelApps.grantAgentCapability(n,{bridgeSessionToken:e.token})},this.confirmAndGrant=async(e,n,r)=>{let i=await this.listGrantCandidateActions(e,n);if(!await this.authorizationManager.requestAuthorization({panelAppId:e.appId,actions:i.map(e=>({actionId:e.id,actionTitle:e.title,actionDescription:e.description,risk:e.risk})),inputPreview:this.createInputPreview(r)}))throw new c({code:`AUTHORIZATION_REJECTED`,message:`Permission rejected for ${n}.`});let a=await t.serviceApps.grantServiceActions(i.map(e=>e.id),{bridgeSessionToken:e.token}),o=a.grants.find(e=>e.actionId===n)??a.grants[0];if(!o)throw Error(`No permission grant returned for ${n}.`);return o},this.listGrantCandidateActions=async(e,n)=>{let r=await t.serviceApps.listServiceActions({bridgeSessionToken:e.token}),i=r.actions.find(e=>e.id===n);if(i&&i.grantState!==`not-granted`)return[i];let a=r.actions.filter(e=>e.grantState===`not-granted`),o=[...a.filter(e=>e.id===n),...a.filter(e=>e.id!==n)];return o.length>0?o:[{appId:i?.appId??n.split(`.`)[0]??n,description:i?.description,id:n,name:i?.name??n,risk:i?.risk??`dangerous`,title:i?.title}]},this.createInputPreview=e=>{if(!(!e||Object.keys(e).length===0))try{let t=JSON.stringify(e,null,2);return t.length>500?`${t.slice(0,500)}...`:t}catch{return`[unserializable input]`}},this.getBridgeContext=e=>({appId:e.appId,token:e.runtimeToken}),this.requireActionId=e=>{let t=e.payload?.actionId?.trim();if(!t)throw Error(`Panel bridge actionId is required.`);return t},this.readOptionalRecord=e=>{if(e!==void 0)return this.requireRecord(e,`input`)},this.readAgentSendRequest=e=>({payload:this.requireRecord(e.payload?.request,`agent.send request`)}),this.readGenerateObjectRequest=e=>({input:this.requireRecord(e.payload?.input,`generateObject input`)}),this.requireRecord=(e,t)=>{if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} is required.`);return e},this.postResponse=(e,t)=>{e.iframe?.contentWindow?.postMessage(t,`*`)},this.toBridgeError=e=>e instanceof c?{code:e.code,message:e.message,details:e.details}:{message:e instanceof Error?e.message:String(e)},this.isBridgeRequest=e=>{if(!e||typeof e!=`object`)return!1;let t=e;return t.type===`nextclaw:panel-app-service-actions:request`&&typeof t.requestId==`string`&&typeof t.runtimeToken==`string`&&typeof t.appId==`string`&&(t.method===`invoke`||t.method===`agent.send`||t.method===`agent.generateObject`||t.method===`acceptance.export`||t.method===`acceptance.status`||t.method===`list`||t.method===`requestGrant`||t.method===`revokeGrant`||t.method===`verification.list`)}}};function he(){return`service-action-auth-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}var O=s((e,t)=>({pending:null,requestAuthorization:async n=>await new Promise(r=>{t().pending?.resolve(!1),e({pending:{id:he(),...n,resolve:r}})}),resolveAuthorization:n=>{let{pending:r}=t();r&&(r.resolve(n),e({pending:null}))}})),ge=class{constructor(){this.requestAuthorization=async e=>await O.getState().requestAuthorization(e)}},k=class{constructor(){this.serviceActionAuthorizationManager=new ge,this.panelAppBridgeManager=new D(this.serviceActionAuthorizationManager)}},A=e(u(),1),j=ee(),M=globalThis,N=M.__NEXTCLAW_PANEL_APP_HOST_CONTEXT__??(0,A.createContext)(null);M.__NEXTCLAW_PANEL_APP_HOST_CONTEXT__=N;function P({children:e,presenter:t}){let n=(0,A.useMemo)(()=>t??new k,[t]);return(0,j.jsx)(N.Provider,{value:n,children:e})}function F(){let e=(0,A.useContext)(N);if(!e)throw Error(`usePanelAppHostPresenter must be used inside PanelAppHostProvider`);return e}var I=[`panel-apps`],L=[`panel-app`];function R(e,t){return e.id===t||e.appId===t}function z(e,t,n){return e&&{...e,entries:e.entries.map(e=>R(e,t)?n(e):e)}}function B(e,t){return z(e,t.id,()=>t)}function V(e,t){let n=e?.entries.reduce((e,t)=>Math.max(e,t.mainSidebarOrder??-1),-1)??-1;return z(e,t.id,e=>({...e,...typeof t.preferences.favorite==`boolean`?{favorite:t.preferences.favorite}:{},...typeof t.preferences.mainSidebar==`boolean`?t.preferences.mainSidebar?{mainSidebar:!0,mainSidebarOrder:e.mainSidebar?e.mainSidebarOrder:n+1}:{mainSidebar:!1,mainSidebarOrder:void 0}:{}}))}function _e(e={}){return n({queryKey:I,queryFn:()=>t.panelApps.listPanelApps(),enabled:e.enabled??!0,staleTime:0})}function H(e,r={}){return n({queryKey:[...L,e],queryFn:()=>t.panelApps.getPanelApp(e),enabled:!!e&&(r.enabled??!0),staleTime:5e3})}function ve(){let e=l();return o({mutationFn:({id:e,preferences:n})=>t.panelApps.updatePanelAppPreferences(e,n),onMutate:async t=>{await e.cancelQueries({queryKey:I});let n=e.getQueryData(I)?.entries.find(e=>R(e,t.id));return e.setQueryData(I,e=>V(e,t)),{previousEntry:n}},onSuccess:t=>{e.setQueryData(I,e=>B(e,t)),e.setQueryData([...L,t.appId],t)},onError:(t,n,r)=>{let a=r?.previousEntry;a&&e.setQueryData(I,e=>z(e,n.id,()=>a));let o=t instanceof Error?t.message:String(t);i.error(`${m(`panelAppsPreferenceUpdateFailed`)}: ${o}`)}})}function ye(){let e=l();return o({mutationFn:e=>t.panelApps.recordPanelAppOpened(e),onSuccess:t=>{e.setQueryData(I,e=>B(e,t)),e.setQueryData([...L,t.appId],t)}})}function U(){let e=l();return o({mutationFn:e=>t.panelApps.grantClient(e),onSuccess:()=>{e.invalidateQueries({queryKey:I}),e.invalidateQueries({queryKey:L})}})}function be(){let e=l();return o({mutationFn:e=>t.panelApps.deletePanelApp(e),onSuccess:()=>{e.invalidateQueries({queryKey:I}),e.invalidateQueries({queryKey:L})}})}function W(){let e=F(),{isPending:t,mutateAsync:n}=U(),r=(0,A.useRef)(new Map);return{ensurePanelAppClientGrant:(0,A.useCallback)(async t=>{if(!t.clientDeclared||t.clientGranted)return!0;let i=r.current.get(t.appId);if(i)return await i;let a=(async()=>await e.serviceActionAuthorizationManager.requestAuthorization({panelAppId:t.appId,actions:[{actionId:`nextclaw.client`,actionTitle:m(`panelAppsClientGrantTitle`),actionDescription:m(`panelAppsClientGrantDescription`),risk:`dangerous`}]})?(await n(t.appId),!0):!1)();r.current.set(t.appId,a);try{return await a}finally{r.current.delete(t.appId)}},[n,e]),isPending:t}}function xe(e){let r=l(),i=(0,A.useId)(),{ensurePanelAppClientGrant:a}=W(),o=!!(e?.clientDeclared&&!e.clientGranted),s=n({queryKey:[`panel-app-client-grant`,e?.appId??`none`,e?.clientGranted??!1],queryFn:async()=>await a(e),enabled:o,gcTime:0,retry:!1,staleTime:1/0}),c=e?o?s.isError?`error`:s.isPending?`checking`:s.data?`allowed`:`denied`:`allowed`:`idle`;return n({queryKey:[`panel-app-open`,i,e?.appId??`none`],queryFn:async()=>{let n=await t.panelApps.recordPanelAppOpened(e.id);return r.setQueryData(I,e=>B(e,n)),r.setQueryData([...L,n.appId],n),n},enabled:!!(e&&c===`allowed`),retry:!1,staleTime:1/0}),{retryClientGrant:s.refetch,state:c}}var G=`allow-scripts allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-downloads allow-pointer-lock allow-presentation`;function K(e){e?.focus({preventScroll:!0}),e?.contentWindow?.focus()}function q(e){if(!e||typeof e!=`object`)return!1;let t=e;return t.kind===`document`?!0:t.kind===`element`&&Array.isArray(t.path)&&t.path.length>0&&t.path.length<=30&&t.path.every(e=>typeof e?.index==`number`&&Number.isInteger(e.index)&&e.index>=0&&e.index<=1e3&&typeof e.tagName==`string`&&e.tagName.length>0&&e.tagName.length<=32)}function Se(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.currentUrl==`string`&&q(t.target)}function Ce(e){if(!e||typeof e!=`object`)return!1;let t=e;return t.type===r.scrollMessageType&&t.version===r.version&&q(t.target)&&typeof t.x==`number`&&Number.isFinite(t.x)&&t.x>=0&&typeof t.y==`number`&&Number.isFinite(t.y)&&t.y>=0}function J({currentUrl:e,iframeRef:t,isEnabled:n,restorationKey:i}){let a=i&&e?JSON.stringify([i,e]):null;return(0,A.useEffect)(()=>{if(!e||!n||!a)return;let r=a,i=n=>{n.source!==t.current?.contentWindow||!Ce(n.data)||g.save(r,{x:n.data.x,y:n.data.y,payload:{currentUrl:e,target:n.data.target}})};return window.addEventListener(`message`,i),()=>window.removeEventListener(`message`,i)},[e,t,n,a]),(0,A.useCallback)(()=>{if(!e||!n||!a)return;let i=g.read(a);!i||!Se(i.payload)||i.payload.currentUrl!==e||t.current?.contentWindow?.postMessage({type:r.restoreScrollMessageType,version:r.version,target:i.payload.target,x:i.x,y:i.y},`*`)},[e,t,n,a])}function Y({appId:e,restorationScope:t,unavailableAction:n}){let r=F(),i=H(e),a=(0,A.useRef)(null),o=(0,A.useMemo)(()=>i.data,[i.data]),s=xe(o),c=J({currentUrl:o?.contentPath??null,iframeRef:a,isEnabled:!!o,restorationKey:o?`panel-app:${t}:${o.appId}`:null});return(0,A.useEffect)(()=>{let e=e=>{r.panelAppBridgeManager.handleIframeMessage({event:e,iframe:a.current})};return window.addEventListener(`message`,e),()=>window.removeEventListener(`message`,e)},[r]),i.isLoading?(0,j.jsx)(X,{message:m(`panelAppsLoading`)}):i.isError?(0,j.jsx)(X,{message:i.error instanceof Error?i.error.message:m(`panelAppsLoadFailed`),actionLabel:m(`panelAppsTryAgain`),onAction:()=>void i.refetch()}):o?s.state===`checking`||s.state===`idle`?(0,j.jsx)(X,{message:m(`panelAppsCheckingPermission`)}):s.state===`denied`||s.state===`error`?(0,j.jsx)(X,{message:s.state===`denied`?m(`panelAppsPermissionDenied`):m(`panelAppsPermissionFailed`),actionLabel:m(`panelAppsTryAgain`),onAction:()=>void s.retryClientGrant()}):(0,j.jsx)(`div`,{className:`h-full min-h-0 bg-background`,children:(0,j.jsx)(`iframe`,{ref:a,src:o.contentPath,title:o.title,sandbox:G,className:`block h-full w-full border-0 bg-background`,onLoad:c,onPointerOver:e=>K(e.currentTarget)},o.appId)}):(0,j.jsx)(X,{message:m(`panelAppsMainUnavailable`),actionLabel:n?.label,onAction:n?.onAction})}function X({actionLabel:e,message:t,onAction:n}){return(0,j.jsx)(`div`,{className:`flex h-full min-h-0 items-center justify-center bg-background px-6 text-center`,children:(0,j.jsxs)(`div`,{className:`max-w-sm`,children:[(0,j.jsx)(`div`,{className:`mx-auto flex h-10 w-10 items-center justify-center rounded-lg bg-muted text-muted-foreground`,children:n?(0,j.jsx)(te,{className:`h-5 w-5`}):(0,j.jsx)(T,{className:`h-5 w-5`})}),(0,j.jsx)(`p`,{className:`mt-3 text-sm leading-6 text-muted-foreground`,children:t}),e&&n?(0,j.jsx)(`button`,{type:`button`,className:`mt-4 rounded-md border border-border px-3 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border`,onClick:n,children:e}):null]})})}var Z=(0,A.createContext)(null);function we({children:e}){let[t,n]=(0,A.useState)(()=>ne());(0,A.useEffect)(()=>p(e=>{n(e)}),[]);let r=(0,A.useCallback)(e=>{re(e),n(f())},[]),i=(0,A.useCallback)(()=>{r(t===`en`?`zh`:`en`)},[t,r]),a=(0,A.useMemo)(()=>({language:t,setLanguage:r,toggleLanguage:i}),[t,r,i]);return(0,j.jsx)(Z.Provider,{value:a,children:e})}function Te(){let e=(0,A.useContext)(Z);if(!e)throw Error(`useI18n must be used within I18nProvider`);return{...e,t:m}}function Ee({appId:e}){let t=H(e),n=(0,A.useMemo)(()=>t.data,[t.data]);return(0,A.useEffect)(()=>{let e=document.title;return document.title=`${n?.title??m(`panelAppsTitle`)} · NextClaw`,()=>{document.title=e}},[n?.title]),(0,j.jsx)(`main`,{className:`h-dvh min-h-0 w-full overflow-hidden bg-background`,children:(0,j.jsx)(Y,{appId:e,restorationScope:`standalone`})})}function De(){let e=O(e=>e.pending),t=O(e=>e.resolveAuthorization);return(0,j.jsx)(ce,{open:!!e,onOpenChange:e=>{e||t(!1)},children:(0,j.jsxs)(oe,{children:[(0,j.jsxs)(ie,{showClose:!1,children:[(0,j.jsxs)(h,{className:`flex items-center gap-2`,children:[(0,j.jsx)(E,{className:`h-4 w-4 text-amber-600`}),m(`serviceActionAuthorizationTitle`)]}),(0,j.jsx)(se,{children:m(`serviceActionAuthorizationDescription`)})]}),e?(0,j.jsxs)(`div`,{className:`space-y-3 rounded-md border border-border bg-muted/60 p-3 text-sm`,children:[(0,j.jsx)(Q,{label:m(`serviceActionAuthorizationSource`),value:e.panelAppId}),(0,j.jsxs)(`div`,{className:`space-y-2`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:m(`serviceActionAuthorizationActions`)}),(0,j.jsx)(`div`,{className:`max-h-64 space-y-2 overflow-auto`,children:e.actions.map(e=>(0,j.jsx)(Oe,{action:e},e.actionId))})]}),e.inputPreview?(0,j.jsx)(Q,{label:m(`serviceActionAuthorizationInput`),value:e.inputPreview}):null]}):null,(0,j.jsxs)(ae,{className:`gap-2 sm:gap-0`,children:[(0,j.jsx)(a,{type:`button`,variant:`outline`,onClick:()=>t(!1),children:m(`serviceActionAuthorizationReject`)}),(0,j.jsx)(a,{type:`button`,onClick:()=>t(!0),children:m(`serviceActionAuthorizationAllow`)})]})]})})}function Oe({action:e}){return(0,j.jsxs)(`div`,{className:`space-y-1 rounded border border-border bg-card px-3 py-2`,children:[(0,j.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,j.jsx)(`div`,{className:`min-w-0 break-words text-xs font-medium text-foreground`,children:e.actionTitle??e.actionId}),(0,j.jsx)(`div`,{className:`shrink-0 rounded bg-amber-50 px-1.5 py-0.5 text-[11px] font-medium text-amber-700`,children:e.risk??`dangerous`})]}),(0,j.jsx)(`div`,{className:`break-words text-[11px] text-muted-foreground`,children:e.actionId}),e.actionDescription?(0,j.jsx)(`div`,{className:`break-words text-xs text-muted-foreground`,children:e.actionDescription}):null]})}function Q({label:e,value:t}){return(0,j.jsxs)(`div`,{className:`grid grid-cols-[5rem_minmax(0,1fr)] gap-3`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:e}),(0,j.jsx)(`div`,{className:`min-w-0 break-words text-xs text-foreground`,children:t})]})}var $=(0,A.createContext)(null);function ke({children:e}){let[t,n]=(0,A.useState)(()=>w());(0,A.useEffect)(()=>me(e=>{n(e)}),[]);let r=(0,A.useCallback)(e=>{pe(e),n(fe())},[]),i=(0,A.useMemo)(()=>({theme:t,setTheme:r}),[t,r]);return(0,j.jsx)($.Provider,{value:i,children:e})}function Ae(){let e=(0,A.useContext)($);if(!e)throw Error(`useTheme must be used within ThemeProvider`);return e}export{v as C,x as D,w as E,y as O,T as S,S as T,ve as _,we as a,D as b,J as c,W as d,be as f,ye as g,_e as h,Ee as i,G as l,H as m,Ae as n,Te as o,U as p,De as r,Y as s,ke as t,K as u,P as v,de as w,E as x,k as y};
|
|
1
|
+
import{i as e}from"./chunk-DF37yw5_.js";import{Lt as t,Qn as n,Sn as r,Xn as i,Yt as a,Zn as o,fn as s,hn as c,lr as l,ur as ee,xr as u}from"./api-CXWxExzS.js";import{t as d}from"./createLucideIcon-C3LSyx-e.js";import{J as te}from"./context-menu-C6m-WNpl.js";import{d as ne,f as re,l as f,p,s as m}from"./i18n-ByVUrt9w.js";import{a as ie,i as ae,n as oe,o as h,r as se,t as ce}from"./dialog-DB_l9LK0.js";import{n as g}from"./navigation-history-CCnxsAKR.js";var _=`nextclaw.ui.theme`,v=`default`,le=`plain-paper`;function y(e){return e===`default`?le:e}var b=[{value:`default`,labelKey:`themeDefault`,appearance:`light`},{value:`plain-paper`,labelKey:`themePlainPaper`,appearance:`light`},{value:`paper-ink`,labelKey:`themePaperInk`,appearance:`light`},{value:`work`,labelKey:`themeWork`,appearance:`light`},{value:`night`,labelKey:`themeNight`,appearance:`dark`},{value:`charcoal`,labelKey:`themeCharcoal`,appearance:`dark`},{value:`island`,labelKey:`themeIsland`,appearance:`light`},{value:`natural`,labelKey:`themeNatural`,appearance:`light`},{value:`minimal`,labelKey:`themeMinimal`,appearance:`light`},{value:`warm`,labelKey:`themeWarm`,appearance:`light`},{value:`cool`,labelKey:`themeCool`,appearance:`light`},{value:`dawn`,labelKey:`themeDawn`,appearance:`light`},{value:`graphite`,labelKey:`themeGraphite`,appearance:`light`},{value:`probe`,labelKey:`themeProbe`,appearance:`light`}],ue=b.map(({value:e})=>e),de=b.map(({value:e,labelKey:t})=>({value:e,labelKey:t}));function x(e){return typeof e==`string`?ue.includes(e)?e:e===`leaf`?`warm`:null:null}function S(e){return b.find(t=>t.value===y(e))?.appearance??`light`}var C=new class{constructor(){this.activeTheme=v,this.initialized=!1,this.listeners=new Set,this.resolveInitialTheme=()=>{if(typeof window>`u`)return v;try{let e=x(window.localStorage.getItem(_));if(e)return e}catch{}return v},this.initializeTheme=()=>(this.initialized||=(this.activeTheme=this.resolveInitialTheme(),this.applyThemeAttribute(this.activeTheme),!0),this.activeTheme),this.getTheme=()=>this.initialized?this.activeTheme:this.initializeTheme(),this.setTheme=e=>{this.initializeTheme(),e!==this.activeTheme&&(this.activeTheme=e,this.applyThemeAttribute(this.activeTheme),this.saveTheme(this.activeTheme),this.listeners.forEach(e=>e(this.activeTheme)))},this.subscribeThemeChange=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)}),this.applyThemeAttribute=e=>{if(typeof document>`u`)return;let t=S(e);document.documentElement.setAttribute(`data-theme`,y(e)),document.documentElement.setAttribute(`data-theme-appearance`,t),document.documentElement.style.colorScheme=t},this.saveTheme=e=>{if(!(typeof window>`u`))try{window.localStorage.setItem(_,e)}catch{}}}};function w(){return C.initializeTheme()}function fe(){return C.getTheme()}function pe(e){C.setTheme(e)}function me(e){return C.subscribeThemeChange(e)}var T=d(`Boxes`,[[`path`,{d:`M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z`,key:`lc1i9w`}],[`path`,{d:`m7 16.5-4.74-2.85`,key:`1o9zyk`}],[`path`,{d:`m7 16.5 5-3`,key:`va8pkn`}],[`path`,{d:`M7 16.5v5.17`,key:`jnp8gn`}],[`path`,{d:`M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z`,key:`8zsnat`}],[`path`,{d:`m17 16.5-5-3`,key:`8arw3v`}],[`path`,{d:`m17 16.5 4.74-2.85`,key:`8rfmw`}],[`path`,{d:`M17 16.5v5.17`,key:`k6z78m`}],[`path`,{d:`M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z`,key:`1xygjf`}],[`path`,{d:`M12 8 7.26 5.15`,key:`1vbdud`}],[`path`,{d:`m12 8 4.74-2.85`,key:`3rx089`}],[`path`,{d:`M12 13.5V8`,key:`1io7kd`}]]),E=d(`ShieldAlert`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M12 16h.01`,key:`1drbdi`}]]),D=class{constructor(e){this.authorizationManager=e,this.handleIframeMessage=({event:e,iframe:t})=>{this.isBridgeRequest(e.data)&&(!t?.contentWindow||e.source!==t.contentWindow||this.handleBridgeRequest({event:e,iframe:t},e.data))},this.handleBridgeRequest=async(e,t)=>{try{let n=this.getBridgeContext(t),r=await this.dispatchRequest(n,t);this.postResponse(e,{type:`nextclaw:panel-app-service-actions:response`,requestId:t.requestId,ok:!0,data:r})}catch(n){this.postResponse(e,{type:`nextclaw:panel-app-service-actions:response`,requestId:t.requestId,ok:!1,error:this.toBridgeError(n)})}},this.dispatchRequest=async(e,n)=>{switch(n.method){case`list`:return await t.serviceApps.listServiceActions({bridgeSessionToken:e.token});case`requestGrant`:return await this.confirmAndGrant(e,this.requireActionId(n));case`revokeGrant`:return await t.serviceApps.revokeServiceAction(this.requireActionId(n),{bridgeSessionToken:e.token});case`invoke`:return await this.invokeWithAuthorization(e,n);case`agent.send`:return await this.sendAgentMessageWithAuthorization(e,n);case`agent.generateObject`:return await this.generateAgentObjectWithAuthorization(e,n);case`verification.list`:return await t.serviceApps.listVerificationRecords({acceptanceId:n.payload?.acceptanceId,appId:n.payload?.appId,limit:n.payload?.limit,bridgeSessionToken:e.token});case`acceptance.status`:return await t.serviceApps.getPortableRuntimeAcceptanceStatus({appId:n.payload?.appId,locale:n.payload?.locale,bridgeSessionToken:e.token});case`acceptance.export`:return await t.serviceApps.exportPortableRuntimeAcceptance({appId:n.payload?.appId,locale:n.payload?.locale,bridgeSessionToken:e.token});default:throw Error(`Unsupported panel bridge method: ${String(n.method)}`)}},this.invokeWithAuthorization=async(e,n)=>{let r=this.requireActionId(n);try{return await t.serviceApps.invokeServiceAction(r,this.readOptionalRecord(n.payload?.input),{bridgeSessionToken:e.token})}catch(i){if(!(i instanceof c)||i.code!==`AUTHORIZATION_REQUIRED`)throw i;return await this.confirmAndGrant(e,r,this.readOptionalRecord(n.payload?.input)),await t.serviceApps.invokeServiceAction(r,this.readOptionalRecord(n.payload?.input),{bridgeSessionToken:e.token})}},this.sendAgentMessageWithAuthorization=async(e,n)=>{try{return await t.panelApps.sendAgentMessage(this.readAgentSendRequest(n),{bridgeSessionToken:e.token})}catch(r){if(!(r instanceof c)||r.code!==`AUTHORIZATION_REQUIRED`)throw r;return await this.confirmAndGrantAgentCapability(e,`agent:send`),await t.panelApps.sendAgentMessage(this.readAgentSendRequest(n),{bridgeSessionToken:e.token})}},this.generateAgentObjectWithAuthorization=async(e,n)=>{try{return await t.panelApps.generateAgentObject(this.readGenerateObjectRequest(n),{bridgeSessionToken:e.token})}catch(r){if(!(r instanceof c)||r.code!==`AUTHORIZATION_REQUIRED`)throw r;return await this.confirmAndGrantAgentCapability(e,`agent:generateObject`),await t.panelApps.generateAgentObject(this.readGenerateObjectRequest(n),{bridgeSessionToken:e.token})}},this.confirmAndGrantAgentCapability=async(e,n)=>{if(!await this.authorizationManager.requestAuthorization({panelAppId:e.appId,actions:[{actionId:n,actionTitle:n===`agent:send`?`Send agent message`:`Generate object`,actionDescription:n===`agent:send`?`Send a message to a NextClaw Agent session.`:`Send context to a NextClaw Agent session and receive a structured object.`,risk:`write`}]}))throw new c({code:`AUTHORIZATION_REJECTED`,message:`Permission rejected for ${n}.`});return await t.panelApps.grantAgentCapability(n,{bridgeSessionToken:e.token})},this.confirmAndGrant=async(e,n,r)=>{let i=await this.listGrantCandidateActions(e,n);if(!await this.authorizationManager.requestAuthorization({panelAppId:e.appId,actions:i.map(e=>({actionId:e.id,actionTitle:e.title,actionDescription:e.description,risk:e.risk})),inputPreview:this.createInputPreview(r)}))throw new c({code:`AUTHORIZATION_REJECTED`,message:`Permission rejected for ${n}.`});let a=await t.serviceApps.grantServiceActions(i.map(e=>e.id),{bridgeSessionToken:e.token}),o=a.grants.find(e=>e.actionId===n)??a.grants[0];if(!o)throw Error(`No permission grant returned for ${n}.`);return o},this.listGrantCandidateActions=async(e,n)=>{let r=await t.serviceApps.listServiceActions({bridgeSessionToken:e.token}),i=r.actions.find(e=>e.id===n);if(i&&i.grantState!==`not-granted`)return[i];let a=r.actions.filter(e=>e.grantState===`not-granted`),o=[...a.filter(e=>e.id===n),...a.filter(e=>e.id!==n)];return o.length>0?o:[{appId:i?.appId??n.split(`.`)[0]??n,description:i?.description,id:n,name:i?.name??n,risk:i?.risk??`dangerous`,title:i?.title}]},this.createInputPreview=e=>{if(!(!e||Object.keys(e).length===0))try{let t=JSON.stringify(e,null,2);return t.length>500?`${t.slice(0,500)}...`:t}catch{return`[unserializable input]`}},this.getBridgeContext=e=>({appId:e.appId,token:e.runtimeToken}),this.requireActionId=e=>{let t=e.payload?.actionId?.trim();if(!t)throw Error(`Panel bridge actionId is required.`);return t},this.readOptionalRecord=e=>{if(e!==void 0)return this.requireRecord(e,`input`)},this.readAgentSendRequest=e=>({payload:this.requireRecord(e.payload?.request,`agent.send request`)}),this.readGenerateObjectRequest=e=>({input:this.requireRecord(e.payload?.input,`generateObject input`)}),this.requireRecord=(e,t)=>{if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} is required.`);return e},this.postResponse=(e,t)=>{e.iframe?.contentWindow?.postMessage(t,`*`)},this.toBridgeError=e=>e instanceof c?{code:e.code,message:e.message,details:e.details}:{message:e instanceof Error?e.message:String(e)},this.isBridgeRequest=e=>{if(!e||typeof e!=`object`)return!1;let t=e;return t.type===`nextclaw:panel-app-service-actions:request`&&typeof t.requestId==`string`&&typeof t.runtimeToken==`string`&&typeof t.appId==`string`&&(t.method===`invoke`||t.method===`agent.send`||t.method===`agent.generateObject`||t.method===`acceptance.export`||t.method===`acceptance.status`||t.method===`list`||t.method===`requestGrant`||t.method===`revokeGrant`||t.method===`verification.list`)}}};function he(){return`service-action-auth-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}var O=s((e,t)=>({pending:null,requestAuthorization:async n=>await new Promise(r=>{t().pending?.resolve(!1),e({pending:{id:he(),...n,resolve:r}})}),resolveAuthorization:n=>{let{pending:r}=t();r&&(r.resolve(n),e({pending:null}))}})),ge=class{constructor(){this.requestAuthorization=async e=>await O.getState().requestAuthorization(e)}},k=class{constructor(){this.serviceActionAuthorizationManager=new ge,this.panelAppBridgeManager=new D(this.serviceActionAuthorizationManager)}},A=e(u(),1),j=ee(),M=globalThis,N=M.__NEXTCLAW_PANEL_APP_HOST_CONTEXT__??(0,A.createContext)(null);M.__NEXTCLAW_PANEL_APP_HOST_CONTEXT__=N;function P({children:e,presenter:t}){let n=(0,A.useMemo)(()=>t??new k,[t]);return(0,j.jsx)(N.Provider,{value:n,children:e})}function F(){let e=(0,A.useContext)(N);if(!e)throw Error(`usePanelAppHostPresenter must be used inside PanelAppHostProvider`);return e}var I=[`panel-apps`],L=[`panel-app`];function R(e,t){return e.id===t||e.appId===t}function z(e,t,n){return e&&{...e,entries:e.entries.map(e=>R(e,t)?n(e):e)}}function B(e,t){return z(e,t.id,()=>t)}function V(e,t){let n=e?.entries.reduce((e,t)=>Math.max(e,t.mainSidebarOrder??-1),-1)??-1;return z(e,t.id,e=>({...e,...typeof t.preferences.favorite==`boolean`?{favorite:t.preferences.favorite}:{},...typeof t.preferences.mainSidebar==`boolean`?t.preferences.mainSidebar?{mainSidebar:!0,mainSidebarOrder:e.mainSidebar?e.mainSidebarOrder:n+1}:{mainSidebar:!1,mainSidebarOrder:void 0}:{}}))}function _e(e={}){return n({queryKey:I,queryFn:()=>t.panelApps.listPanelApps(),enabled:e.enabled??!0,staleTime:0})}function H(e,r={}){return n({queryKey:[...L,e],queryFn:()=>t.panelApps.getPanelApp(e),enabled:!!e&&(r.enabled??!0),staleTime:5e3})}function ve(){let e=l();return o({mutationFn:({id:e,preferences:n})=>t.panelApps.updatePanelAppPreferences(e,n),onMutate:async t=>{await e.cancelQueries({queryKey:I});let n=e.getQueryData(I)?.entries.find(e=>R(e,t.id));return e.setQueryData(I,e=>V(e,t)),{previousEntry:n}},onSuccess:t=>{e.setQueryData(I,e=>B(e,t)),e.setQueryData([...L,t.appId],t)},onError:(t,n,r)=>{let a=r?.previousEntry;a&&e.setQueryData(I,e=>z(e,n.id,()=>a));let o=t instanceof Error?t.message:String(t);i.error(`${m(`panelAppsPreferenceUpdateFailed`)}: ${o}`)}})}function ye(){let e=l();return o({mutationFn:e=>t.panelApps.recordPanelAppOpened(e),onSuccess:t=>{e.setQueryData(I,e=>B(e,t)),e.setQueryData([...L,t.appId],t)}})}function U(){let e=l();return o({mutationFn:e=>t.panelApps.grantClient(e),onSuccess:()=>{e.invalidateQueries({queryKey:I}),e.invalidateQueries({queryKey:L})}})}function be(){let e=l();return o({mutationFn:e=>t.panelApps.deletePanelApp(e),onSuccess:()=>{e.invalidateQueries({queryKey:I}),e.invalidateQueries({queryKey:L})}})}function W(){let e=F(),{isPending:t,mutateAsync:n}=U(),r=(0,A.useRef)(new Map);return{ensurePanelAppClientGrant:(0,A.useCallback)(async t=>{if(!t.clientDeclared||t.clientGranted)return!0;let i=r.current.get(t.appId);if(i)return await i;let a=(async()=>await e.serviceActionAuthorizationManager.requestAuthorization({panelAppId:t.appId,actions:[{actionId:`nextclaw.client`,actionTitle:m(`panelAppsClientGrantTitle`),actionDescription:m(`panelAppsClientGrantDescription`),risk:`dangerous`}]})?(await n(t.appId),!0):!1)();r.current.set(t.appId,a);try{return await a}finally{r.current.delete(t.appId)}},[n,e]),isPending:t}}function xe(e){let r=l(),i=(0,A.useId)(),{ensurePanelAppClientGrant:a}=W(),o=!!(e?.clientDeclared&&!e.clientGranted),s=n({queryKey:[`panel-app-client-grant`,e?.appId??`none`,e?.clientGranted??!1],queryFn:async()=>await a(e),enabled:o,gcTime:0,retry:!1,staleTime:1/0}),c=e?o?s.isError?`error`:s.isPending?`checking`:s.data?`allowed`:`denied`:`allowed`:`idle`;return n({queryKey:[`panel-app-open`,i,e?.appId??`none`],queryFn:async()=>{let n=await t.panelApps.recordPanelAppOpened(e.id);return r.setQueryData(I,e=>B(e,n)),r.setQueryData([...L,n.appId],n),n},enabled:!!(e&&c===`allowed`),retry:!1,staleTime:1/0}),{retryClientGrant:s.refetch,state:c}}var G=`allow-scripts allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-downloads allow-pointer-lock allow-presentation`;function K(e){e?.focus({preventScroll:!0}),e?.contentWindow?.focus()}function q(e){if(!e||typeof e!=`object`)return!1;let t=e;return t.kind===`document`?!0:t.kind===`element`&&Array.isArray(t.path)&&t.path.length>0&&t.path.length<=30&&t.path.every(e=>typeof e?.index==`number`&&Number.isInteger(e.index)&&e.index>=0&&e.index<=1e3&&typeof e.tagName==`string`&&e.tagName.length>0&&e.tagName.length<=32)}function Se(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.currentUrl==`string`&&q(t.target)}function Ce(e){if(!e||typeof e!=`object`)return!1;let t=e;return t.type===r.scrollMessageType&&t.version===r.version&&q(t.target)&&typeof t.x==`number`&&Number.isFinite(t.x)&&t.x>=0&&typeof t.y==`number`&&Number.isFinite(t.y)&&t.y>=0}function J({currentUrl:e,iframeRef:t,isEnabled:n,restorationKey:i}){let a=i&&e?JSON.stringify([i,e]):null;return(0,A.useEffect)(()=>{if(!e||!n||!a)return;let r=a,i=n=>{n.source!==t.current?.contentWindow||!Ce(n.data)||g.save(r,{x:n.data.x,y:n.data.y,payload:{currentUrl:e,target:n.data.target}})};return window.addEventListener(`message`,i),()=>window.removeEventListener(`message`,i)},[e,t,n,a]),(0,A.useCallback)(()=>{if(!e||!n||!a)return;let i=g.read(a);!i||!Se(i.payload)||i.payload.currentUrl!==e||t.current?.contentWindow?.postMessage({type:r.restoreScrollMessageType,version:r.version,target:i.payload.target,x:i.x,y:i.y},`*`)},[e,t,n,a])}function Y({appId:e,restorationScope:t,refreshVersion:n=0,unavailableAction:r}){let i=F(),a=H(e),o=(0,A.useRef)(null),s=(0,A.useMemo)(()=>a.data,[a.data]),c=xe(s),l=J({currentUrl:s?.contentPath??null,iframeRef:o,isEnabled:!!s,restorationKey:s?`panel-app:${t}:${s.appId}`:null});return(0,A.useEffect)(()=>{let e=e=>{i.panelAppBridgeManager.handleIframeMessage({event:e,iframe:o.current})};return window.addEventListener(`message`,e),()=>window.removeEventListener(`message`,e)},[i]),a.isLoading?(0,j.jsx)(X,{message:m(`panelAppsLoading`)}):a.isError?(0,j.jsx)(X,{message:a.error instanceof Error?a.error.message:m(`panelAppsLoadFailed`),actionLabel:m(`panelAppsTryAgain`),onAction:()=>void a.refetch()}):s?c.state===`checking`||c.state===`idle`?(0,j.jsx)(X,{message:m(`panelAppsCheckingPermission`)}):c.state===`denied`||c.state===`error`?(0,j.jsx)(X,{message:c.state===`denied`?m(`panelAppsPermissionDenied`):m(`panelAppsPermissionFailed`),actionLabel:m(`panelAppsTryAgain`),onAction:()=>void c.retryClientGrant()}):(0,j.jsx)(`div`,{className:`h-full min-h-0 bg-background`,children:(0,j.jsx)(`iframe`,{ref:o,src:s.contentPath,title:s.title,sandbox:G,className:`block h-full w-full border-0 bg-background`,onLoad:l,onPointerOver:e=>K(e.currentTarget)},`${s.appId}:${n}`)}):(0,j.jsx)(X,{message:m(`panelAppsMainUnavailable`),actionLabel:r?.label,onAction:r?.onAction})}function X({actionLabel:e,message:t,onAction:n}){return(0,j.jsx)(`div`,{className:`flex h-full min-h-0 items-center justify-center bg-background px-6 text-center`,children:(0,j.jsxs)(`div`,{className:`max-w-sm`,children:[(0,j.jsx)(`div`,{className:`mx-auto flex h-10 w-10 items-center justify-center rounded-lg bg-muted text-muted-foreground`,children:n?(0,j.jsx)(te,{className:`h-5 w-5`}):(0,j.jsx)(T,{className:`h-5 w-5`})}),(0,j.jsx)(`p`,{className:`mt-3 text-sm leading-6 text-muted-foreground`,children:t}),e&&n?(0,j.jsx)(`button`,{type:`button`,className:`mt-4 rounded-md border border-border px-3 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border`,onClick:n,children:e}):null]})})}var Z=(0,A.createContext)(null);function we({children:e}){let[t,n]=(0,A.useState)(()=>ne());(0,A.useEffect)(()=>p(e=>{n(e)}),[]);let r=(0,A.useCallback)(e=>{re(e),n(f())},[]),i=(0,A.useCallback)(()=>{r(t===`en`?`zh`:`en`)},[t,r]),a=(0,A.useMemo)(()=>({language:t,setLanguage:r,toggleLanguage:i}),[t,r,i]);return(0,j.jsx)(Z.Provider,{value:a,children:e})}function Te(){let e=(0,A.useContext)(Z);if(!e)throw Error(`useI18n must be used within I18nProvider`);return{...e,t:m}}function Ee({appId:e}){let t=H(e),n=(0,A.useMemo)(()=>t.data,[t.data]);return(0,A.useEffect)(()=>{let e=document.title;return document.title=`${n?.title??m(`panelAppsTitle`)} · NextClaw`,()=>{document.title=e}},[n?.title]),(0,j.jsx)(`main`,{className:`h-dvh min-h-0 w-full overflow-hidden bg-background`,children:(0,j.jsx)(Y,{appId:e,restorationScope:`standalone`})})}function De(){let e=O(e=>e.pending),t=O(e=>e.resolveAuthorization);return(0,j.jsx)(ce,{open:!!e,onOpenChange:e=>{e||t(!1)},children:(0,j.jsxs)(oe,{children:[(0,j.jsxs)(ie,{showClose:!1,children:[(0,j.jsxs)(h,{className:`flex items-center gap-2`,children:[(0,j.jsx)(E,{className:`h-4 w-4 text-amber-600`}),m(`serviceActionAuthorizationTitle`)]}),(0,j.jsx)(se,{children:m(`serviceActionAuthorizationDescription`)})]}),e?(0,j.jsxs)(`div`,{className:`space-y-3 rounded-md border border-border bg-muted/60 p-3 text-sm`,children:[(0,j.jsx)(Q,{label:m(`serviceActionAuthorizationSource`),value:e.panelAppId}),(0,j.jsxs)(`div`,{className:`space-y-2`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:m(`serviceActionAuthorizationActions`)}),(0,j.jsx)(`div`,{className:`max-h-64 space-y-2 overflow-auto`,children:e.actions.map(e=>(0,j.jsx)(Oe,{action:e},e.actionId))})]}),e.inputPreview?(0,j.jsx)(Q,{label:m(`serviceActionAuthorizationInput`),value:e.inputPreview}):null]}):null,(0,j.jsxs)(ae,{className:`gap-2 sm:gap-0`,children:[(0,j.jsx)(a,{type:`button`,variant:`outline`,onClick:()=>t(!1),children:m(`serviceActionAuthorizationReject`)}),(0,j.jsx)(a,{type:`button`,onClick:()=>t(!0),children:m(`serviceActionAuthorizationAllow`)})]})]})})}function Oe({action:e}){return(0,j.jsxs)(`div`,{className:`space-y-1 rounded border border-border bg-card px-3 py-2`,children:[(0,j.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,j.jsx)(`div`,{className:`min-w-0 break-words text-xs font-medium text-foreground`,children:e.actionTitle??e.actionId}),(0,j.jsx)(`div`,{className:`shrink-0 rounded bg-amber-50 px-1.5 py-0.5 text-[11px] font-medium text-amber-700`,children:e.risk??`dangerous`})]}),(0,j.jsx)(`div`,{className:`break-words text-[11px] text-muted-foreground`,children:e.actionId}),e.actionDescription?(0,j.jsx)(`div`,{className:`break-words text-xs text-muted-foreground`,children:e.actionDescription}):null]})}function Q({label:e,value:t}){return(0,j.jsxs)(`div`,{className:`grid grid-cols-[5rem_minmax(0,1fr)] gap-3`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:e}),(0,j.jsx)(`div`,{className:`min-w-0 break-words text-xs text-foreground`,children:t})]})}var $=(0,A.createContext)(null);function ke({children:e}){let[t,n]=(0,A.useState)(()=>w());(0,A.useEffect)(()=>me(e=>{n(e)}),[]);let r=(0,A.useCallback)(e=>{pe(e),n(fe())},[]),i=(0,A.useMemo)(()=>({theme:t,setTheme:r}),[t,r]);return(0,j.jsx)($.Provider,{value:i,children:e})}function Ae(){let e=(0,A.useContext)($);if(!e)throw Error(`useTheme must be used within ThemeProvider`);return e}export{v as C,x as D,w as E,y as O,T as S,S as T,ve as _,we as a,D as b,J as c,W as d,be as f,ye as g,_e as h,Ee as i,G as l,H as m,Ae as n,Te as o,U as p,De as r,Y as s,ke as t,K as u,P as v,de as w,E as x,k as y};
|
package/dist/index.html
CHANGED
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
})();
|
|
193
193
|
</script>
|
|
194
194
|
<title>NextClaw</title>
|
|
195
|
-
<script type="module" crossorigin src="/assets/main-
|
|
195
|
+
<script type="module" crossorigin src="/assets/main-BNWRrWc_.js"></script>
|
|
196
196
|
<link rel="modulepreload" crossorigin href="/assets/chunk-DF37yw5_.js">
|
|
197
197
|
<link rel="modulepreload" crossorigin href="/assets/preload-helper-DWTEM3RW.js">
|
|
198
198
|
<link rel="modulepreload" crossorigin href="/assets/i18n-ByVUrt9w.js">
|
|
@@ -206,12 +206,12 @@
|
|
|
206
206
|
<link rel="modulepreload" crossorigin href="/assets/inbox-CI8ATevA.js">
|
|
207
207
|
<link rel="modulepreload" crossorigin href="/assets/x-waP-WLuT.js">
|
|
208
208
|
<link rel="modulepreload" crossorigin href="/assets/plus-C42o6xrD.js">
|
|
209
|
-
<link rel="modulepreload" crossorigin href="/assets/context-menu-
|
|
209
|
+
<link rel="modulepreload" crossorigin href="/assets/context-menu-C6m-WNpl.js">
|
|
210
210
|
<link rel="modulepreload" crossorigin href="/assets/puzzle-DmKVREoh.js">
|
|
211
211
|
<link rel="modulepreload" crossorigin href="/assets/book-open-B3Ac0voD.js">
|
|
212
|
-
<link rel="modulepreload" crossorigin href="/assets/dialog-
|
|
212
|
+
<link rel="modulepreload" crossorigin href="/assets/dialog-DB_l9LK0.js">
|
|
213
213
|
<link rel="modulepreload" crossorigin href="/assets/navigation-history-CCnxsAKR.js">
|
|
214
|
-
<link rel="modulepreload" crossorigin href="/assets/theme-provider-
|
|
214
|
+
<link rel="modulepreload" crossorigin href="/assets/theme-provider-D4rd-tCP.js">
|
|
215
215
|
<link rel="modulepreload" crossorigin href="/assets/download-C2gYe8n1.js">
|
|
216
216
|
<link rel="modulepreload" crossorigin href="/assets/middleware-B--6mAUM.js">
|
|
217
217
|
<link rel="modulepreload" crossorigin href="/assets/use-viewport-layout-Bnm5W5Qz.js">
|
|
@@ -224,15 +224,15 @@
|
|
|
224
224
|
<link rel="modulepreload" crossorigin href="/assets/doc-browser-context-CoVMIiU8.js">
|
|
225
225
|
<link rel="modulepreload" crossorigin href="/assets/tag-chip-DFzDSvcF.js">
|
|
226
226
|
<link rel="modulepreload" crossorigin href="/assets/card-eFBmxYiI.js">
|
|
227
|
-
<link rel="modulepreload" crossorigin href="/assets/confirm-dialog-
|
|
228
|
-
<link rel="modulepreload" crossorigin href="/assets/provider-models-
|
|
227
|
+
<link rel="modulepreload" crossorigin href="/assets/confirm-dialog-D30HJBXN.js">
|
|
228
|
+
<link rel="modulepreload" crossorigin href="/assets/provider-models-zGsDUBHG.js">
|
|
229
229
|
<link rel="modulepreload" crossorigin href="/assets/select-BJ-EjmCz.js">
|
|
230
230
|
<link rel="modulepreload" crossorigin href="/assets/use-config-M1L4xn8c.js">
|
|
231
|
-
<link rel="modulepreload" crossorigin href="/assets/app-presenter-provider-
|
|
232
|
-
<link rel="modulepreload" crossorigin href="/assets/provider-scoped-model-input-
|
|
231
|
+
<link rel="modulepreload" crossorigin href="/assets/app-presenter-provider-Cx9MwMtb.js">
|
|
232
|
+
<link rel="modulepreload" crossorigin href="/assets/provider-scoped-model-input-DpEyP1h8.js">
|
|
233
233
|
<link rel="modulepreload" crossorigin href="/assets/settings-2-D3-m8a3v.js">
|
|
234
|
-
<link rel="modulepreload" crossorigin href="/assets/agents-
|
|
235
|
-
<link rel="modulepreload" crossorigin href="/assets/pwa-
|
|
234
|
+
<link rel="modulepreload" crossorigin href="/assets/agents-Dr2KkEp2.js">
|
|
235
|
+
<link rel="modulepreload" crossorigin href="/assets/pwa-jmuWbrqH.js">
|
|
236
236
|
<link rel="modulepreload" crossorigin href="/assets/login-page--Njgbmpm.js">
|
|
237
237
|
<link rel="stylesheet" crossorigin href="/assets/context-menu-DEcVZfaU.css">
|
|
238
238
|
<link rel="stylesheet" crossorigin href="/assets/app-presenter-provider-D3BuuOyZ.css">
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="theme-color" content="#ffffff" />
|
|
7
7
|
<title>Panel App · NextClaw</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/panelStandalone-
|
|
8
|
+
<script type="module" crossorigin src="/assets/panelStandalone-C38o5B4Q.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/chunk-DF37yw5_.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/preload-helper-DWTEM3RW.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/i18n-ByVUrt9w.js">
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
<link rel="modulepreload" crossorigin href="/assets/inbox-CI8ATevA.js">
|
|
20
20
|
<link rel="modulepreload" crossorigin href="/assets/x-waP-WLuT.js">
|
|
21
21
|
<link rel="modulepreload" crossorigin href="/assets/plus-C42o6xrD.js">
|
|
22
|
-
<link rel="modulepreload" crossorigin href="/assets/context-menu-
|
|
23
|
-
<link rel="modulepreload" crossorigin href="/assets/dialog-
|
|
22
|
+
<link rel="modulepreload" crossorigin href="/assets/context-menu-C6m-WNpl.js">
|
|
23
|
+
<link rel="modulepreload" crossorigin href="/assets/dialog-DB_l9LK0.js">
|
|
24
24
|
<link rel="modulepreload" crossorigin href="/assets/navigation-history-CCnxsAKR.js">
|
|
25
|
-
<link rel="modulepreload" crossorigin href="/assets/theme-provider-
|
|
25
|
+
<link rel="modulepreload" crossorigin href="/assets/theme-provider-D4rd-tCP.js">
|
|
26
26
|
<link rel="stylesheet" crossorigin href="/assets/context-menu-DEcVZfaU.css">
|
|
27
27
|
<link rel="stylesheet" crossorigin href="/assets/panelStandalone-XRlWxbRS.css">
|
|
28
28
|
</head>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ui",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.5-beta.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
35
35
|
"zod": "^3.23.8",
|
|
36
36
|
"zustand": "^5.0.2",
|
|
37
|
-
"@nextclaw/agent-chat": "0.
|
|
38
|
-
"@nextclaw/ncp": "0.11.3",
|
|
37
|
+
"@nextclaw/agent-chat-ui": "0.12.4-beta.0",
|
|
39
38
|
"@nextclaw/ncp-http-agent-client": "0.4.27",
|
|
40
|
-
"@nextclaw/ncp
|
|
41
|
-
"@nextclaw/
|
|
42
|
-
"@nextclaw/
|
|
39
|
+
"@nextclaw/ncp": "0.11.3",
|
|
40
|
+
"@nextclaw/client-sdk": "0.12.14-beta.1",
|
|
41
|
+
"@nextclaw/shared": "0.8.4",
|
|
43
42
|
"@nextclaw/ncp-toolkit": "0.6.28",
|
|
44
|
-
"@nextclaw/
|
|
43
|
+
"@nextclaw/ncp-react": "0.5.31",
|
|
44
|
+
"@nextclaw/agent-chat": "0.3.14"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@testing-library/react": "^16.3.0",
|
package/src/features/chat/features/message/utils/__tests__/chat-message-timeline.utils.test.ts
CHANGED
|
@@ -20,6 +20,22 @@ const visibleMessage = {
|
|
|
20
20
|
} satisfies NcpMessage;
|
|
21
21
|
|
|
22
22
|
describe("chat message timeline visibility", () => {
|
|
23
|
+
it("places an async question at its tool call between assistant text parts", () => {
|
|
24
|
+
const source = { ...visibleMessage, parts: [
|
|
25
|
+
{ type: "text" as const, text: "先说明。" },
|
|
26
|
+
{ type: "tool-invocation" as const, toolCallId: "call-1", toolName: "request_user_input_async", state: "result" as const,
|
|
27
|
+
args: "{}", result: { accepted: true, questionIds: ["q-1"] } },
|
|
28
|
+
{ type: "text" as const, text: "稍后继续。" },
|
|
29
|
+
] } satisfies NcpMessage;
|
|
30
|
+
const question = { ...visibleMessage, id: "assistant-question-1", parts: [
|
|
31
|
+
{ type: "text" as const, text: "城市? (北京 / 上海)" },
|
|
32
|
+
{ type: "extension" as const, extensionType: "nextclaw.user-question", data: { questions: [{ id: "q-1", title: "城市?", options: ["北京", "上海"] }] } },
|
|
33
|
+
] } satisfies NcpMessage;
|
|
34
|
+
const projected = projectVisibleChatMessages([source, question]);
|
|
35
|
+
expect(projected).toHaveLength(1);
|
|
36
|
+
expect(projected[0]?.parts.map((part) => part.type)).toEqual(["text", "extension", "text"]);
|
|
37
|
+
expect(projected[0]?.parts[1]).toMatchObject({ data: { questions: [{ id: "q-1" }] } });
|
|
38
|
+
});
|
|
23
39
|
it("places context compaction between surrounding visible messages", () => {
|
|
24
40
|
const afterMessage = {
|
|
25
41
|
...visibleMessage,
|
|
@@ -118,6 +118,23 @@ it("maps context compaction extensions into stable process parts", () => {
|
|
|
118
118
|
}]);
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
+
it("keeps assistant prose on both sides of an unanchored question fallback", () => {
|
|
122
|
+
const data = { questions: [{ id: "question-1", title: "Which format?", options: ["PDF", "DOCX"] }] };
|
|
123
|
+
const adapted = adapt([{
|
|
124
|
+
id: "assistant-question-older",
|
|
125
|
+
role: "assistant",
|
|
126
|
+
parts: [
|
|
127
|
+
{ type: "text", text: "Before." },
|
|
128
|
+
{ type: "text", text: "Which format? (PDF / DOCX)" },
|
|
129
|
+
{ type: "extension", extensionType: "nextclaw.user-question", data },
|
|
130
|
+
{ type: "text", text: "After." },
|
|
131
|
+
],
|
|
132
|
+
}]);
|
|
133
|
+
expect(adapted[0]?.parts.map((part) => part.type)).toEqual(["markdown", "custom", "markdown"]);
|
|
134
|
+
expect(adapted[0]?.parts[0]).toMatchObject({ text: "Before." });
|
|
135
|
+
expect(adapted[0]?.parts[2]).toMatchObject({ text: "After." });
|
|
136
|
+
});
|
|
137
|
+
|
|
121
138
|
it("renders a structured user question at its message position without repeating fallback text", () => {
|
|
122
139
|
const data = { questions: [{ id: "question-1", title: "Which format?", options: ["PDF", "DOCX"] }] };
|
|
123
140
|
const adapted = adapt([{
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
readObservationEventPartData,
|
|
14
14
|
type ObservationEventPartData,
|
|
15
15
|
} from "@/features/chat/features/message/utils/chat-message-observation-event.utils";
|
|
16
|
+
import { placeUserQuestionsInAssistantBody } from "@/features/chat/features/message/utils/chat-user-question-timeline.utils";
|
|
16
17
|
|
|
17
18
|
const INHERITED_FROM_SESSION_METADATA_KEY = "inherited_from_session_id";
|
|
18
|
-
export const CONTEXT_COMPACTION_PART_EXTENSION_TYPE =
|
|
19
|
-
"nextclaw.context-compaction";
|
|
19
|
+
export const CONTEXT_COMPACTION_PART_EXTENSION_TYPE = "nextclaw.context-compaction";
|
|
20
20
|
|
|
21
21
|
export type ContextCompactionPartData = {
|
|
22
22
|
id: string;
|
|
@@ -280,7 +280,7 @@ function projectVisibleChatMessageState(
|
|
|
280
280
|
status: "pending",
|
|
281
281
|
};
|
|
282
282
|
}
|
|
283
|
-
return { messages,
|
|
283
|
+
return { ...placeUserQuestionsInAssistantBody(messages, observationEvents), inlineCompactionMessageIds };
|
|
284
284
|
}
|
|
285
285
|
|
|
286
286
|
export function projectVisibleChatMessages(
|
|
@@ -122,16 +122,23 @@ export function adaptChatMessage(
|
|
|
122
122
|
texts: params.texts,
|
|
123
123
|
}))
|
|
124
124
|
.filter((part) => part !== null);
|
|
125
|
-
const hasQuestionPart = parts.some(
|
|
126
|
-
(part) => part.type === "custom" && part.customType === "nextclaw.user-question",
|
|
127
|
-
);
|
|
128
125
|
const reply = message.meta?.userQuestionReply;
|
|
129
126
|
const displayParts: ChatMessageViewModel["parts"] = reply
|
|
130
127
|
? [
|
|
131
128
|
{ type: "custom", id: reply.questionId, customType: "nextclaw.user-question-reply", data: reply },
|
|
132
129
|
...(reply.answer ? [{ type: "markdown" as const, text: reply.answer }] : []),
|
|
133
130
|
]
|
|
134
|
-
:
|
|
131
|
+
: parts.filter((part, index) => {
|
|
132
|
+
const next = parts[index + 1];
|
|
133
|
+
if (part.type !== "markdown" || next?.type !== "custom" || next.customType !== "nextclaw.user-question") return true;
|
|
134
|
+
const entries = next.data && typeof next.data === "object" && "questions" in next.data ? next.data.questions : null;
|
|
135
|
+
if (!Array.isArray(entries)) return true;
|
|
136
|
+
const fallback = entries.map((entry) => {
|
|
137
|
+
if (!entry || typeof entry.title !== "string") return "";
|
|
138
|
+
return `${entry.title}${Array.isArray(entry.options) && entry.options.length ? ` (${entry.options.join(" / ")})` : ""}`;
|
|
139
|
+
}).join("\n");
|
|
140
|
+
return part.text !== fallback;
|
|
141
|
+
});
|
|
135
142
|
return {
|
|
136
143
|
id: message.id,
|
|
137
144
|
role: resolveUiRole(message.role),
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { NcpMessage } from "@nextclaw/ncp";
|
|
2
|
+
|
|
3
|
+
function questionIdsFromToolPart(part: NcpMessage["parts"][number]): string[] {
|
|
4
|
+
if (part.type !== "tool-invocation" || part.toolName !== "request_user_input_async" ||
|
|
5
|
+
!part.result || typeof part.result !== "object" || Array.isArray(part.result)) return [];
|
|
6
|
+
const { accepted, questionIds } = part.result as { accepted?: unknown; questionIds?: unknown };
|
|
7
|
+
return accepted === true && Array.isArray(questionIds) && questionIds.every((id) => typeof id === "string")
|
|
8
|
+
? questionIds : [];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function questionEntries(part: NcpMessage["parts"][number]): Array<{ id: string }> {
|
|
12
|
+
if (part.type !== "extension" || part.extensionType !== "nextclaw.user-question") return [];
|
|
13
|
+
const entries = part.data && typeof part.data === "object" && "questions" in part.data ? part.data.questions : null;
|
|
14
|
+
return Array.isArray(entries) ? entries.filter((entry): entry is { id: string } => Boolean(entry && typeof entry.id === "string")) : [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function placeUserQuestionsInAssistantBody<T extends { boundaryIndex: number }>(
|
|
18
|
+
messages: NcpMessage[], observationEvents: T[],
|
|
19
|
+
): { messages: NcpMessage[]; observationEvents: T[] } {
|
|
20
|
+
const entriesById = new Map(messages.flatMap((message) => message.parts.flatMap((part) => questionEntries(part).map((entry) => [entry.id, entry] as const))));
|
|
21
|
+
const anchoredIds = new Set(messages.flatMap((message) => message.parts.flatMap((part) =>
|
|
22
|
+
questionIdsFromToolPart(part).filter((id) => entriesById.has(id)))));
|
|
23
|
+
if (!anchoredIds.size) return { messages, observationEvents };
|
|
24
|
+
const removedIndices: number[] = [];
|
|
25
|
+
const projected = messages.flatMap((message, index) => {
|
|
26
|
+
const questionPart = message.parts.find((part) => questionEntries(part).length);
|
|
27
|
+
if (questionPart && message.id.startsWith("assistant-question-")) {
|
|
28
|
+
const remaining = questionEntries(questionPart).filter((entry) => !anchoredIds.has(entry.id));
|
|
29
|
+
if (!remaining.length) { removedIndices.push(index); return []; }
|
|
30
|
+
return [{ ...message, parts: [{ type: "extension" as const, extensionType: "nextclaw.user-question", data: { questions: remaining } }] }];
|
|
31
|
+
}
|
|
32
|
+
const parts = message.parts.flatMap((part): NcpMessage["parts"] => {
|
|
33
|
+
const questions = questionIdsFromToolPart(part).flatMap((id) => entriesById.get(id) ?? []);
|
|
34
|
+
return questions.length
|
|
35
|
+
? [{ type: "extension", extensionType: "nextclaw.user-question", data: { questions } }]
|
|
36
|
+
: [part];
|
|
37
|
+
});
|
|
38
|
+
return [{ ...message, parts }];
|
|
39
|
+
});
|
|
40
|
+
return { messages: projected, observationEvents: observationEvents.map((entry) => ({ ...entry,
|
|
41
|
+
boundaryIndex: entry.boundaryIndex - removedIndices.filter((index) => index < entry.boundaryIndex).length })) };
|
|
42
|
+
}
|
package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx
CHANGED
|
@@ -37,6 +37,7 @@ function renderDetail(detailId: string) {
|
|
|
37
37
|
open: vi.fn(),
|
|
38
38
|
openTarget: vi.fn(),
|
|
39
39
|
refreshIframe: vi.fn(),
|
|
40
|
+
refreshVersion: 0,
|
|
40
41
|
tab: {
|
|
41
42
|
id: "tab-1",
|
|
42
43
|
kind: MARKETPLACE_DETAIL_TAB_KIND,
|
|
@@ -131,6 +132,7 @@ describe("Marketplace detail doc renderer", () => {
|
|
|
131
132
|
open: vi.fn(),
|
|
132
133
|
openTarget: vi.fn(),
|
|
133
134
|
refreshIframe: vi.fn(),
|
|
135
|
+
refreshVersion: 0,
|
|
134
136
|
tab: {
|
|
135
137
|
id: "tab-1",
|
|
136
138
|
kind: MARKETPLACE_DETAIL_TAB_KIND,
|
|
@@ -18,10 +18,12 @@ type PanelAppUnavailableAction = {
|
|
|
18
18
|
export function PanelAppRuntimeSurface({
|
|
19
19
|
appId,
|
|
20
20
|
restorationScope,
|
|
21
|
+
refreshVersion = 0,
|
|
21
22
|
unavailableAction,
|
|
22
23
|
}: {
|
|
23
24
|
appId: string;
|
|
24
25
|
restorationScope: "main" | "standalone";
|
|
26
|
+
refreshVersion?: number;
|
|
25
27
|
unavailableAction?: PanelAppUnavailableAction;
|
|
26
28
|
}) {
|
|
27
29
|
const presenter = usePanelAppHostPresenter();
|
|
@@ -97,7 +99,7 @@ export function PanelAppRuntimeSurface({
|
|
|
97
99
|
return (
|
|
98
100
|
<div className="h-full min-h-0 bg-background">
|
|
99
101
|
<iframe
|
|
100
|
-
key={entry.appId}
|
|
102
|
+
key={`${entry.appId}:${refreshVersion}`}
|
|
101
103
|
ref={iframeRef}
|
|
102
104
|
src={entry.contentPath}
|
|
103
105
|
title={entry.title}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { AppWindow, Boxes } from 'lucide-react';
|
|
1
|
+
import { AppWindow, Boxes, ExternalLink, RefreshCw } from 'lucide-react';
|
|
2
2
|
import type { DocBrowserContextValue } from '@/shared/components/doc-browser/doc-browser-context';
|
|
3
3
|
import type { DocBrowserCustomTabRenderers } from '@/shared/components/doc-browser/doc-browser-renderer.types';
|
|
4
4
|
import { getPresenter } from '@/app/presenters/app.presenter';
|
|
5
5
|
import { AppsPanel } from '@/features/apps';
|
|
6
|
-
import { PanelAppDocBrowserToolbar } from '@/features/panel-apps/components/panel-app-toolbar';
|
|
7
6
|
import {
|
|
8
7
|
createPanelAppRightPanelResourceTarget,
|
|
9
8
|
RIGHT_PANEL_APPS_TAB_KIND,
|
|
@@ -12,6 +11,7 @@ import {
|
|
|
12
11
|
RIGHT_PANEL_HOME_TAB_KIND,
|
|
13
12
|
RIGHT_PANEL_PANEL_APP_TAB_KIND,
|
|
14
13
|
RightPanelResourceHomePage,
|
|
14
|
+
readPanelAppIdFromTab,
|
|
15
15
|
} from '@/features/right-panel-resources';
|
|
16
16
|
import { t } from '@/shared/lib/i18n';
|
|
17
17
|
import { PANEL_APP_IFRAME_SANDBOX, focusPanelAppIframe } from './panel-app-iframe.utils';
|
|
@@ -56,14 +56,29 @@ export const PANEL_APPS_DOC_BROWSER_RENDERERS: DocBrowserCustomTabRenderers = {
|
|
|
56
56
|
onIframeMessage: (params) => getPresenter().panelAppBridgeManager.handleIframeMessage(params),
|
|
57
57
|
onIframePointerOver: (event) => focusPanelAppIframe(event.currentTarget),
|
|
58
58
|
renderIcon: () => <AppWindow className="w-4 h-4 text-primary shrink-0" />,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
getTabMenuGroups: ({ refreshIframe, tab }) => {
|
|
60
|
+
const appId = readPanelAppIdFromTab(tab);
|
|
61
|
+
return [{
|
|
62
|
+
key: 'panel-app-actions',
|
|
63
|
+
items: [
|
|
64
|
+
{
|
|
65
|
+
key: 'refresh',
|
|
66
|
+
icon: <RefreshCw className="h-4 w-4" />,
|
|
67
|
+
label: t('panelAppsRefreshCurrent'),
|
|
68
|
+
onSelect: refreshIframe,
|
|
69
|
+
},
|
|
70
|
+
...(appId ? [{
|
|
71
|
+
key: 'open-standalone',
|
|
72
|
+
icon: <ExternalLink className="h-4 w-4" />,
|
|
73
|
+
label: t(typeof window !== 'undefined' && window.nextclawDesktop ? 'panelAppsOpenInBrowser' : 'panelAppsOpenInNewTab'),
|
|
74
|
+
href: `/apps/panel/${encodeURIComponent(appId)}/standalone`,
|
|
75
|
+
target: '_blank' as const,
|
|
76
|
+
rel: 'opener',
|
|
77
|
+
referrerPolicy: 'no-referrer' as const,
|
|
78
|
+
}] : []),
|
|
79
|
+
],
|
|
80
|
+
}];
|
|
81
|
+
},
|
|
67
82
|
supportsScrollRestoration: true,
|
|
68
83
|
},
|
|
69
84
|
};
|
package/src/features/right-panel-resources/components/__tests__/system-object-resource.test.tsx
CHANGED
|
@@ -17,7 +17,7 @@ vi.mock("@/features/inbox", () => ({ InboxPage: ({ resourceId }: { resourceId: s
|
|
|
17
17
|
vi.mock("@/features/apps", () => ({ AppsPanel: ({ serviceResourceId }: { serviceResourceId: string }) => <div>service-app:{serviceResourceId}</div> }));
|
|
18
18
|
vi.mock("@/features/marketplace", () => ({ McpMarketplacePage: ({ resourceId }: { resourceId: string }) => <div>mcp-server:{resourceId}</div> }));
|
|
19
19
|
vi.mock("@/features/panel-apps", () => ({
|
|
20
|
-
PanelAppRuntimeSurface: ({ appId }: { appId: string }) => <div>panel-app:{appId}</div>,
|
|
20
|
+
PanelAppRuntimeSurface: ({ appId, refreshVersion }: { appId: string; refreshVersion?: number }) => <div>panel-app:{appId}:{refreshVersion}</div>,
|
|
21
21
|
PanelAppHostProvider: ({ children }: { children: ReactNode }) => children,
|
|
22
22
|
}));
|
|
23
23
|
|
|
@@ -61,7 +61,7 @@ afterEach(cleanup);
|
|
|
61
61
|
describe("system object reading identity", () => {
|
|
62
62
|
it.each(["agent", "cron-job", "project", "inbox-delivery", "service-app", "mcp-server", "panel-app"])("opens %s with its native renderer and unchanged identity", async (objectType) => {
|
|
63
63
|
render(<NativeObjectResource objectType={objectType} objectId="raw:id" openTarget={vi.fn()} />);
|
|
64
|
-
expect(await screen.findByText(`${objectType}:raw:id`)).toBeTruthy();
|
|
64
|
+
expect(await screen.findByText(objectType === "panel-app" ? `${objectType}:raw:id:` : `${objectType}:raw:id`)).toBeTruthy();
|
|
65
65
|
expect(screen.queryByTestId("preview")).toBeNull();
|
|
66
66
|
});
|
|
67
67
|
|
|
@@ -70,6 +70,27 @@ describe("system object reading identity", () => {
|
|
|
70
70
|
expect(await screen.findByText("project:project/work")).toBeTruthy();
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
+
it("adds refresh to the host tab menu and passes its version to panel app content", async () => {
|
|
74
|
+
const uri = "nextclaw://objects/panel-app/raw%3Aid";
|
|
75
|
+
const refreshIframe = vi.fn();
|
|
76
|
+
const params = (refreshVersion: number) => ({
|
|
77
|
+
currentUrl: uri,
|
|
78
|
+
tab: { id: uri, kind: "system-object", title: "Panel App", currentUrl: uri, resourceUri: uri, history: [uri], historyIndex: 0, navVersion: 0 },
|
|
79
|
+
open: vi.fn(), openTarget: vi.fn(), refreshIframe, refreshVersion,
|
|
80
|
+
} satisfies DocBrowserCustomTabRenderParams);
|
|
81
|
+
const renderer = SYSTEM_OBJECT_RESOURCE_RENDERERS["system-object"];
|
|
82
|
+
expect(renderer.renderToolbar).toBeUndefined();
|
|
83
|
+
const refreshAction = renderer.getTabMenuGroups!(params(0))[0]?.items[0];
|
|
84
|
+
expect(refreshAction?.label).toBe("Refresh current panel app");
|
|
85
|
+
if (refreshAction && "onSelect" in refreshAction) refreshAction.onSelect?.();
|
|
86
|
+
expect(refreshIframe).toHaveBeenCalledTimes(1);
|
|
87
|
+
const view = render(renderer.renderContent!(params(0)));
|
|
88
|
+
expect(await screen.findByText("panel-app:raw:id:0")).toBeTruthy();
|
|
89
|
+
view.rerender(renderer.renderContent!(params(1)));
|
|
90
|
+
expect(await screen.findByText("panel-app:raw:id:1")).toBeTruthy();
|
|
91
|
+
expect(renderer.getTabMenuGroups!({ ...params(0), tab: { ...params(0).tab, currentUrl: "nextclaw://objects/agent/test", resourceUri: "nextclaw://objects/agent/test" } })).toEqual([]);
|
|
92
|
+
});
|
|
93
|
+
|
|
73
94
|
it("retains a global file's source context when quoting into a different conversation", () => {
|
|
74
95
|
const target = createWorkspaceFilePanelTarget({
|
|
75
96
|
key: "source-file", path: "agent.md", label: "agent.md", parentSessionKey: "source-session", viewMode: "preview",
|
|
@@ -77,7 +98,7 @@ describe("system object reading identity", () => {
|
|
|
77
98
|
render(WORKSPACE_FILE_PANEL_RENDERERS["workspace-file"].renderContent!({
|
|
78
99
|
currentUrl: target.url,
|
|
79
100
|
tab: { ...target, id: target.url, currentUrl: target.url, history: [target.url], historyIndex: 0, navVersion: 0 },
|
|
80
|
-
open: vi.fn(), openTarget: vi.fn(), refreshIframe: vi.fn(),
|
|
101
|
+
open: vi.fn(), openTarget: vi.fn(), refreshIframe: vi.fn(), refreshVersion: 0,
|
|
81
102
|
}));
|
|
82
103
|
fireEvent.click(screen.getByRole("button", { name: "Add selection" }));
|
|
83
104
|
expect(actions.addExcerptToChat).toHaveBeenLastCalledWith({
|
|
@@ -92,6 +113,7 @@ describe("system object reading identity", () => {
|
|
|
92
113
|
open: vi.fn(),
|
|
93
114
|
openTarget: vi.fn(),
|
|
94
115
|
refreshIframe: vi.fn(),
|
|
116
|
+
refreshVersion: 0,
|
|
95
117
|
} satisfies DocBrowserCustomTabRenderParams);
|
|
96
118
|
const first = "nextclaw://objects/skill/first";
|
|
97
119
|
const second = "nextclaw://objects/skill/second";
|
|
@@ -65,10 +65,12 @@ export function NativeObjectResource({
|
|
|
65
65
|
objectType,
|
|
66
66
|
objectId,
|
|
67
67
|
openTarget,
|
|
68
|
+
refreshVersion,
|
|
68
69
|
}: {
|
|
69
70
|
objectType: string;
|
|
70
71
|
objectId: string;
|
|
71
72
|
openTarget: DocBrowserCustomTabRenderParams["openTarget"];
|
|
73
|
+
refreshVersion?: number;
|
|
72
74
|
}) {
|
|
73
75
|
let content;
|
|
74
76
|
switch (objectType) {
|
|
@@ -111,7 +113,7 @@ export function NativeObjectResource({
|
|
|
111
113
|
case "panel-app":
|
|
112
114
|
content = (
|
|
113
115
|
<PanelAppHostProvider>
|
|
114
|
-
<PanelAppRuntimeSurface appId={objectId} restorationScope="main" />
|
|
116
|
+
<PanelAppRuntimeSurface appId={objectId} restorationScope="main" refreshVersion={refreshVersion} />
|
|
115
117
|
</PanelAppHostProvider>
|
|
116
118
|
);
|
|
117
119
|
break;
|
|
@@ -13,12 +13,14 @@ import { useAppPresenter } from "@/app/components/app-presenter-provider";
|
|
|
13
13
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
14
14
|
import { parseSystemObjectReferenceUri } from "@nextclaw/shared";
|
|
15
15
|
import { NativeObjectResource } from "./native-object-resource";
|
|
16
|
+
import { RefreshCw } from "lucide-react";
|
|
16
17
|
import { ChatTextSelectionAction } from "@nextclaw/agent-chat-ui";
|
|
17
18
|
import { WORKSPACE_TEXT_EXCERPT_MAX_CHARACTERS } from "@/features/chat";
|
|
18
19
|
|
|
19
20
|
function SystemObjectResource({
|
|
20
21
|
tab,
|
|
21
22
|
openTarget,
|
|
23
|
+
refreshVersion,
|
|
22
24
|
}: DocBrowserCustomTabRenderParams) {
|
|
23
25
|
const app = useAppPresenter();
|
|
24
26
|
const { pathname } = useLocation();
|
|
@@ -52,7 +54,7 @@ function SystemObjectResource({
|
|
|
52
54
|
)
|
|
53
55
|
}
|
|
54
56
|
>
|
|
55
|
-
<NativeObjectResource key={uri} {...identity} openTarget={openTarget} />
|
|
57
|
+
<NativeObjectResource key={uri} {...identity} openTarget={openTarget} refreshVersion={refreshVersion} />
|
|
56
58
|
</ChatTextSelectionAction>
|
|
57
59
|
);
|
|
58
60
|
}
|
|
@@ -160,6 +162,18 @@ function SystemObjectDocument({
|
|
|
160
162
|
export const SYSTEM_OBJECT_RESOURCE_RENDERERS: DocBrowserCustomTabRenderers = {
|
|
161
163
|
"system-object": {
|
|
162
164
|
getTitle: (tab) => tab.title,
|
|
165
|
+
getTabMenuGroups: ({ refreshIframe, tab }) => {
|
|
166
|
+
const identity = parseSystemObjectReferenceUri(tab.resourceUri ?? tab.currentUrl);
|
|
167
|
+
return identity?.objectType === "panel-app" ? [{
|
|
168
|
+
key: "panel-app-refresh",
|
|
169
|
+
items: [{
|
|
170
|
+
key: "refresh",
|
|
171
|
+
label: t("panelAppsRefreshCurrent"),
|
|
172
|
+
icon: <RefreshCw className="h-4 w-4" />,
|
|
173
|
+
onSelect: refreshIframe,
|
|
174
|
+
}],
|
|
175
|
+
}] : [];
|
|
176
|
+
},
|
|
163
177
|
renderContent: (params) => <SystemObjectResource {...params} />,
|
|
164
178
|
},
|
|
165
179
|
};
|