@xopcai/xopc 0.0.42 → 0.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/extensions/dingtalk/src/plugin.js +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/telegram/src/plugin.js +1 -1
  4. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  5. package/dist/extensions/telegram/xopc.extension.json +1 -1
  6. package/dist/extensions/weixin/src/api/api.js +2 -2
  7. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  8. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  9. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  10. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  11. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  12. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  13. package/dist/extensions/weixin/src/plugin.js +1 -1
  14. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  15. package/dist/gateway/static/root/assets/{agents-DMW4-fH-.js → agents-BDhkkT2o.js} +2 -2
  16. package/dist/gateway/static/root/assets/{agents-DMW4-fH-.js.map → agents-BDhkkT2o.js.map} +1 -1
  17. package/dist/gateway/static/root/assets/{apps-page-DOHsxEjt.js → apps-page-Bco3oZzd.js} +2 -2
  18. package/dist/gateway/static/root/assets/{apps-page-DOHsxEjt.js.map → apps-page-Bco3oZzd.js.map} +1 -1
  19. package/dist/gateway/static/root/assets/{channels-settings-JVq31iIN.js → channels-settings-CpTZxCKG.js} +2 -2
  20. package/dist/gateway/static/root/assets/{channels-settings-JVq31iIN.js.map → channels-settings-CpTZxCKG.js.map} +1 -1
  21. package/dist/gateway/static/root/assets/{cron-api-BqeNAeYQ.js → cron-api-YLqLzMDN.js} +2 -2
  22. package/dist/gateway/static/root/assets/{cron-api-BqeNAeYQ.js.map → cron-api-YLqLzMDN.js.map} +1 -1
  23. package/dist/gateway/static/root/assets/{cron-page-ryZsTAOn.js → cron-page-aiDeJtJ-.js} +2 -2
  24. package/dist/gateway/static/root/assets/{cron-page-ryZsTAOn.js.map → cron-page-aiDeJtJ-.js.map} +1 -1
  25. package/dist/gateway/static/root/assets/{dist-zlgGKakL.js → dist-4ClCuR-G.js} +2 -2
  26. package/dist/gateway/static/root/assets/{dist-zlgGKakL.js.map → dist-4ClCuR-G.js.map} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-debug-page-BAHhJLEv.js → extension-debug-page-yNO3rwBQ.js} +2 -2
  28. package/dist/gateway/static/root/assets/{extension-debug-page-BAHhJLEv.js.map → extension-debug-page-yNO3rwBQ.js.map} +1 -1
  29. package/dist/gateway/static/root/assets/{extension-page-9UNKgelu.js → extension-page-D0vOu9eC.js} +2 -2
  30. package/dist/gateway/static/root/assets/{extension-page-9UNKgelu.js.map → extension-page-D0vOu9eC.js.map} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-settings-page-Mjv8LQCe.js → extension-settings-page-DqaNWoo7.js} +2 -2
  32. package/dist/gateway/static/root/assets/{extension-settings-page-Mjv8LQCe.js.map → extension-settings-page-DqaNWoo7.js.map} +1 -1
  33. package/dist/gateway/static/root/assets/{index-DLfAjBJz.js → index-KxjI2fjF.js} +4 -4
  34. package/dist/gateway/static/root/assets/{index-DLfAjBJz.js.map → index-KxjI2fjF.js.map} +1 -1
  35. package/dist/gateway/static/root/assets/{logs-page-XNnEW2Be.js → logs-page-DSdKuyeD.js} +2 -2
  36. package/dist/gateway/static/root/assets/{logs-page-XNnEW2Be.js.map → logs-page-DSdKuyeD.js.map} +1 -1
  37. package/dist/gateway/static/root/assets/{sessions-page-pgcikS9L.js → sessions-page-Bfb-hZJb.js} +2 -2
  38. package/dist/gateway/static/root/assets/{sessions-page-pgcikS9L.js.map → sessions-page-Bfb-hZJb.js.map} +1 -1
  39. package/dist/gateway/static/root/assets/{settings-page-CrXaEe86.js → settings-page-B7NZPSpO.js} +2 -2
  40. package/dist/gateway/static/root/assets/{settings-page-CrXaEe86.js.map → settings-page-B7NZPSpO.js.map} +1 -1
  41. package/dist/gateway/static/root/assets/{skills-page-Cq1gHbJ0.js → skills-page-D-AJTEVx.js} +2 -2
  42. package/dist/gateway/static/root/assets/{skills-page-Cq1gHbJ0.js.map → skills-page-D-AJTEVx.js.map} +1 -1
  43. package/dist/gateway/static/root/assets/{use-image-provider-credentials-BZcegAHq.js → use-image-provider-credentials-Cu5zeVdn.js} +2 -2
  44. package/dist/gateway/static/root/assets/{use-image-provider-credentials-BZcegAHq.js.map → use-image-provider-credentials-Cu5zeVdn.js.map} +1 -1
  45. package/dist/gateway/static/root/index.html +1 -1
  46. package/dist/package.js +1 -1
  47. package/dist/src/agent/agent-manager.js +6 -6
  48. package/dist/src/agent/context/workspace-seed.js +2 -2
  49. package/dist/src/agent/goals/post-turn.js +1 -1
  50. package/dist/src/agent/image/load-image-media.js +1 -1
  51. package/dist/src/agent/ipc/bus.js +1 -1
  52. package/dist/src/agent/ipc/inbox.js +2 -2
  53. package/dist/src/agent/ipc/socket.js +1 -1
  54. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  55. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  56. package/dist/src/agent/memory/dreaming/events.js +1 -1
  57. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  58. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  59. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  60. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  61. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  62. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  63. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  64. package/dist/src/agent/models/manager.js +1 -1
  65. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  66. package/dist/src/agent/service.js +5 -5
  67. package/dist/src/agent/skills/config.js +1 -1
  68. package/dist/src/agent/skills/hub-hash.js +2 -2
  69. package/dist/src/agent/skills/hub-lock.js +1 -1
  70. package/dist/src/agent/skills/hub-pull.js +1 -1
  71. package/dist/src/agent/skills/index.js +1 -1
  72. package/dist/src/agent/skills/managed-store.js +1 -1
  73. package/dist/src/agent/skills/scanner.js +1 -1
  74. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  75. package/dist/src/agent/skills/skill-manager.js +1 -1
  76. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  77. package/dist/src/agent/tools/factory.js +1 -1
  78. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  79. package/dist/src/agent/tools/send-media.js +1 -1
  80. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  81. package/dist/src/agent/tools/write.js +1 -1
  82. package/dist/src/auth/credentials.js +3 -3
  83. package/dist/src/auth/profiles/store.js +1 -1
  84. package/dist/src/auth/sync-provider-auth.js +1 -1
  85. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  86. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  87. package/dist/src/channels/outbound/persist-store.js +1 -1
  88. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  89. package/dist/src/channels/pairing/pairing-store.js +2 -2
  90. package/dist/src/chat-commands/builtins/config.js +2 -2
  91. package/dist/src/chat-commands/context.js +1 -1
  92. package/dist/src/cli/commands/agent.js +1 -1
  93. package/dist/src/cli/commands/agents.js +1 -1
  94. package/dist/src/cli/commands/config.js +1 -1
  95. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  96. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  97. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  98. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  99. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  100. package/dist/src/cli/commands/extension-dev.js +1 -1
  101. package/dist/src/cli/commands/extension-dev.js.map +1 -1
  102. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  103. package/dist/src/cli/commands/extension-pack.js +1 -1
  104. package/dist/src/cli/commands/image.js +1 -1
  105. package/dist/src/cli/commands/init.js +4 -4
  106. package/dist/src/cli/utils/init-workspace.js +2 -2
  107. package/dist/src/config/index.js +2 -2
  108. package/dist/src/config/loader.js +2 -2
  109. package/dist/src/config/models-json.js +2 -2
  110. package/dist/src/config/profile.js +2 -2
  111. package/dist/src/cron/executor.js +2 -2
  112. package/dist/src/cron/persistence.js +1 -1
  113. package/dist/src/cron/run-log-store.js +1 -1
  114. package/dist/src/daemon/launchd.js +2 -2
  115. package/dist/src/daemon/systemd.js +2 -2
  116. package/dist/src/extensions/health.js +1 -1
  117. package/dist/src/extensions/loader.js +1 -1
  118. package/dist/src/extensions/lockfile.js +2 -2
  119. package/dist/src/gateway/agents-admin.js +2 -2
  120. package/dist/src/gateway/hono/lib/extension-store.js +1 -1
  121. package/dist/src/gateway/hono/lib/static-ui.js +1 -1
  122. package/dist/src/gateway/hono/oauth.js +1 -1
  123. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  124. package/dist/src/gateway/hono/routes/config.js +1 -1
  125. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  126. package/dist/src/gateway/hono/routes/host-fs.js +1 -1
  127. package/dist/src/gateway/hono/routes/models.js +1 -1
  128. package/dist/src/gateway/hono/routes/workspace.js +3 -3
  129. package/dist/src/gateway/hono/sse.js +2 -2
  130. package/dist/src/gateway/lock.js +2 -2
  131. package/dist/src/gateway/service/run-gateway-agent.js +2 -2
  132. package/dist/src/gateway/service.js +5 -5
  133. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  134. package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
  135. package/dist/src/infra/update-check.js +1 -1
  136. package/dist/src/infra/update-lock.js +3 -3
  137. package/dist/src/infra/update-runner.js +1 -1
  138. package/dist/src/infra/update-startup.js +2 -2
  139. package/dist/src/infra/write-file-atomic.js +2 -2
  140. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  141. package/dist/src/providers/index.js +2 -2
  142. package/dist/src/providers/model-registry.js +1 -1
  143. package/dist/src/session/config-store.js +2 -2
  144. package/dist/src/session/search-index-cache.js +1 -1
  145. package/dist/src/session/search-index.js +1 -1
  146. package/dist/src/session/session-title.js +1 -1
  147. package/dist/src/session/store.js +5 -5
  148. package/dist/src/tui/backends/embedded-backend.js +1 -1
  149. package/dist/src/tui/tui.js +1 -1
  150. package/dist/src/utils/logger/audit.js +1 -1
  151. package/dist/src/utils/logger/log-store.js +1 -1
  152. package/dist/src/utils/logger/rotation.js +1 -1
  153. package/dist/src/voice/tts/audio.js +1 -1
  154. package/dist/src/voice/tts/providers/edge-speech.js +1 -1
  155. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{i as t,t as n}from"./vendor-react-DbimaAId.js";import{a as r,i}from"./vendor-swr-B5fPo7KK.js";import{An as a,At as o,Ci as s,Dr as c,Dt as l,Fn as u,Ln as d,Mt as f,Oi as p,Ot as m,Sn as h,Wn as g,X as _,Yr as v,_n as y,an as b,ar as x,ci as S,cn as C,fr as w,gn as T,hn as E,jt as D,kt as O,mi as k,mn as A,nr as j,on as M,sn as N,un as P,vi as F,vr as I}from"./index-DLfAjBJz.js";var L=e(t(),1);function R(e){return e===`builtin`||e===`user`?e:`marketplace`}async function z(e){try{let t=await e.json();if(typeof t.error==`string`)return t.error;if(typeof t.message==`string`)return t.message}catch{}return e.statusText||`HTTP ${e.status}`}async function B(e){let t=await A(P(`/api/marketplace/packages/${encodeURIComponent(e.trim())}`),{cache:`no-store`});if(!t.ok)throw Error(await z(t));let n=await t.json();if(!n.ok||!n.payload?.id)throw Error(n.error??`Invalid response`);return n.payload}async function V(e){let t=await A(P(`/api/marketplace/install`),{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)});if(!t.ok)throw Error(await z(t));let n=await t.json();if(!n.ok||!n.payload?.extensionId)throw Error(n.error??`Invalid response`);return n.payload}async function H(e){let t=await A(P(`/api/marketplace/uninstall`),{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({extensionId:e})});if(!t.ok)throw Error(await z(t));let n=await t.json();if(!n.ok||!n.payload)throw Error(n.error??`Invalid response`);return n.payload}var U=n();function W(e,t){let n=e.find(e=>e.id===t);return n?n.source===`bundled`?`bundled`:`user`:`absent`}function G({className:e}){let t=a(h(e=>e.language)).appsPage,n=y(e=>!!e.token),o=N(),{mutate:s}=r(),[l,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(``),m=n?`marketplace-${f}`:null,[_,v]=(0,L.useState)(null),[b,C]=(0,L.useState)(null),[w,T]=(0,L.useState)(null),[D,O]=(0,L.useState)(null);(0,L.useEffect)(()=>{let e=window.setTimeout(()=>p(l.trim()),300);return()=>window.clearTimeout(e)},[l]);let{data:k,isLoading:A,error:j}=i(m,async()=>E(f.length>0?P(`/api/marketplace?q=${encodeURIComponent(f)}`):P(`/api/marketplace`)),{revalidateOnFocus:!1}),M=(0,L.useCallback)(()=>{s(`gateway-extensions-list`),window.dispatchEvent(new CustomEvent(`config-reload`))},[s]),F=(0,L.useCallback)(async(e,n)=>{T(null),O(null),C(e);try{let r=await V({name:e,overwrite:n});M(),r.requiresGatewayRestart&&O(t.marketplaceRestartHint)}catch(e){throw T(e instanceof Error?e.message:t.marketplaceInstallFailed),e}finally{C(null)}},[t.marketplaceInstallFailed,t.marketplaceRestartHint,M]),R=(0,L.useCallback)(async e=>{T(null),O(null),C(e);try{let n=await H(e);M(),n.requiresGatewayRestart&&O(t.marketplaceRestartHint)}catch(e){throw T(e instanceof Error?e.message:t.marketplaceUninstallFailed),e}finally{C(null)}},[t.marketplaceRestartHint,t.marketplaceUninstallFailed,M]),z=k?.extensions??[];return(0,U.jsxs)(`div`,{className:u(`flex flex-col gap-4`,e),children:[(0,U.jsxs)(`div`,{className:`relative`,children:[(0,U.jsx)(x,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted`,strokeWidth:1.75,"aria-hidden":!0}),(0,U.jsx)(`input`,{type:`search`,value:l,onChange:e=>d(e.target.value),placeholder:t.marketplaceSearchPlaceholder,className:`ui-input h-10 w-full rounded-lg border border-edge bg-surface-base pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted`})]}),j?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:j instanceof Error?j.message:t.marketplaceLoadFailed}):null,w?(0,U.jsx)(`p`,{className:`text-sm text-red-600 dark:text-red-400`,children:w}):null,D?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:D}):null,A&&!k?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:`…`}):(0,U.jsx)(`ul`,{className:`flex flex-col gap-3`,children:z.length===0?(0,U.jsx)(`li`,{className:`text-sm text-fg-muted`,children:t.marketplaceEmpty}):z.map(e=>{let n=W(o,e.id),r=b===e.id;return(0,U.jsx)(`li`,{className:`list-none`,children:(0,U.jsxs)(`div`,{role:`button`,tabIndex:0,"aria-label":`${e.name}, ${t.marketplaceDetailTitle}`,onClick:()=>v(e.id),onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),v(e.id))},className:u(`flex w-full cursor-pointer flex-wrap items-start gap-3 rounded-xl border border-edge bg-surface-base p-4 text-left shadow-surface`,`transition-[transform,background-color,border-color,box-shadow] duration-150 ease-out`,`hover:border-edge-subtle hover:bg-surface-hover/40`,`active:scale-[0.992] active:bg-surface-hover/55`,`focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-panel`,`dark:hover:bg-surface-hover/25 dark:active:bg-surface-hover/35`),children:[(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,U.jsx)(`h3`,{className:`font-semibold text-fg`,children:e.name}),e.verified?(0,U.jsx)(S,{className:`size-4 shrink-0 text-emerald-600 dark:text-emerald-400`,strokeWidth:1.75,"aria-label":`Verified`}):null,e.version?(0,U.jsx)(`span`,{className:`text-xs text-fg-muted`,children:e.version}):null]}),e.description?(0,U.jsx)(`p`,{className:`mt-1 line-clamp-2 text-sm text-fg-muted`,children:e.description}):null,(0,U.jsx)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:(e.categories??[]).map(e=>(0,U.jsx)(`span`,{className:`rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-[11px] text-fg-muted`,children:e},e))}),(0,U.jsxs)(`p`,{className:`mt-2 flex items-center gap-1.5 text-xs text-fg-muted`,children:[(0,U.jsx)(I,{className:`size-3.5 shrink-0`,strokeWidth:1.75,"aria-hidden":!0}),(0,U.jsx)(`code`,{className:`rounded bg-surface-panel px-1 py-0.5`,children:e.npmPackage})]})]}),(0,U.jsx)(`div`,{className:`flex shrink-0 flex-col items-end gap-2 sm:min-w-[9rem]`,onClick:e=>e.stopPropagation(),onKeyDown:e=>e.stopPropagation(),children:n===`bundled`?(0,U.jsx)(`span`,{className:`rounded-md bg-surface-hover px-2 py-1 text-[11px] font-medium text-fg-muted`,children:t.marketplaceBuiltin}):n===`user`?(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(`span`,{className:`text-[11px] font-medium text-fg-muted`,children:t.marketplaceInstalled}),(0,U.jsxs)(`button`,{type:`button`,disabled:r,onClick:()=>{window.confirm(t.marketplaceUninstallConfirm)&&R(e.id).catch(()=>{})},className:u(`inline-flex items-center justify-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-xs font-medium text-fg`,`transition-colors active:scale-[0.98] active:bg-surface-hover/80`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,`disabled:pointer-events-none disabled:opacity-50`),children:[r?(0,U.jsx)(c,{className:`size-3.5 animate-spin`,"aria-hidden":!0}):(0,U.jsx)(g,{className:`size-3.5`,strokeWidth:2,"aria-hidden":!0}),t.marketplaceUninstall]})]}):(0,U.jsxs)(`button`,{type:`button`,disabled:r,onClick:()=>{F(e.id,!1).catch(()=>{})},className:u(`inline-flex w-full items-center justify-center rounded-lg bg-accent px-3 py-2 text-xs font-medium text-white`,`shadow-surface transition-[transform,background-color] active:scale-[0.98]`,`hover:bg-accent-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-base`,`disabled:pointer-events-none disabled:opacity-50`),children:[r?(0,U.jsx)(c,{className:`size-3.5 animate-spin`,"aria-hidden":!0}):null,t.marketplaceInstall]})})]})},e.id)})}),_?(0,U.jsx)(K,{packageName:_,copy:t,extensions:o,onClose:()=>v(null),onInstall:F,onUninstall:R}):null]})}function K({packageName:e,copy:t,extensions:n,onClose:r,onInstall:a,onUninstall:s}){let[p,m]=(0,L.useState)(!1),{data:h,error:v,isLoading:b}=i(y(e=>!!e.token)?`ext-mp-detail-${e}`:null,async()=>B(e),{revalidateOnFocus:!1}),x=W(n,e),S=x===`user`,C=h?.readme?.trim()||(h?.description?.trim()?`### ${h.name}\n\n${h.description}`:`*${t.marketplaceNoReadme}*`);return(0,U.jsx)(D,{defaultOpen:!0,onOpenChange:e=>!e&&r(),children:(0,U.jsxs)(o,{children:[(0,U.jsx)(O,{className:`xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim`}),(0,U.jsxs)(l,{className:`fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated`,onOpenAutoFocus:e=>e.preventDefault(),children:[(0,U.jsxs)(`div`,{className:`flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3`,children:[(0,U.jsx)(`button`,{type:`button`,onClick:r,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailBack,children:(0,U.jsx)(F,{className:`size-5`})}),(0,U.jsx)(f,{className:`min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg`,children:t.marketplaceDetailTitle}),(0,U.jsx)(`button`,{type:`button`,onClick:r,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailClose,children:(0,U.jsx)(d,{className:`size-5`})})]}),(0,U.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-5`,children:b&&!h?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:`…`}):v?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:t.marketplaceDetailLoadFailed}):h?(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(`h3`,{className:`text-lg font-semibold text-fg`,children:h.name}),(0,U.jsx)(`p`,{className:`mt-1 text-xs text-fg-muted`,children:(0,U.jsx)(`code`,{className:`rounded bg-surface-panel px-1 py-0.5`,children:h.id})}),(0,U.jsxs)(`dl`,{className:`mt-3 grid gap-2 text-xs text-fg-muted sm:grid-cols-2`,children:[(0,U.jsxs)(`div`,{children:[(0,U.jsx)(`dt`,{className:`font-medium text-fg`,children:t.marketplaceAuthor}),(0,U.jsx)(`dd`,{children:h.author.username})]}),(0,U.jsxs)(`div`,{children:[(0,U.jsx)(`dt`,{className:`font-medium text-fg`,children:t.marketplaceVersion}),(0,U.jsx)(`dd`,{children:h.latestVersion.version})]}),(0,U.jsxs)(`div`,{children:[(0,U.jsx)(`dt`,{className:`font-medium text-fg`,children:t.marketplaceDownloads}),(0,U.jsx)(`dd`,{children:h.downloads})]})]}),h.readme?.trim()?(0,U.jsx)(`h4`,{className:`mb-2 mt-6 text-sm font-semibold text-fg`,children:t.marketplaceDetailReadmeHeading}):null,(0,U.jsx)(`div`,{className:`markdown-content min-w-0 break-words text-sm`,children:(0,U.jsx)(_,{content:C})})]}):null}),h?(0,U.jsx)(`div`,{className:`flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-edge-subtle px-5 py-4`,children:x===`bundled`?(0,U.jsx)(`p`,{className:`w-full text-sm leading-relaxed text-fg-muted`,children:t.marketplaceBuiltinManageHint}):(0,U.jsxs)(U.Fragment,{children:[(0,U.jsxs)(`button`,{type:`button`,disabled:p,onClick:()=>{S&&!window.confirm(t.marketplaceReinstallConfirm)||(m(!0),a(e,S).catch(()=>{}).finally(()=>m(!1)))},className:u(`inline-flex items-center justify-center gap-1.5 rounded-lg px-3 py-2 text-sm font-medium`,`bg-accent text-white shadow-surface hover:bg-accent-hover`,`focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-panel`,`disabled:pointer-events-none disabled:opacity-50`),children:[p?(0,U.jsx)(c,{className:`size-4 animate-spin`,"aria-hidden":!0}):null,S?t.marketplaceReinstall:t.marketplaceInstall]}),S?(0,U.jsxs)(`button`,{type:`button`,disabled:p,onClick:()=>{window.confirm(t.marketplaceUninstallConfirm)&&(m(!0),s(e).then(()=>r()).catch(()=>{}).finally(()=>m(!1)))},className:u(`inline-flex items-center justify-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,`disabled:pointer-events-none disabled:opacity-50`),children:[(0,U.jsx)(g,{className:`size-4 shrink-0`,"aria-hidden":!0}),t.marketplaceUninstall]}):null]})}):null]})]})})}function q(){let e=h(e=>e.language),t=a(e),n=T(e=>e.setPageHeader),r=T(e=>e.clearPageHeader),i=N(),o=C(),[s,c]=p(),l=R(s.get(`tab`)),d=s.get(`q`)??``,[f,m]=(0,L.useState)(l),[g,_]=(0,L.useState)(d),[v,y]=(0,L.useState)(null);(0,L.useEffect)(()=>{let e=R(s.get(`tab`)),t=s.get(`q`)??``;m(t=>t===e?t:e),_(e=>e===t?e:t)},[s]),(0,L.useEffect)(()=>{c(e=>{let t=new URLSearchParams(e),n=g.trim();return n?t.set(`q`,n):t.delete(`q`),f===`marketplace`?t.delete(`tab`):t.set(`tab`,f),t.toString()===e.toString()?e:t},{replace:!0})},[f,g,c]);let b=(0,L.useMemo)(()=>i.filter(e=>e.source===`bundled`),[i]),S=(0,L.useMemo)(()=>i.filter(e=>e.source!==`bundled`),[i]),w=f===`builtin`?b:S,E=(0,L.useMemo)(()=>{let t=g.trim().toLowerCase(),n=w;return t&&(n=n.filter(e=>(e.name??``).toLowerCase().includes(t)||e.id.toLowerCase().includes(t)||(e.description??``).toLowerCase().includes(t))),[...n].sort((t,n)=>t.hasUi===n.hasUi?(t.name||t.id).localeCompare(n.name||n.id,e):t.hasUi?-1:1)},[w,g,e]);if((0,L.useEffect)(()=>{y(e=>{if(!e)return e;let t=i.find(t=>t.id===e.id);return t?J(e)===J(t)&&e.active===t.active?e:t:null})},[i]),(0,L.useLayoutEffect)(()=>(n({startExtra:null,main:(0,U.jsx)(`div`,{className:`w-full min-w-0 px-3 sm:px-5 xl:px-6`,children:(0,U.jsx)(`h1`,{className:`min-w-0 truncate text-base font-semibold tracking-tight text-fg`,children:t.appsPage.title})}),end:null}),()=>r()),[r,t.appsPage.title,n]),o&&f!==`marketplace`)return(0,U.jsx)(ne,{});let D=f!==`marketplace`&&w.length>0;return(0,U.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel`,children:[(0,U.jsxs)(`div`,{className:`mx-auto w-full max-w-app-main px-4 py-8`,children:[(0,U.jsxs)(`header`,{className:`mb-6`,children:[(0,U.jsx)(`h1`,{className:`text-xl font-semibold text-fg`,children:t.appsPage.title}),(0,U.jsx)(`p`,{className:`mt-1 text-sm text-fg-muted`,children:t.appsPage.subtitle})]}),(0,U.jsxs)(`div`,{className:`mb-5 flex flex-col gap-3 border-b border-edge-subtle pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-edge-subtle`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap gap-x-1 gap-y-1`,role:`tablist`,"aria-label":t.appsPage.appsNavAria,children:[(0,U.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":f===`marketplace`,className:u(`relative max-w-full rounded-md px-3 py-2 text-left text-sm font-medium transition-colors sm:text-center`,f===`marketplace`?`text-fg`:`text-fg-muted hover:text-fg`,f===`marketplace`&&`after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent`),onClick:()=>m(`marketplace`),children:t.appsPage.tabMarketplace}),(0,U.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":f===`builtin`,className:u(`relative rounded-md px-3 py-2 text-sm font-medium transition-colors`,f===`builtin`?`text-fg`:`text-fg-muted hover:text-fg`,f===`builtin`&&`after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent`),onClick:()=>m(`builtin`),children:[t.appsPage.tabBuiltin,(0,U.jsxs)(`span`,{className:`ml-1 tabular-nums text-fg-muted`,children:[`(`,b.length,`)`]})]}),(0,U.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":f===`user`,className:u(`relative rounded-md px-3 py-2 text-sm font-medium transition-colors`,f===`user`?`text-fg`:`text-fg-muted hover:text-fg`,f===`user`&&`after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent`),onClick:()=>m(`user`),children:[t.appsPage.tabUser,(0,U.jsxs)(`span`,{className:`ml-1 tabular-nums text-fg-muted`,children:[`(`,S.length,`)`]})]})]}),D?(0,U.jsxs)(`div`,{className:`relative w-full min-w-0 sm:max-w-xs`,children:[(0,U.jsx)(x,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted`,"aria-hidden":!0}),(0,U.jsx)(`input`,{type:`search`,value:g,onChange:e=>_(e.target.value),placeholder:t.appsPage.searchPlaceholder,className:`w-full rounded-lg border border-edge bg-surface-base py-2 pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,autoComplete:`off`})]}):null]}),f===`marketplace`?(0,U.jsx)(G,{}):f===`builtin`&&b.length===0?(0,U.jsx)($,{message:t.appsPage.emptyBuiltin}):f===`user`&&S.length===0?(0,U.jsx)($,{message:t.appsPage.emptyUser}):E.length===0?(0,U.jsx)(`p`,{className:`rounded-xl border border-dashed border-edge-subtle bg-surface-hover/30 px-4 py-8 text-center text-sm text-fg-muted dark:bg-surface-hover/15`,children:t.appsPage.noSearchResults}):(0,U.jsx)(`div`,{className:`grid gap-4 sm:grid-cols-2 lg:grid-cols-3`,children:E.map(e=>(0,U.jsx)(ee,{extension:e,copy:t.appsPage,showSourceBadge:f===`user`,onOpen:()=>y(e)},e.id))})]}),v?(0,U.jsx)(te,{extension:v,copy:t.appsPage,onClose:()=>y(null)},v.id):null]})}function J(e){return e.activationEligible??e.active}function Y(e,t){return e.source===`bundled`?t.providerBundled:e.source===`global`?t.providerGlobal:e.source===`workspace`?t.providerWorkspace:t.providerOther}function X(e,t){return e.source===`global`?t.badgeSourceGlobal:e.source===`workspace`?t.badgeSourceWorkspace:t.badgeSourceOther}function Z(e,t){let n=J(e);return n&&e.active?t.runStateLive:n&&!e.active?t.runStatePendingOn:!n&&e.active?t.runStatePendingOff:t.runStateOff}function ee({extension:e,copy:t,showSourceBadge:n,onOpen:r}){let i=J(e),a=e.hasUi?t.cardTooltipHasUi:t.cardTooltipNoUi;return(0,U.jsx)(`button`,{type:`button`,onClick:r,className:u(`group flex w-full flex-col rounded-xl border border-edge bg-surface-base p-4 text-left shadow-sm transition-colors`,`hover:border-edge-subtle hover:bg-surface-hover/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,`dark:hover:bg-surface-hover/25`),children:(0,U.jsxs)(`div`,{className:`flex gap-3`,children:[(0,U.jsx)(`div`,{className:`flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent-soft text-base font-semibold text-accent-fg`,"aria-hidden":!0,children:(e.name||e.id).charAt(0).toUpperCase()}),(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(`h2`,{className:`truncate text-sm font-semibold text-fg`,children:e.name}),e.version?(0,U.jsxs)(`span`,{className:`text-[11px] text-fg-muted`,children:[`v`,e.version]}):null]}),i?(0,U.jsxs)(`span`,{className:`inline-flex shrink-0 items-center gap-1 rounded-full bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted`,children:[(0,U.jsx)(k,{className:`size-3`,strokeWidth:2.5,"aria-hidden":!0}),t.statusEnabled]}):(0,U.jsx)(`span`,{className:`flex size-8 shrink-0 items-center justify-center rounded-full border-2 border-accent text-accent`,"aria-hidden":!0,children:(0,U.jsx)(w,{className:`size-4`,strokeWidth:2.5})})]}),(0,U.jsx)(`p`,{className:`mt-2 line-clamp-2 text-xs leading-relaxed text-fg-muted`,children:e.description?.trim()||t.cardNoDescription}),(0,U.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[(0,U.jsx)(`span`,{title:a,className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:e.hasUi?t.badgeKindUi:t.badgeKindBackend}),e.source===`bundled`?(0,U.jsx)(`span`,{className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:t.badgeBundled}):n?(0,U.jsx)(`span`,{title:Y(e,t),className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:X(e,t)}):null]})]})]})})}function te({extension:e,copy:t,onClose:n}){let r=e.ui?.contributions?.pages??[],i=e.ui?.contributions?.settingsPanels??[],a=e.ui?.contributions?.chatWidgets??[],c=e.ui?.contributions?.sidebarPanels??[],p=r.find(e=>e.showInNav)??r[0],h=i[0],g=p?b(e.id,p):null,_=h?`/settings/ext/${e.id}/${h.id}`:e.hasConfigSchema?`/settings/ext/${e.id}`:null;return(0,U.jsx)(D,{defaultOpen:!0,onOpenChange:e=>!e&&n(),children:(0,U.jsxs)(o,{children:[(0,U.jsx)(O,{className:`xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim`}),(0,U.jsxs)(l,{className:`fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated`,onOpenAutoFocus:e=>e.preventDefault(),children:[(0,U.jsxs)(`div`,{className:`flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3`,children:[(0,U.jsx)(`button`,{type:`button`,onClick:n,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailBack,children:(0,U.jsx)(F,{className:`size-5`})}),(0,U.jsx)(f,{className:`min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg`,children:t.detailTitle}),(0,U.jsxs)(m,{className:`sr-only`,children:[e.name,` (`,e.id,`)`]}),(0,U.jsx)(`button`,{type:`button`,onClick:n,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailClose,children:(0,U.jsx)(d,{className:`size-5`})})]}),(0,U.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-5`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap items-start gap-4`,children:[(0,U.jsx)(`div`,{className:`flex size-16 shrink-0 items-center justify-center rounded-2xl bg-accent-soft text-xl font-semibold text-accent-fg`,"aria-hidden":!0,children:(e.name||e.id).charAt(0).toUpperCase()}),(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsx)(`h3`,{className:`text-lg font-semibold text-fg`,children:e.name}),(0,U.jsxs)(`p`,{className:`mt-0.5 text-sm text-fg-muted`,children:[t.detailProviderPrefix,` `,Y(e,t)]}),e.version?(0,U.jsxs)(`p`,{className:`mt-1 text-xs text-fg-muted`,children:[`v`,e.version]}):null]})]}),(0,U.jsx)(`p`,{className:`mt-5 text-sm leading-relaxed text-fg`,children:e.description?.trim()||t.detailNoDescription}),e.hasUi?null:(0,U.jsx)(`p`,{className:`mt-3 text-xs text-fg-muted`,children:t.backendOnlyHint}),(0,U.jsx)(`p`,{className:`mt-2 text-xs text-fg-muted`,children:Z(e,t)}),e.source===`bundled`?(0,U.jsx)(`p`,{className:`mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20`,children:t.builtinConfigHint}):(0,U.jsx)(`p`,{className:`mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20`,children:t.cliManageHint}),e.hasUi&&(r.length>0||i.length>0||a.length>0)?(0,U.jsxs)(`section`,{className:`mt-8`,children:[(0,U.jsx)(`h4`,{className:`mb-3 text-sm font-semibold text-fg`,children:t.detailSectionFeatures}),(0,U.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,U.jsx)(Q,{template:t.badgePages,count:r.length,hidden:r.length===0}),(0,U.jsx)(Q,{template:t.badgeSettings,count:i.length,hidden:i.length===0}),(0,U.jsx)(Q,{template:t.badgeWidgets,count:a.length,hidden:a.length===0}),(0,U.jsx)(Q,{template:t.badgeSidebar,count:c.length,hidden:c.length===0})]})]}):null,M(e)&&(g||_)?(0,U.jsxs)(`div`,{className:`mt-6 flex flex-wrap gap-2 border-t border-edge-subtle pt-4`,children:[g?(0,U.jsxs)(s,{to:g,onClick:n,className:u(`inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`),children:[(0,U.jsx)(v,{className:`size-4 shrink-0 opacity-80`,"aria-hidden":!0}),t.open]}):null,_?(0,U.jsxs)(s,{to:_,onClick:n,className:u(`inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`),children:[(0,U.jsx)(j,{className:`size-4 shrink-0 opacity-80`,"aria-hidden":!0}),t.openSettings]}):null]}):null,(0,U.jsx)(`p`,{className:`mt-6 text-[11px] leading-relaxed text-fg-muted`,children:t.restartNote})]})]})]})})}function Q({template:e,count:t,hidden:n}){return n||t===0?null:(0,U.jsx)(`span`,{className:`inline-flex items-center rounded-md bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted`,children:e.replace(/\{\{count\}\}/g,String(t))})}function ne(){return(0,U.jsx)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel`,children:(0,U.jsxs)(`div`,{className:`mx-auto w-full max-w-app-main px-4 py-8`,children:[(0,U.jsx)(`div`,{className:`mb-6 h-8 w-40 max-w-full animate-pulse rounded-md bg-surface-hover`}),(0,U.jsx)(`div`,{className:`mb-2 h-4 w-full max-w-md animate-pulse rounded bg-surface-hover`}),(0,U.jsx)(`div`,{className:`mb-5 h-9 w-full max-w-lg animate-pulse rounded-full bg-surface-hover`}),(0,U.jsx)(`div`,{className:`mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3`,children:[0,1,2,3,4,5].map(e=>(0,U.jsx)(`div`,{className:`h-36 animate-pulse rounded-xl border border-edge bg-surface-base`},e))})]})})}function $({message:e}){return(0,U.jsx)(`div`,{className:`flex min-h-[min(40vh,16rem)] flex-col items-center justify-center rounded-xl border border-dashed border-edge-subtle bg-surface-hover/40 px-4 py-12 text-center dark:bg-surface-hover/20`,children:(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:e})})}export{q as AppsPage};
2
- //# sourceMappingURL=apps-page-DOHsxEjt.js.map
1
+ import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{i as t,t as n}from"./vendor-react-DbimaAId.js";import{a as r,i}from"./vendor-swr-B5fPo7KK.js";import{An as a,At as o,Ci as s,Dr as c,Dt as l,Fn as u,Ln as d,Mt as f,Oi as p,Ot as m,Sn as h,Wn as g,X as _,Yr as v,_n as y,an as b,ar as x,ci as S,cn as C,fr as w,gn as T,hn as E,jt as D,kt as O,mi as k,mn as A,nr as j,on as M,sn as N,un as P,vi as F,vr as I}from"./index-KxjI2fjF.js";var L=e(t(),1);function R(e){return e===`builtin`||e===`user`?e:`marketplace`}async function z(e){try{let t=await e.json();if(typeof t.error==`string`)return t.error;if(typeof t.message==`string`)return t.message}catch{}return e.statusText||`HTTP ${e.status}`}async function B(e){let t=await A(P(`/api/marketplace/packages/${encodeURIComponent(e.trim())}`),{cache:`no-store`});if(!t.ok)throw Error(await z(t));let n=await t.json();if(!n.ok||!n.payload?.id)throw Error(n.error??`Invalid response`);return n.payload}async function V(e){let t=await A(P(`/api/marketplace/install`),{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)});if(!t.ok)throw Error(await z(t));let n=await t.json();if(!n.ok||!n.payload?.extensionId)throw Error(n.error??`Invalid response`);return n.payload}async function H(e){let t=await A(P(`/api/marketplace/uninstall`),{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({extensionId:e})});if(!t.ok)throw Error(await z(t));let n=await t.json();if(!n.ok||!n.payload)throw Error(n.error??`Invalid response`);return n.payload}var U=n();function W(e,t){let n=e.find(e=>e.id===t);return n?n.source===`bundled`?`bundled`:`user`:`absent`}function G({className:e}){let t=a(h(e=>e.language)).appsPage,n=y(e=>!!e.token),o=N(),{mutate:s}=r(),[l,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(``),m=n?`marketplace-${f}`:null,[_,v]=(0,L.useState)(null),[b,C]=(0,L.useState)(null),[w,T]=(0,L.useState)(null),[D,O]=(0,L.useState)(null);(0,L.useEffect)(()=>{let e=window.setTimeout(()=>p(l.trim()),300);return()=>window.clearTimeout(e)},[l]);let{data:k,isLoading:A,error:j}=i(m,async()=>E(f.length>0?P(`/api/marketplace?q=${encodeURIComponent(f)}`):P(`/api/marketplace`)),{revalidateOnFocus:!1}),M=(0,L.useCallback)(()=>{s(`gateway-extensions-list`),window.dispatchEvent(new CustomEvent(`config-reload`))},[s]),F=(0,L.useCallback)(async(e,n)=>{T(null),O(null),C(e);try{let r=await V({name:e,overwrite:n});M(),r.requiresGatewayRestart&&O(t.marketplaceRestartHint)}catch(e){throw T(e instanceof Error?e.message:t.marketplaceInstallFailed),e}finally{C(null)}},[t.marketplaceInstallFailed,t.marketplaceRestartHint,M]),R=(0,L.useCallback)(async e=>{T(null),O(null),C(e);try{let n=await H(e);M(),n.requiresGatewayRestart&&O(t.marketplaceRestartHint)}catch(e){throw T(e instanceof Error?e.message:t.marketplaceUninstallFailed),e}finally{C(null)}},[t.marketplaceRestartHint,t.marketplaceUninstallFailed,M]),z=k?.extensions??[];return(0,U.jsxs)(`div`,{className:u(`flex flex-col gap-4`,e),children:[(0,U.jsxs)(`div`,{className:`relative`,children:[(0,U.jsx)(x,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted`,strokeWidth:1.75,"aria-hidden":!0}),(0,U.jsx)(`input`,{type:`search`,value:l,onChange:e=>d(e.target.value),placeholder:t.marketplaceSearchPlaceholder,className:`ui-input h-10 w-full rounded-lg border border-edge bg-surface-base pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted`})]}),j?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:j instanceof Error?j.message:t.marketplaceLoadFailed}):null,w?(0,U.jsx)(`p`,{className:`text-sm text-red-600 dark:text-red-400`,children:w}):null,D?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:D}):null,A&&!k?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:`…`}):(0,U.jsx)(`ul`,{className:`flex flex-col gap-3`,children:z.length===0?(0,U.jsx)(`li`,{className:`text-sm text-fg-muted`,children:t.marketplaceEmpty}):z.map(e=>{let n=W(o,e.id),r=b===e.id;return(0,U.jsx)(`li`,{className:`list-none`,children:(0,U.jsxs)(`div`,{role:`button`,tabIndex:0,"aria-label":`${e.name}, ${t.marketplaceDetailTitle}`,onClick:()=>v(e.id),onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),v(e.id))},className:u(`flex w-full cursor-pointer flex-wrap items-start gap-3 rounded-xl border border-edge bg-surface-base p-4 text-left shadow-surface`,`transition-[transform,background-color,border-color,box-shadow] duration-150 ease-out`,`hover:border-edge-subtle hover:bg-surface-hover/40`,`active:scale-[0.992] active:bg-surface-hover/55`,`focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-panel`,`dark:hover:bg-surface-hover/25 dark:active:bg-surface-hover/35`),children:[(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,U.jsx)(`h3`,{className:`font-semibold text-fg`,children:e.name}),e.verified?(0,U.jsx)(S,{className:`size-4 shrink-0 text-emerald-600 dark:text-emerald-400`,strokeWidth:1.75,"aria-label":`Verified`}):null,e.version?(0,U.jsx)(`span`,{className:`text-xs text-fg-muted`,children:e.version}):null]}),e.description?(0,U.jsx)(`p`,{className:`mt-1 line-clamp-2 text-sm text-fg-muted`,children:e.description}):null,(0,U.jsx)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:(e.categories??[]).map(e=>(0,U.jsx)(`span`,{className:`rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-[11px] text-fg-muted`,children:e},e))}),(0,U.jsxs)(`p`,{className:`mt-2 flex items-center gap-1.5 text-xs text-fg-muted`,children:[(0,U.jsx)(I,{className:`size-3.5 shrink-0`,strokeWidth:1.75,"aria-hidden":!0}),(0,U.jsx)(`code`,{className:`rounded bg-surface-panel px-1 py-0.5`,children:e.npmPackage})]})]}),(0,U.jsx)(`div`,{className:`flex shrink-0 flex-col items-end gap-2 sm:min-w-[9rem]`,onClick:e=>e.stopPropagation(),onKeyDown:e=>e.stopPropagation(),children:n===`bundled`?(0,U.jsx)(`span`,{className:`rounded-md bg-surface-hover px-2 py-1 text-[11px] font-medium text-fg-muted`,children:t.marketplaceBuiltin}):n===`user`?(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(`span`,{className:`text-[11px] font-medium text-fg-muted`,children:t.marketplaceInstalled}),(0,U.jsxs)(`button`,{type:`button`,disabled:r,onClick:()=>{window.confirm(t.marketplaceUninstallConfirm)&&R(e.id).catch(()=>{})},className:u(`inline-flex items-center justify-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-xs font-medium text-fg`,`transition-colors active:scale-[0.98] active:bg-surface-hover/80`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,`disabled:pointer-events-none disabled:opacity-50`),children:[r?(0,U.jsx)(c,{className:`size-3.5 animate-spin`,"aria-hidden":!0}):(0,U.jsx)(g,{className:`size-3.5`,strokeWidth:2,"aria-hidden":!0}),t.marketplaceUninstall]})]}):(0,U.jsxs)(`button`,{type:`button`,disabled:r,onClick:()=>{F(e.id,!1).catch(()=>{})},className:u(`inline-flex w-full items-center justify-center rounded-lg bg-accent px-3 py-2 text-xs font-medium text-white`,`shadow-surface transition-[transform,background-color] active:scale-[0.98]`,`hover:bg-accent-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-base`,`disabled:pointer-events-none disabled:opacity-50`),children:[r?(0,U.jsx)(c,{className:`size-3.5 animate-spin`,"aria-hidden":!0}):null,t.marketplaceInstall]})})]})},e.id)})}),_?(0,U.jsx)(K,{packageName:_,copy:t,extensions:o,onClose:()=>v(null),onInstall:F,onUninstall:R}):null]})}function K({packageName:e,copy:t,extensions:n,onClose:r,onInstall:a,onUninstall:s}){let[p,m]=(0,L.useState)(!1),{data:h,error:v,isLoading:b}=i(y(e=>!!e.token)?`ext-mp-detail-${e}`:null,async()=>B(e),{revalidateOnFocus:!1}),x=W(n,e),S=x===`user`,C=h?.readme?.trim()||(h?.description?.trim()?`### ${h.name}\n\n${h.description}`:`*${t.marketplaceNoReadme}*`);return(0,U.jsx)(D,{defaultOpen:!0,onOpenChange:e=>!e&&r(),children:(0,U.jsxs)(o,{children:[(0,U.jsx)(O,{className:`xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim`}),(0,U.jsxs)(l,{className:`fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated`,onOpenAutoFocus:e=>e.preventDefault(),children:[(0,U.jsxs)(`div`,{className:`flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3`,children:[(0,U.jsx)(`button`,{type:`button`,onClick:r,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailBack,children:(0,U.jsx)(F,{className:`size-5`})}),(0,U.jsx)(f,{className:`min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg`,children:t.marketplaceDetailTitle}),(0,U.jsx)(`button`,{type:`button`,onClick:r,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailClose,children:(0,U.jsx)(d,{className:`size-5`})})]}),(0,U.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-5`,children:b&&!h?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:`…`}):v?(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:t.marketplaceDetailLoadFailed}):h?(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(`h3`,{className:`text-lg font-semibold text-fg`,children:h.name}),(0,U.jsx)(`p`,{className:`mt-1 text-xs text-fg-muted`,children:(0,U.jsx)(`code`,{className:`rounded bg-surface-panel px-1 py-0.5`,children:h.id})}),(0,U.jsxs)(`dl`,{className:`mt-3 grid gap-2 text-xs text-fg-muted sm:grid-cols-2`,children:[(0,U.jsxs)(`div`,{children:[(0,U.jsx)(`dt`,{className:`font-medium text-fg`,children:t.marketplaceAuthor}),(0,U.jsx)(`dd`,{children:h.author.username})]}),(0,U.jsxs)(`div`,{children:[(0,U.jsx)(`dt`,{className:`font-medium text-fg`,children:t.marketplaceVersion}),(0,U.jsx)(`dd`,{children:h.latestVersion.version})]}),(0,U.jsxs)(`div`,{children:[(0,U.jsx)(`dt`,{className:`font-medium text-fg`,children:t.marketplaceDownloads}),(0,U.jsx)(`dd`,{children:h.downloads})]})]}),h.readme?.trim()?(0,U.jsx)(`h4`,{className:`mb-2 mt-6 text-sm font-semibold text-fg`,children:t.marketplaceDetailReadmeHeading}):null,(0,U.jsx)(`div`,{className:`markdown-content min-w-0 break-words text-sm`,children:(0,U.jsx)(_,{content:C})})]}):null}),h?(0,U.jsx)(`div`,{className:`flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-edge-subtle px-5 py-4`,children:x===`bundled`?(0,U.jsx)(`p`,{className:`w-full text-sm leading-relaxed text-fg-muted`,children:t.marketplaceBuiltinManageHint}):(0,U.jsxs)(U.Fragment,{children:[(0,U.jsxs)(`button`,{type:`button`,disabled:p,onClick:()=>{S&&!window.confirm(t.marketplaceReinstallConfirm)||(m(!0),a(e,S).catch(()=>{}).finally(()=>m(!1)))},className:u(`inline-flex items-center justify-center gap-1.5 rounded-lg px-3 py-2 text-sm font-medium`,`bg-accent text-white shadow-surface hover:bg-accent-hover`,`focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-panel`,`disabled:pointer-events-none disabled:opacity-50`),children:[p?(0,U.jsx)(c,{className:`size-4 animate-spin`,"aria-hidden":!0}):null,S?t.marketplaceReinstall:t.marketplaceInstall]}),S?(0,U.jsxs)(`button`,{type:`button`,disabled:p,onClick:()=>{window.confirm(t.marketplaceUninstallConfirm)&&(m(!0),s(e).then(()=>r()).catch(()=>{}).finally(()=>m(!1)))},className:u(`inline-flex items-center justify-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,`disabled:pointer-events-none disabled:opacity-50`),children:[(0,U.jsx)(g,{className:`size-4 shrink-0`,"aria-hidden":!0}),t.marketplaceUninstall]}):null]})}):null]})]})})}function q(){let e=h(e=>e.language),t=a(e),n=T(e=>e.setPageHeader),r=T(e=>e.clearPageHeader),i=N(),o=C(),[s,c]=p(),l=R(s.get(`tab`)),d=s.get(`q`)??``,[f,m]=(0,L.useState)(l),[g,_]=(0,L.useState)(d),[v,y]=(0,L.useState)(null);(0,L.useEffect)(()=>{let e=R(s.get(`tab`)),t=s.get(`q`)??``;m(t=>t===e?t:e),_(e=>e===t?e:t)},[s]),(0,L.useEffect)(()=>{c(e=>{let t=new URLSearchParams(e),n=g.trim();return n?t.set(`q`,n):t.delete(`q`),f===`marketplace`?t.delete(`tab`):t.set(`tab`,f),t.toString()===e.toString()?e:t},{replace:!0})},[f,g,c]);let b=(0,L.useMemo)(()=>i.filter(e=>e.source===`bundled`),[i]),S=(0,L.useMemo)(()=>i.filter(e=>e.source!==`bundled`),[i]),w=f===`builtin`?b:S,E=(0,L.useMemo)(()=>{let t=g.trim().toLowerCase(),n=w;return t&&(n=n.filter(e=>(e.name??``).toLowerCase().includes(t)||e.id.toLowerCase().includes(t)||(e.description??``).toLowerCase().includes(t))),[...n].sort((t,n)=>t.hasUi===n.hasUi?(t.name||t.id).localeCompare(n.name||n.id,e):t.hasUi?-1:1)},[w,g,e]);if((0,L.useEffect)(()=>{y(e=>{if(!e)return e;let t=i.find(t=>t.id===e.id);return t?J(e)===J(t)&&e.active===t.active?e:t:null})},[i]),(0,L.useLayoutEffect)(()=>(n({startExtra:null,main:(0,U.jsx)(`div`,{className:`w-full min-w-0 px-3 sm:px-5 xl:px-6`,children:(0,U.jsx)(`h1`,{className:`min-w-0 truncate text-base font-semibold tracking-tight text-fg`,children:t.appsPage.title})}),end:null}),()=>r()),[r,t.appsPage.title,n]),o&&f!==`marketplace`)return(0,U.jsx)(ne,{});let D=f!==`marketplace`&&w.length>0;return(0,U.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel`,children:[(0,U.jsxs)(`div`,{className:`mx-auto w-full max-w-app-main px-4 py-8`,children:[(0,U.jsxs)(`header`,{className:`mb-6`,children:[(0,U.jsx)(`h1`,{className:`text-xl font-semibold text-fg`,children:t.appsPage.title}),(0,U.jsx)(`p`,{className:`mt-1 text-sm text-fg-muted`,children:t.appsPage.subtitle})]}),(0,U.jsxs)(`div`,{className:`mb-5 flex flex-col gap-3 border-b border-edge-subtle pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-edge-subtle`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap gap-x-1 gap-y-1`,role:`tablist`,"aria-label":t.appsPage.appsNavAria,children:[(0,U.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":f===`marketplace`,className:u(`relative max-w-full rounded-md px-3 py-2 text-left text-sm font-medium transition-colors sm:text-center`,f===`marketplace`?`text-fg`:`text-fg-muted hover:text-fg`,f===`marketplace`&&`after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent`),onClick:()=>m(`marketplace`),children:t.appsPage.tabMarketplace}),(0,U.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":f===`builtin`,className:u(`relative rounded-md px-3 py-2 text-sm font-medium transition-colors`,f===`builtin`?`text-fg`:`text-fg-muted hover:text-fg`,f===`builtin`&&`after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent`),onClick:()=>m(`builtin`),children:[t.appsPage.tabBuiltin,(0,U.jsxs)(`span`,{className:`ml-1 tabular-nums text-fg-muted`,children:[`(`,b.length,`)`]})]}),(0,U.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":f===`user`,className:u(`relative rounded-md px-3 py-2 text-sm font-medium transition-colors`,f===`user`?`text-fg`:`text-fg-muted hover:text-fg`,f===`user`&&`after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent`),onClick:()=>m(`user`),children:[t.appsPage.tabUser,(0,U.jsxs)(`span`,{className:`ml-1 tabular-nums text-fg-muted`,children:[`(`,S.length,`)`]})]})]}),D?(0,U.jsxs)(`div`,{className:`relative w-full min-w-0 sm:max-w-xs`,children:[(0,U.jsx)(x,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted`,"aria-hidden":!0}),(0,U.jsx)(`input`,{type:`search`,value:g,onChange:e=>_(e.target.value),placeholder:t.appsPage.searchPlaceholder,className:`w-full rounded-lg border border-edge bg-surface-base py-2 pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,autoComplete:`off`})]}):null]}),f===`marketplace`?(0,U.jsx)(G,{}):f===`builtin`&&b.length===0?(0,U.jsx)($,{message:t.appsPage.emptyBuiltin}):f===`user`&&S.length===0?(0,U.jsx)($,{message:t.appsPage.emptyUser}):E.length===0?(0,U.jsx)(`p`,{className:`rounded-xl border border-dashed border-edge-subtle bg-surface-hover/30 px-4 py-8 text-center text-sm text-fg-muted dark:bg-surface-hover/15`,children:t.appsPage.noSearchResults}):(0,U.jsx)(`div`,{className:`grid gap-4 sm:grid-cols-2 lg:grid-cols-3`,children:E.map(e=>(0,U.jsx)(ee,{extension:e,copy:t.appsPage,showSourceBadge:f===`user`,onOpen:()=>y(e)},e.id))})]}),v?(0,U.jsx)(te,{extension:v,copy:t.appsPage,onClose:()=>y(null)},v.id):null]})}function J(e){return e.activationEligible??e.active}function Y(e,t){return e.source===`bundled`?t.providerBundled:e.source===`global`?t.providerGlobal:e.source===`workspace`?t.providerWorkspace:t.providerOther}function X(e,t){return e.source===`global`?t.badgeSourceGlobal:e.source===`workspace`?t.badgeSourceWorkspace:t.badgeSourceOther}function Z(e,t){let n=J(e);return n&&e.active?t.runStateLive:n&&!e.active?t.runStatePendingOn:!n&&e.active?t.runStatePendingOff:t.runStateOff}function ee({extension:e,copy:t,showSourceBadge:n,onOpen:r}){let i=J(e),a=e.hasUi?t.cardTooltipHasUi:t.cardTooltipNoUi;return(0,U.jsx)(`button`,{type:`button`,onClick:r,className:u(`group flex w-full flex-col rounded-xl border border-edge bg-surface-base p-4 text-left shadow-sm transition-colors`,`hover:border-edge-subtle hover:bg-surface-hover/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,`dark:hover:bg-surface-hover/25`),children:(0,U.jsxs)(`div`,{className:`flex gap-3`,children:[(0,U.jsx)(`div`,{className:`flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent-soft text-base font-semibold text-accent-fg`,"aria-hidden":!0,children:(e.name||e.id).charAt(0).toUpperCase()}),(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,U.jsxs)(`div`,{className:`min-w-0`,children:[(0,U.jsx)(`h2`,{className:`truncate text-sm font-semibold text-fg`,children:e.name}),e.version?(0,U.jsxs)(`span`,{className:`text-[11px] text-fg-muted`,children:[`v`,e.version]}):null]}),i?(0,U.jsxs)(`span`,{className:`inline-flex shrink-0 items-center gap-1 rounded-full bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted`,children:[(0,U.jsx)(k,{className:`size-3`,strokeWidth:2.5,"aria-hidden":!0}),t.statusEnabled]}):(0,U.jsx)(`span`,{className:`flex size-8 shrink-0 items-center justify-center rounded-full border-2 border-accent text-accent`,"aria-hidden":!0,children:(0,U.jsx)(w,{className:`size-4`,strokeWidth:2.5})})]}),(0,U.jsx)(`p`,{className:`mt-2 line-clamp-2 text-xs leading-relaxed text-fg-muted`,children:e.description?.trim()||t.cardNoDescription}),(0,U.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[(0,U.jsx)(`span`,{title:a,className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:e.hasUi?t.badgeKindUi:t.badgeKindBackend}),e.source===`bundled`?(0,U.jsx)(`span`,{className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:t.badgeBundled}):n?(0,U.jsx)(`span`,{title:Y(e,t),className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:X(e,t)}):null]})]})]})})}function te({extension:e,copy:t,onClose:n}){let r=e.ui?.contributions?.pages??[],i=e.ui?.contributions?.settingsPanels??[],a=e.ui?.contributions?.chatWidgets??[],c=e.ui?.contributions?.sidebarPanels??[],p=r.find(e=>e.showInNav)??r[0],h=i[0],g=p?b(e.id,p):null,_=h?`/settings/ext/${e.id}/${h.id}`:e.hasConfigSchema?`/settings/ext/${e.id}`:null;return(0,U.jsx)(D,{defaultOpen:!0,onOpenChange:e=>!e&&n(),children:(0,U.jsxs)(o,{children:[(0,U.jsx)(O,{className:`xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim`}),(0,U.jsxs)(l,{className:`fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated`,onOpenAutoFocus:e=>e.preventDefault(),children:[(0,U.jsxs)(`div`,{className:`flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3`,children:[(0,U.jsx)(`button`,{type:`button`,onClick:n,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailBack,children:(0,U.jsx)(F,{className:`size-5`})}),(0,U.jsx)(f,{className:`min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg`,children:t.detailTitle}),(0,U.jsxs)(m,{className:`sr-only`,children:[e.name,` (`,e.id,`)`]}),(0,U.jsx)(`button`,{type:`button`,onClick:n,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailClose,children:(0,U.jsx)(d,{className:`size-5`})})]}),(0,U.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-5`,children:[(0,U.jsxs)(`div`,{className:`flex flex-wrap items-start gap-4`,children:[(0,U.jsx)(`div`,{className:`flex size-16 shrink-0 items-center justify-center rounded-2xl bg-accent-soft text-xl font-semibold text-accent-fg`,"aria-hidden":!0,children:(e.name||e.id).charAt(0).toUpperCase()}),(0,U.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,U.jsx)(`h3`,{className:`text-lg font-semibold text-fg`,children:e.name}),(0,U.jsxs)(`p`,{className:`mt-0.5 text-sm text-fg-muted`,children:[t.detailProviderPrefix,` `,Y(e,t)]}),e.version?(0,U.jsxs)(`p`,{className:`mt-1 text-xs text-fg-muted`,children:[`v`,e.version]}):null]})]}),(0,U.jsx)(`p`,{className:`mt-5 text-sm leading-relaxed text-fg`,children:e.description?.trim()||t.detailNoDescription}),e.hasUi?null:(0,U.jsx)(`p`,{className:`mt-3 text-xs text-fg-muted`,children:t.backendOnlyHint}),(0,U.jsx)(`p`,{className:`mt-2 text-xs text-fg-muted`,children:Z(e,t)}),e.source===`bundled`?(0,U.jsx)(`p`,{className:`mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20`,children:t.builtinConfigHint}):(0,U.jsx)(`p`,{className:`mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20`,children:t.cliManageHint}),e.hasUi&&(r.length>0||i.length>0||a.length>0)?(0,U.jsxs)(`section`,{className:`mt-8`,children:[(0,U.jsx)(`h4`,{className:`mb-3 text-sm font-semibold text-fg`,children:t.detailSectionFeatures}),(0,U.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,U.jsx)(Q,{template:t.badgePages,count:r.length,hidden:r.length===0}),(0,U.jsx)(Q,{template:t.badgeSettings,count:i.length,hidden:i.length===0}),(0,U.jsx)(Q,{template:t.badgeWidgets,count:a.length,hidden:a.length===0}),(0,U.jsx)(Q,{template:t.badgeSidebar,count:c.length,hidden:c.length===0})]})]}):null,M(e)&&(g||_)?(0,U.jsxs)(`div`,{className:`mt-6 flex flex-wrap gap-2 border-t border-edge-subtle pt-4`,children:[g?(0,U.jsxs)(s,{to:g,onClick:n,className:u(`inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`),children:[(0,U.jsx)(v,{className:`size-4 shrink-0 opacity-80`,"aria-hidden":!0}),t.open]}):null,_?(0,U.jsxs)(s,{to:_,onClick:n,className:u(`inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`),children:[(0,U.jsx)(j,{className:`size-4 shrink-0 opacity-80`,"aria-hidden":!0}),t.openSettings]}):null]}):null,(0,U.jsx)(`p`,{className:`mt-6 text-[11px] leading-relaxed text-fg-muted`,children:t.restartNote})]})]})]})})}function Q({template:e,count:t,hidden:n}){return n||t===0?null:(0,U.jsx)(`span`,{className:`inline-flex items-center rounded-md bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted`,children:e.replace(/\{\{count\}\}/g,String(t))})}function ne(){return(0,U.jsx)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel`,children:(0,U.jsxs)(`div`,{className:`mx-auto w-full max-w-app-main px-4 py-8`,children:[(0,U.jsx)(`div`,{className:`mb-6 h-8 w-40 max-w-full animate-pulse rounded-md bg-surface-hover`}),(0,U.jsx)(`div`,{className:`mb-2 h-4 w-full max-w-md animate-pulse rounded bg-surface-hover`}),(0,U.jsx)(`div`,{className:`mb-5 h-9 w-full max-w-lg animate-pulse rounded-full bg-surface-hover`}),(0,U.jsx)(`div`,{className:`mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3`,children:[0,1,2,3,4,5].map(e=>(0,U.jsx)(`div`,{className:`h-36 animate-pulse rounded-xl border border-edge bg-surface-base`},e))})]})})}function $({message:e}){return(0,U.jsx)(`div`,{className:`flex min-h-[min(40vh,16rem)] flex-col items-center justify-center rounded-xl border border-dashed border-edge-subtle bg-surface-hover/40 px-4 py-12 text-center dark:bg-surface-hover/20`,children:(0,U.jsx)(`p`,{className:`text-sm text-fg-muted`,children:e})})}export{q as AppsPage};
2
+ //# sourceMappingURL=apps-page-Bco3oZzd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apps-page-DOHsxEjt.js","names":[],"sources":["../../../../../web/src/features/apps/apps-page.constants.ts","../../../../../web/src/features/extensions/extension-marketplace-api.ts","../../../../../web/src/features/extensions/extension-marketplace.tsx","../../../../../web/src/pages/apps-page.tsx"],"sourcesContent":["export type AppsMainTab = 'marketplace' | 'builtin' | 'user';\n\nexport function parseAppsMainTab(raw: string | null): AppsMainTab {\n if (raw === 'builtin' || raw === 'user') return raw;\n return 'marketplace';\n}\n","import { apiFetch } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\n\nexport type ExtensionMarketplacePackageDetail = {\n id: string;\n name: string;\n type: string;\n description: string;\n readme: string | null;\n downloads: number;\n author: { username: string; avatarUrl: string | null };\n latestVersion: {\n version: string;\n changelog: string | null;\n publishedAt: string;\n };\n};\n\nasync function readErrorMessage(res: Response): Promise<string> {\n try {\n const j = (await res.json()) as { error?: string; message?: string };\n if (typeof j.error === 'string') return j.error;\n if (typeof j.message === 'string') return j.message;\n } catch {\n /* ignore */\n }\n return res.statusText || `HTTP ${res.status}`;\n}\n\nexport async function getExtensionMarketplacePackageDetail(\n packageName: string,\n): Promise<ExtensionMarketplacePackageDetail> {\n const enc = encodeURIComponent(packageName.trim());\n const res = await apiFetch(apiUrl(`/api/marketplace/packages/${enc}`), { cache: 'no-store' });\n if (!res.ok) {\n throw new Error(await readErrorMessage(res));\n }\n const data = (await res.json()) as {\n ok?: boolean;\n error?: string;\n payload?: ExtensionMarketplacePackageDetail;\n };\n if (!data.ok || !data.payload?.id) {\n throw new Error(data.error ?? 'Invalid response');\n }\n return data.payload;\n}\n\nexport async function installExtensionFromMarketplace(opts: {\n name: string;\n version?: string;\n overwrite?: boolean;\n}): Promise<{ extensionId: string; version: string; requiresGatewayRestart: boolean }> {\n const res = await apiFetch(apiUrl('/api/marketplace/install'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(opts),\n });\n if (!res.ok) {\n throw new Error(await readErrorMessage(res));\n }\n const data = (await res.json()) as {\n ok?: boolean;\n error?: string;\n payload?: { extensionId: string; version: string; requiresGatewayRestart: boolean };\n };\n if (!data.ok || !data.payload?.extensionId) {\n throw new Error(data.error ?? 'Invalid response');\n }\n return data.payload;\n}\n\nexport async function uninstallExtensionFromDisk(extensionId: string): Promise<{\n requiresGatewayRestart: boolean;\n}> {\n const res = await apiFetch(apiUrl('/api/marketplace/uninstall'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ extensionId }),\n });\n if (!res.ok) {\n throw new Error(await readErrorMessage(res));\n }\n const data = (await res.json()) as {\n ok?: boolean;\n error?: string;\n payload?: { requiresGatewayRestart: boolean };\n };\n if (!data.ok || !data.payload) {\n throw new Error(data.error ?? 'Invalid response');\n }\n return data.payload;\n}\n","import * as Dialog from '@radix-ui/react-dialog';\nimport { ArrowLeft, CheckCircle, Loader2, Package, Search, Trash2, X } from 'lucide-react';\nimport { useCallback, useEffect, useState } from 'react';\nimport useSWR, { useSWRConfig } from 'swr';\n\nimport { MarkdownView } from '@/components/markdown/markdown-view';\nimport {\n getExtensionMarketplacePackageDetail,\n installExtensionFromMarketplace,\n uninstallExtensionFromDisk,\n} from '@/features/extensions/extension-marketplace-api';\nimport { useExtensions } from '@/features/extensions/extension-provider';\nimport type { ExtensionApiRow } from '@/features/extensions/types';\nimport { messages, type MessageBundle } from '@/i18n/messages';\nimport { cn } from '@/lib/cn';\nimport { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\ntype RegistryEntry = {\n id: string;\n name: string;\n description?: string;\n npmPackage: string;\n version?: string;\n categories?: string[];\n tags?: string[];\n verified?: boolean;\n homepage?: string;\n author?: string;\n};\n\ntype MarketplaceResponse = { ok: boolean; extensions: RegistryEntry[] };\n\n/** Same catalog id on disk: bundled vs user/global/workspace. */\nfunction extensionInstallKind(\n extensions: ExtensionApiRow[],\n catalogId: string,\n): 'absent' | 'bundled' | 'user' {\n const row = extensions.find((x) => x.id === catalogId);\n if (!row) return 'absent';\n if (row.source === 'bundled') return 'bundled';\n return 'user';\n}\n\nexport function ExtensionMarketplacePanel({ className }: { className?: string }) {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const copy = m.appsPage;\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n const extensions = useExtensions();\n const { mutate } = useSWRConfig();\n const [q, setQ] = useState('');\n const [debounced, setDebounced] = useState('');\n const listKey = hasToken ? `marketplace-${debounced}` : null;\n const [detailPkg, setDetailPkg] = useState<string | null>(null);\n const [rowBusy, setRowBusy] = useState<string | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [restartHint, setRestartHint] = useState<string | null>(null);\n\n useEffect(() => {\n const t = window.setTimeout(() => setDebounced(q.trim()), 300);\n return () => window.clearTimeout(t);\n }, [q]);\n\n const { data, isLoading, error } = useSWR(\n listKey,\n async () => {\n const url =\n debounced.length > 0\n ? apiUrl(`/api/marketplace?q=${encodeURIComponent(debounced)}`)\n : apiUrl('/api/marketplace');\n return fetchJson<MarketplaceResponse>(url);\n },\n { revalidateOnFocus: false },\n );\n\n const refetchExtensions = useCallback(() => {\n void mutate('gateway-extensions-list');\n window.dispatchEvent(new CustomEvent('config-reload'));\n }, [mutate]);\n\n const runInstall = useCallback(\n async (packageName: string, overwrite: boolean) => {\n setActionError(null);\n setRestartHint(null);\n setRowBusy(packageName);\n try {\n const payload = await installExtensionFromMarketplace({ name: packageName, overwrite });\n refetchExtensions();\n if (payload.requiresGatewayRestart) {\n setRestartHint(copy.marketplaceRestartHint);\n }\n } catch (e) {\n setActionError(e instanceof Error ? e.message : copy.marketplaceInstallFailed);\n throw e;\n } finally {\n setRowBusy(null);\n }\n },\n [copy.marketplaceInstallFailed, copy.marketplaceRestartHint, refetchExtensions],\n );\n\n const runUninstall = useCallback(\n async (extensionId: string) => {\n setActionError(null);\n setRestartHint(null);\n setRowBusy(extensionId);\n try {\n const payload = await uninstallExtensionFromDisk(extensionId);\n refetchExtensions();\n if (payload.requiresGatewayRestart) {\n setRestartHint(copy.marketplaceRestartHint);\n }\n } catch (e) {\n setActionError(e instanceof Error ? e.message : copy.marketplaceUninstallFailed);\n throw e;\n } finally {\n setRowBusy(null);\n }\n },\n [copy.marketplaceRestartHint, copy.marketplaceUninstallFailed, refetchExtensions],\n );\n\n const extensionsList = data?.extensions ?? [];\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n <div className=\"relative\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted\"\n strokeWidth={1.75}\n aria-hidden\n />\n <input\n type=\"search\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder={copy.marketplaceSearchPlaceholder}\n className=\"ui-input h-10 w-full rounded-lg border border-edge bg-surface-base pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted\"\n />\n </div>\n\n {error ? (\n <p className=\"text-sm text-fg-muted\">\n {error instanceof Error ? error.message : copy.marketplaceLoadFailed}\n </p>\n ) : null}\n {actionError ? <p className=\"text-sm text-red-600 dark:text-red-400\">{actionError}</p> : null}\n {restartHint ? <p className=\"text-sm text-fg-muted\">{restartHint}</p> : null}\n\n {isLoading && !data ? (\n <p className=\"text-sm text-fg-muted\">…</p>\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {extensionsList.length === 0 ? (\n <li className=\"text-sm text-fg-muted\">{copy.marketplaceEmpty}</li>\n ) : (\n extensionsList.map((e) => {\n const kind = extensionInstallKind(extensions, e.id);\n const busy = rowBusy === e.id;\n return (\n <li key={e.id} className=\"list-none\">\n <div\n role=\"button\"\n tabIndex={0}\n aria-label={`${e.name}, ${copy.marketplaceDetailTitle}`}\n onClick={() => setDetailPkg(e.id)}\n onKeyDown={(ev) => {\n if (ev.key === 'Enter' || ev.key === ' ') {\n ev.preventDefault();\n setDetailPkg(e.id);\n }\n }}\n className={cn(\n 'flex w-full cursor-pointer flex-wrap items-start gap-3 rounded-xl border border-edge bg-surface-base p-4 text-left shadow-surface',\n 'transition-[transform,background-color,border-color,box-shadow] duration-150 ease-out',\n 'hover:border-edge-subtle hover:bg-surface-hover/40',\n 'active:scale-[0.992] active:bg-surface-hover/55',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-panel',\n 'dark:hover:bg-surface-hover/25 dark:active:bg-surface-hover/35',\n )}\n >\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"font-semibold text-fg\">{e.name}</h3>\n {e.verified ? (\n <CheckCircle\n className=\"size-4 shrink-0 text-emerald-600 dark:text-emerald-400\"\n strokeWidth={1.75}\n aria-label=\"Verified\"\n />\n ) : null}\n {e.version ? (\n <span className=\"text-xs text-fg-muted\">{e.version}</span>\n ) : null}\n </div>\n {e.description ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-fg-muted\">{e.description}</p>\n ) : null}\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n {(e.categories ?? []).map((c) => (\n <span\n key={c}\n className=\"rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-[11px] text-fg-muted\"\n >\n {c}\n </span>\n ))}\n </div>\n <p className=\"mt-2 flex items-center gap-1.5 text-xs text-fg-muted\">\n <Package className=\"size-3.5 shrink-0\" strokeWidth={1.75} aria-hidden />\n <code className=\"rounded bg-surface-panel px-1 py-0.5\">{e.npmPackage}</code>\n </p>\n </div>\n <div\n className=\"flex shrink-0 flex-col items-end gap-2 sm:min-w-[9rem]\"\n onClick={(ev) => ev.stopPropagation()}\n onKeyDown={(ev) => ev.stopPropagation()}\n >\n {kind === 'bundled' ? (\n <span className=\"rounded-md bg-surface-hover px-2 py-1 text-[11px] font-medium text-fg-muted\">\n {copy.marketplaceBuiltin}\n </span>\n ) : kind === 'user' ? (\n <>\n <span className=\"text-[11px] font-medium text-fg-muted\">\n {copy.marketplaceInstalled}\n </span>\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => {\n if (!window.confirm(copy.marketplaceUninstallConfirm)) return;\n void runUninstall(e.id).catch(() => {\n /* error surfaced via actionError */\n });\n }}\n className={cn(\n 'inline-flex items-center justify-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-xs font-medium text-fg',\n 'transition-colors active:scale-[0.98] active:bg-surface-hover/80',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n 'disabled:pointer-events-none disabled:opacity-50',\n )}\n >\n {busy ? (\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n ) : (\n <Trash2 className=\"size-3.5\" strokeWidth={2} aria-hidden />\n )}\n {copy.marketplaceUninstall}\n </button>\n </>\n ) : (\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => {\n void runInstall(e.id, false).catch(() => {\n /* surfaced */\n });\n }}\n className={cn(\n 'inline-flex w-full items-center justify-center rounded-lg bg-accent px-3 py-2 text-xs font-medium text-white',\n 'shadow-surface transition-[transform,background-color] active:scale-[0.98]',\n 'hover:bg-accent-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-base',\n 'disabled:pointer-events-none disabled:opacity-50',\n )}\n >\n {busy ? (\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n ) : null}\n {copy.marketplaceInstall}\n </button>\n )}\n </div>\n </div>\n </li>\n );\n })\n )}\n </ul>\n )}\n\n {detailPkg ? (\n <ExtensionMarketplaceDetailDialog\n packageName={detailPkg}\n copy={copy}\n extensions={extensions}\n onClose={() => setDetailPkg(null)}\n onInstall={runInstall}\n onUninstall={runUninstall}\n />\n ) : null}\n </div>\n );\n}\n\nfunction ExtensionMarketplaceDetailDialog({\n packageName,\n copy,\n extensions,\n onClose,\n onInstall,\n onUninstall,\n}: {\n packageName: string;\n copy: MessageBundle['appsPage'];\n extensions: ExtensionApiRow[];\n onClose: () => void;\n onInstall: (name: string, overwrite: boolean) => Promise<void>;\n onUninstall: (id: string) => Promise<void>;\n}) {\n const [busy, setBusy] = useState(false);\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n const key = hasToken ? `ext-mp-detail-${packageName}` : null;\n const { data, error, isLoading } = useSWR(\n key,\n async () => getExtensionMarketplacePackageDetail(packageName),\n { revalidateOnFocus: false },\n );\n\n const installKind = extensionInstallKind(extensions, packageName);\n const userInstalled = installKind === 'user';\n\n const readmeMd =\n data?.readme?.trim() ||\n (data?.description?.trim() ? `### ${data.name}\\n\\n${data.description}` : `*${copy.marketplaceNoReadme}*`);\n\n return (\n <Dialog.Root defaultOpen onOpenChange={(o) => !o && onClose()}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim\" />\n <Dialog.Content\n className=\"fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailBack}\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg\">\n {copy.marketplaceDetailTitle}\n </Dialog.Title>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailClose}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto px-5 py-5\">\n {isLoading && !data ? (\n <p className=\"text-sm text-fg-muted\">…</p>\n ) : error ? (\n <p className=\"text-sm text-fg-muted\">{copy.marketplaceDetailLoadFailed}</p>\n ) : data ? (\n <>\n <h3 className=\"text-lg font-semibold text-fg\">{data.name}</h3>\n <p className=\"mt-1 text-xs text-fg-muted\">\n <code className=\"rounded bg-surface-panel px-1 py-0.5\">{data.id}</code>\n </p>\n <dl className=\"mt-3 grid gap-2 text-xs text-fg-muted sm:grid-cols-2\">\n <div>\n <dt className=\"font-medium text-fg\">{copy.marketplaceAuthor}</dt>\n <dd>{data.author.username}</dd>\n </div>\n <div>\n <dt className=\"font-medium text-fg\">{copy.marketplaceVersion}</dt>\n <dd>{data.latestVersion.version}</dd>\n </div>\n <div>\n <dt className=\"font-medium text-fg\">{copy.marketplaceDownloads}</dt>\n <dd>{data.downloads}</dd>\n </div>\n </dl>\n {data.readme?.trim() ? (\n <h4 className=\"mb-2 mt-6 text-sm font-semibold text-fg\">\n {copy.marketplaceDetailReadmeHeading}\n </h4>\n ) : null}\n <div className=\"markdown-content min-w-0 break-words text-sm\">\n <MarkdownView content={readmeMd} />\n </div>\n </>\n ) : null}\n </div>\n\n {data ? (\n <div className=\"flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-edge-subtle px-5 py-4\">\n {installKind === 'bundled' ? (\n <p className=\"w-full text-sm leading-relaxed text-fg-muted\">{copy.marketplaceBuiltinManageHint}</p>\n ) : (\n <>\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => {\n if (userInstalled) {\n if (!window.confirm(copy.marketplaceReinstallConfirm)) return;\n }\n setBusy(true);\n void onInstall(packageName, userInstalled)\n .catch(() => {\n /* parent sets actionError */\n })\n .finally(() => setBusy(false));\n }}\n className={cn(\n 'inline-flex items-center justify-center gap-1.5 rounded-lg px-3 py-2 text-sm font-medium',\n 'bg-accent text-white shadow-surface hover:bg-accent-hover',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-panel',\n 'disabled:pointer-events-none disabled:opacity-50',\n )}\n >\n {busy ? <Loader2 className=\"size-4 animate-spin\" aria-hidden /> : null}\n {userInstalled ? copy.marketplaceReinstall : copy.marketplaceInstall}\n </button>\n {userInstalled ? (\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => {\n if (!window.confirm(copy.marketplaceUninstallConfirm)) return;\n setBusy(true);\n void onUninstall(packageName)\n .then(() => onClose())\n .catch(() => {\n /* parent */\n })\n .finally(() => setBusy(false));\n }}\n className={cn(\n 'inline-flex items-center justify-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n 'disabled:pointer-events-none disabled:opacity-50',\n )}\n >\n <Trash2 className=\"size-4 shrink-0\" aria-hidden />\n {copy.marketplaceUninstall}\n </button>\n ) : null}\n </>\n )}\n </div>\n ) : null}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n","import * as Dialog from '@radix-ui/react-dialog';\nimport { ArrowLeft, Check, ExternalLink, Plus, Search, Settings, X } from 'lucide-react';\nimport { useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { Link, useSearchParams } from 'react-router-dom';\n\nimport { parseAppsMainTab, type AppsMainTab } from '@/features/apps/apps-page.constants';\nimport {\n extensionExposesGatewayShellUi,\n useExtensions,\n useExtensionsLoading,\n} from '@/features/extensions/extension-provider';\nimport { ExtensionMarketplacePanel } from '@/features/extensions/extension-marketplace';\nimport { extensionPagePath } from '@/features/extensions/extension-paths';\nimport type { ExtensionApiRow, PageContribution } from '@/features/extensions/types';\nimport { messages } from '@/i18n/messages';\nimport type { MessageBundle } from '@/i18n/messages';\nimport { cn } from '@/lib/cn';\nimport { usePageHeaderStore } from '@/stores/page-header-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\ntype AppsPageCopy = MessageBundle['appsPage'];\n\nexport function AppsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n const extensions = useExtensions();\n const loading = useExtensionsLoading();\n const [searchParams, setSearchParams] = useSearchParams();\n\n const initialTab = parseAppsMainTab(searchParams.get('tab'));\n const initialQ = searchParams.get('q') ?? '';\n const [mainTab, setMainTab] = useState<AppsMainTab>(initialTab);\n const [search, setSearch] = useState(initialQ);\n const [detail, setDetail] = useState<ExtensionApiRow | null>(null);\n\n useEffect(() => {\n const nextTab = parseAppsMainTab(searchParams.get('tab'));\n const nextQ = searchParams.get('q') ?? '';\n setMainTab((prev) => (prev === nextTab ? prev : nextTab));\n setSearch((prev) => (prev === nextQ ? prev : nextQ));\n }, [searchParams]);\n\n useEffect(() => {\n setSearchParams(\n (prev) => {\n const params = new URLSearchParams(prev);\n const qq = search.trim();\n if (qq) params.set('q', qq);\n else params.delete('q');\n if (mainTab !== 'marketplace') params.set('tab', mainTab);\n else params.delete('tab');\n if (params.toString() === prev.toString()) return prev;\n return params;\n },\n { replace: true },\n );\n }, [mainTab, search, setSearchParams]);\n\n const bundledExtensions = useMemo(\n () => extensions.filter((e) => e.source === 'bundled'),\n [extensions],\n );\n const userExtensions = useMemo(\n () => extensions.filter((e) => e.source !== 'bundled'),\n [extensions],\n );\n\n const listForTab = mainTab === 'builtin' ? bundledExtensions : userExtensions;\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n let list = listForTab;\n if (q) {\n list = list.filter(\n (e) =>\n (e.name ?? '').toLowerCase().includes(q) ||\n e.id.toLowerCase().includes(q) ||\n (e.description ?? '').toLowerCase().includes(q),\n );\n }\n return [...list].sort((a, b) => {\n if (a.hasUi !== b.hasUi) return a.hasUi ? -1 : 1;\n return (a.name || a.id).localeCompare(b.name || b.id, language);\n });\n }, [listForTab, search, language]);\n\n /** Keep dialog + cards in sync after SWR refetch (detail was a stale row reference). */\n useEffect(() => {\n setDetail((prev) => {\n if (!prev) return prev;\n const next = extensions.find((e) => e.id === prev.id);\n if (!next) return null;\n const eligPrev = activationEligibleFor(prev);\n const eligNext = activationEligibleFor(next);\n if (eligPrev === eligNext && prev.active === next.active) return prev;\n return next;\n });\n }, [extensions]);\n\n useLayoutEffect(() => {\n setPageHeader({\n startExtra: null,\n main: (\n <div className=\"w-full min-w-0 px-3 sm:px-5 xl:px-6\">\n <h1 className=\"min-w-0 truncate text-base font-semibold tracking-tight text-fg\">{m.appsPage.title}</h1>\n </div>\n ),\n end: null,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, m.appsPage.title, setPageHeader]);\n\n if (loading && mainTab !== 'marketplace') {\n return <AppsPageSkeleton />;\n }\n\n const showSearch = mainTab !== 'marketplace' && listForTab.length > 0;\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto w-full max-w-app-main px-4 py-8\">\n <header className=\"mb-6\">\n <h1 className=\"text-xl font-semibold text-fg\">{m.appsPage.title}</h1>\n <p className=\"mt-1 text-sm text-fg-muted\">{m.appsPage.subtitle}</p>\n </header>\n\n <div className=\"mb-5 flex flex-col gap-3 border-b border-edge-subtle pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-edge-subtle\">\n <div\n className=\"flex flex-wrap gap-x-1 gap-y-1\"\n role=\"tablist\"\n aria-label={m.appsPage.appsNavAria}\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'marketplace'}\n className={cn(\n 'relative max-w-full rounded-md px-3 py-2 text-left text-sm font-medium transition-colors sm:text-center',\n mainTab === 'marketplace' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'marketplace' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('marketplace')}\n >\n {m.appsPage.tabMarketplace}\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'builtin'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'builtin' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'builtin' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('builtin')}\n >\n {m.appsPage.tabBuiltin}\n <span className=\"ml-1 tabular-nums text-fg-muted\">({bundledExtensions.length})</span>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'user'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'user' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'user' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('user')}\n >\n {m.appsPage.tabUser}\n <span className=\"ml-1 tabular-nums text-fg-muted\">({userExtensions.length})</span>\n </button>\n </div>\n {showSearch ? (\n <div className=\"relative w-full min-w-0 sm:max-w-xs\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted\"\n aria-hidden\n />\n <input\n type=\"search\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder={m.appsPage.searchPlaceholder}\n className=\"w-full rounded-lg border border-edge bg-surface-base py-2 pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n autoComplete=\"off\"\n />\n </div>\n ) : null}\n </div>\n\n {mainTab === 'marketplace' ? (\n <ExtensionMarketplacePanel />\n ) : mainTab === 'builtin' && bundledExtensions.length === 0 ? (\n <EmptyAppsState message={m.appsPage.emptyBuiltin} />\n ) : mainTab === 'user' && userExtensions.length === 0 ? (\n <EmptyAppsState message={m.appsPage.emptyUser} />\n ) : filtered.length === 0 ? (\n <p className=\"rounded-xl border border-dashed border-edge-subtle bg-surface-hover/30 px-4 py-8 text-center text-sm text-fg-muted dark:bg-surface-hover/15\">\n {m.appsPage.noSearchResults}\n </p>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((ext) => (\n <ExtensionAppCard\n key={ext.id}\n extension={ext}\n copy={m.appsPage}\n showSourceBadge={mainTab === 'user'}\n onOpen={() => setDetail(ext)}\n />\n ))}\n </div>\n )}\n </div>\n\n {detail ? (\n <ExtensionDetailDialog key={detail.id} extension={detail} copy={m.appsPage} onClose={() => setDetail(null)} />\n ) : null}\n </div>\n );\n}\n\nfunction activationEligibleFor(ext: ExtensionApiRow): boolean {\n return ext.activationEligible ?? ext.active;\n}\n\nfunction providerLabel(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n if (ext.source === 'bundled') return copy.providerBundled;\n if (ext.source === 'global') return copy.providerGlobal;\n if (ext.source === 'workspace') return copy.providerWorkspace;\n return copy.providerOther;\n}\n\nfunction installSourceBadgeLabel(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n if (ext.source === 'global') return copy.badgeSourceGlobal;\n if (ext.source === 'workspace') return copy.badgeSourceWorkspace;\n return copy.badgeSourceOther;\n}\n\nfunction bundledRunCaption(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n const eligible = activationEligibleFor(ext);\n if (eligible && ext.active) return copy.runStateLive;\n if (eligible && !ext.active) return copy.runStatePendingOn;\n if (!eligible && ext.active) return copy.runStatePendingOff;\n return copy.runStateOff;\n}\n\nfunction ExtensionAppCard({\n extension: ext,\n copy,\n showSourceBadge,\n onOpen,\n}: {\n extension: ExtensionApiRow;\n copy: AppsPageCopy;\n /** When true, show a short global/workspace/other pill (user-installed tab). */\n showSourceBadge: boolean;\n onOpen: () => void;\n}) {\n const eligible = activationEligibleFor(ext);\n const uiTitle = ext.hasUi ? copy.cardTooltipHasUi : copy.cardTooltipNoUi;\n\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className={cn(\n 'group flex w-full flex-col rounded-xl border border-edge bg-surface-base p-4 text-left shadow-sm transition-colors',\n 'hover:border-edge-subtle hover:bg-surface-hover/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n 'dark:hover:bg-surface-hover/25',\n )}\n >\n <div className=\"flex gap-3\">\n <div\n className=\"flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent-soft text-base font-semibold text-accent-fg\"\n aria-hidden\n >\n {(ext.name || ext.id).charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h2 className=\"truncate text-sm font-semibold text-fg\">{ext.name}</h2>\n {ext.version ? (\n <span className=\"text-[11px] text-fg-muted\">v{ext.version}</span>\n ) : null}\n </div>\n {eligible ? (\n <span className=\"inline-flex shrink-0 items-center gap-1 rounded-full bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted\">\n <Check className=\"size-3\" strokeWidth={2.5} aria-hidden />\n {copy.statusEnabled}\n </span>\n ) : (\n <span\n className=\"flex size-8 shrink-0 items-center justify-center rounded-full border-2 border-accent text-accent\"\n aria-hidden\n >\n <Plus className=\"size-4\" strokeWidth={2.5} />\n </span>\n )}\n </div>\n <p className=\"mt-2 line-clamp-2 text-xs leading-relaxed text-fg-muted\">\n {ext.description?.trim() || copy.cardNoDescription}\n </p>\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n <span\n title={uiTitle}\n className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\"\n >\n {ext.hasUi ? copy.badgeKindUi : copy.badgeKindBackend}\n </span>\n {ext.source === 'bundled' ? (\n <span className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\">\n {copy.badgeBundled}\n </span>\n ) : showSourceBadge ? (\n <span\n title={providerLabel(ext, copy)}\n className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\"\n >\n {installSourceBadgeLabel(ext, copy)}\n </span>\n ) : null}\n </div>\n </div>\n </div>\n </button>\n );\n}\n\nfunction ExtensionDetailDialog({\n extension: ext,\n copy,\n onClose,\n}: {\n extension: ExtensionApiRow;\n copy: AppsPageCopy;\n onClose: () => void;\n}) {\n const pages = ext.ui?.contributions?.pages ?? [];\n const settingsPanels = ext.ui?.contributions?.settingsPanels ?? [];\n const chatWidgets = ext.ui?.contributions?.chatWidgets ?? [];\n const sidebarPanels = ext.ui?.contributions?.sidebarPanels ?? [];\n const primaryPage: PageContribution | undefined = pages.find((p) => p.showInNav) ?? pages[0];\n const primarySettingsPanel = settingsPanels[0];\n const openPath = primaryPage ? extensionPagePath(ext.id, primaryPage) : null;\n const settingsPath = primarySettingsPanel\n ? `/settings/ext/${ext.id}/${primarySettingsPanel.id}`\n : ext.hasConfigSchema\n ? `/settings/ext/${ext.id}`\n : null;\n\n return (\n <Dialog.Root defaultOpen onOpenChange={(o) => !o && onClose()}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim\" />\n <Dialog.Content\n className=\"fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailBack}\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg\">\n {copy.detailTitle}\n </Dialog.Title>\n <Dialog.Description className=\"sr-only\">\n {ext.name} ({ext.id})\n </Dialog.Description>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailClose}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto px-5 py-5\">\n <div className=\"flex flex-wrap items-start gap-4\">\n <div\n className=\"flex size-16 shrink-0 items-center justify-center rounded-2xl bg-accent-soft text-xl font-semibold text-accent-fg\"\n aria-hidden\n >\n {(ext.name || ext.id).charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-lg font-semibold text-fg\">{ext.name}</h3>\n <p className=\"mt-0.5 text-sm text-fg-muted\">\n {copy.detailProviderPrefix} {providerLabel(ext, copy)}\n </p>\n {ext.version ? (\n <p className=\"mt-1 text-xs text-fg-muted\">v{ext.version}</p>\n ) : null}\n </div>\n </div>\n\n <p className=\"mt-5 text-sm leading-relaxed text-fg\">\n {ext.description?.trim() || copy.detailNoDescription}\n </p>\n\n {!ext.hasUi ? (\n <p className=\"mt-3 text-xs text-fg-muted\">{copy.backendOnlyHint}</p>\n ) : null}\n\n <p className=\"mt-2 text-xs text-fg-muted\">{bundledRunCaption(ext, copy)}</p>\n\n {ext.source === 'bundled' ? (\n <p className=\"mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20\">\n {copy.builtinConfigHint}\n </p>\n ) : (\n <p className=\"mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20\">\n {copy.cliManageHint}\n </p>\n )}\n\n {ext.hasUi && (pages.length > 0 || settingsPanels.length > 0 || chatWidgets.length > 0) ? (\n <section className=\"mt-8\">\n <h4 className=\"mb-3 text-sm font-semibold text-fg\">{copy.detailSectionFeatures}</h4>\n <div className=\"flex flex-wrap gap-1.5\">\n <ContributionBadge\n template={copy.badgePages}\n count={pages.length}\n hidden={pages.length === 0}\n />\n <ContributionBadge\n template={copy.badgeSettings}\n count={settingsPanels.length}\n hidden={settingsPanels.length === 0}\n />\n <ContributionBadge\n template={copy.badgeWidgets}\n count={chatWidgets.length}\n hidden={chatWidgets.length === 0}\n />\n <ContributionBadge\n template={copy.badgeSidebar}\n count={sidebarPanels.length}\n hidden={sidebarPanels.length === 0}\n />\n </div>\n </section>\n ) : null}\n\n {extensionExposesGatewayShellUi(ext) && (openPath || settingsPath) ? (\n <div className=\"mt-6 flex flex-wrap gap-2 border-t border-edge-subtle pt-4\">\n {openPath ? (\n <Link\n to={openPath}\n onClick={onClose}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n )}\n >\n <ExternalLink className=\"size-4 shrink-0 opacity-80\" aria-hidden />\n {copy.open}\n </Link>\n ) : null}\n {settingsPath ? (\n <Link\n to={settingsPath}\n onClick={onClose}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n )}\n >\n <Settings className=\"size-4 shrink-0 opacity-80\" aria-hidden />\n {copy.openSettings}\n </Link>\n ) : null}\n </div>\n ) : null}\n\n <p className=\"mt-6 text-[11px] leading-relaxed text-fg-muted\">{copy.restartNote}</p>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n\nfunction ContributionBadge({\n template,\n count,\n hidden,\n}: {\n template: string;\n count: number;\n hidden: boolean;\n}) {\n if (hidden || count === 0) return null;\n return (\n <span className=\"inline-flex items-center rounded-md bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted\">\n {template.replace(/\\{\\{count\\}\\}/g, String(count))}\n </span>\n );\n}\n\nfunction AppsPageSkeleton() {\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto w-full max-w-app-main px-4 py-8\">\n <div className=\"mb-6 h-8 w-40 max-w-full animate-pulse rounded-md bg-surface-hover\" />\n <div className=\"mb-2 h-4 w-full max-w-md animate-pulse rounded bg-surface-hover\" />\n <div className=\"mb-5 h-9 w-full max-w-lg animate-pulse rounded-full bg-surface-hover\" />\n <div className=\"mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {[0, 1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-36 animate-pulse rounded-xl border border-edge bg-surface-base\" />\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nfunction EmptyAppsState({ message }: { message: string }) {\n return (\n <div className=\"flex min-h-[min(40vh,16rem)] flex-col items-center justify-center rounded-xl border border-dashed border-edge-subtle bg-surface-hover/40 px-4 py-12 text-center dark:bg-surface-hover/20\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"apps-page-Bco3oZzd.js","names":[],"sources":["../../../../../web/src/features/apps/apps-page.constants.ts","../../../../../web/src/features/extensions/extension-marketplace-api.ts","../../../../../web/src/features/extensions/extension-marketplace.tsx","../../../../../web/src/pages/apps-page.tsx"],"sourcesContent":["export type AppsMainTab = 'marketplace' | 'builtin' | 'user';\n\nexport function parseAppsMainTab(raw: string | null): AppsMainTab {\n if (raw === 'builtin' || raw === 'user') return raw;\n return 'marketplace';\n}\n","import { apiFetch } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\n\nexport type ExtensionMarketplacePackageDetail = {\n id: string;\n name: string;\n type: string;\n description: string;\n readme: string | null;\n downloads: number;\n author: { username: string; avatarUrl: string | null };\n latestVersion: {\n version: string;\n changelog: string | null;\n publishedAt: string;\n };\n};\n\nasync function readErrorMessage(res: Response): Promise<string> {\n try {\n const j = (await res.json()) as { error?: string; message?: string };\n if (typeof j.error === 'string') return j.error;\n if (typeof j.message === 'string') return j.message;\n } catch {\n /* ignore */\n }\n return res.statusText || `HTTP ${res.status}`;\n}\n\nexport async function getExtensionMarketplacePackageDetail(\n packageName: string,\n): Promise<ExtensionMarketplacePackageDetail> {\n const enc = encodeURIComponent(packageName.trim());\n const res = await apiFetch(apiUrl(`/api/marketplace/packages/${enc}`), { cache: 'no-store' });\n if (!res.ok) {\n throw new Error(await readErrorMessage(res));\n }\n const data = (await res.json()) as {\n ok?: boolean;\n error?: string;\n payload?: ExtensionMarketplacePackageDetail;\n };\n if (!data.ok || !data.payload?.id) {\n throw new Error(data.error ?? 'Invalid response');\n }\n return data.payload;\n}\n\nexport async function installExtensionFromMarketplace(opts: {\n name: string;\n version?: string;\n overwrite?: boolean;\n}): Promise<{ extensionId: string; version: string; requiresGatewayRestart: boolean }> {\n const res = await apiFetch(apiUrl('/api/marketplace/install'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(opts),\n });\n if (!res.ok) {\n throw new Error(await readErrorMessage(res));\n }\n const data = (await res.json()) as {\n ok?: boolean;\n error?: string;\n payload?: { extensionId: string; version: string; requiresGatewayRestart: boolean };\n };\n if (!data.ok || !data.payload?.extensionId) {\n throw new Error(data.error ?? 'Invalid response');\n }\n return data.payload;\n}\n\nexport async function uninstallExtensionFromDisk(extensionId: string): Promise<{\n requiresGatewayRestart: boolean;\n}> {\n const res = await apiFetch(apiUrl('/api/marketplace/uninstall'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ extensionId }),\n });\n if (!res.ok) {\n throw new Error(await readErrorMessage(res));\n }\n const data = (await res.json()) as {\n ok?: boolean;\n error?: string;\n payload?: { requiresGatewayRestart: boolean };\n };\n if (!data.ok || !data.payload) {\n throw new Error(data.error ?? 'Invalid response');\n }\n return data.payload;\n}\n","import * as Dialog from '@radix-ui/react-dialog';\nimport { ArrowLeft, CheckCircle, Loader2, Package, Search, Trash2, X } from 'lucide-react';\nimport { useCallback, useEffect, useState } from 'react';\nimport useSWR, { useSWRConfig } from 'swr';\n\nimport { MarkdownView } from '@/components/markdown/markdown-view';\nimport {\n getExtensionMarketplacePackageDetail,\n installExtensionFromMarketplace,\n uninstallExtensionFromDisk,\n} from '@/features/extensions/extension-marketplace-api';\nimport { useExtensions } from '@/features/extensions/extension-provider';\nimport type { ExtensionApiRow } from '@/features/extensions/types';\nimport { messages, type MessageBundle } from '@/i18n/messages';\nimport { cn } from '@/lib/cn';\nimport { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\ntype RegistryEntry = {\n id: string;\n name: string;\n description?: string;\n npmPackage: string;\n version?: string;\n categories?: string[];\n tags?: string[];\n verified?: boolean;\n homepage?: string;\n author?: string;\n};\n\ntype MarketplaceResponse = { ok: boolean; extensions: RegistryEntry[] };\n\n/** Same catalog id on disk: bundled vs user/global/workspace. */\nfunction extensionInstallKind(\n extensions: ExtensionApiRow[],\n catalogId: string,\n): 'absent' | 'bundled' | 'user' {\n const row = extensions.find((x) => x.id === catalogId);\n if (!row) return 'absent';\n if (row.source === 'bundled') return 'bundled';\n return 'user';\n}\n\nexport function ExtensionMarketplacePanel({ className }: { className?: string }) {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const copy = m.appsPage;\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n const extensions = useExtensions();\n const { mutate } = useSWRConfig();\n const [q, setQ] = useState('');\n const [debounced, setDebounced] = useState('');\n const listKey = hasToken ? `marketplace-${debounced}` : null;\n const [detailPkg, setDetailPkg] = useState<string | null>(null);\n const [rowBusy, setRowBusy] = useState<string | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [restartHint, setRestartHint] = useState<string | null>(null);\n\n useEffect(() => {\n const t = window.setTimeout(() => setDebounced(q.trim()), 300);\n return () => window.clearTimeout(t);\n }, [q]);\n\n const { data, isLoading, error } = useSWR(\n listKey,\n async () => {\n const url =\n debounced.length > 0\n ? apiUrl(`/api/marketplace?q=${encodeURIComponent(debounced)}`)\n : apiUrl('/api/marketplace');\n return fetchJson<MarketplaceResponse>(url);\n },\n { revalidateOnFocus: false },\n );\n\n const refetchExtensions = useCallback(() => {\n void mutate('gateway-extensions-list');\n window.dispatchEvent(new CustomEvent('config-reload'));\n }, [mutate]);\n\n const runInstall = useCallback(\n async (packageName: string, overwrite: boolean) => {\n setActionError(null);\n setRestartHint(null);\n setRowBusy(packageName);\n try {\n const payload = await installExtensionFromMarketplace({ name: packageName, overwrite });\n refetchExtensions();\n if (payload.requiresGatewayRestart) {\n setRestartHint(copy.marketplaceRestartHint);\n }\n } catch (e) {\n setActionError(e instanceof Error ? e.message : copy.marketplaceInstallFailed);\n throw e;\n } finally {\n setRowBusy(null);\n }\n },\n [copy.marketplaceInstallFailed, copy.marketplaceRestartHint, refetchExtensions],\n );\n\n const runUninstall = useCallback(\n async (extensionId: string) => {\n setActionError(null);\n setRestartHint(null);\n setRowBusy(extensionId);\n try {\n const payload = await uninstallExtensionFromDisk(extensionId);\n refetchExtensions();\n if (payload.requiresGatewayRestart) {\n setRestartHint(copy.marketplaceRestartHint);\n }\n } catch (e) {\n setActionError(e instanceof Error ? e.message : copy.marketplaceUninstallFailed);\n throw e;\n } finally {\n setRowBusy(null);\n }\n },\n [copy.marketplaceRestartHint, copy.marketplaceUninstallFailed, refetchExtensions],\n );\n\n const extensionsList = data?.extensions ?? [];\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n <div className=\"relative\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted\"\n strokeWidth={1.75}\n aria-hidden\n />\n <input\n type=\"search\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder={copy.marketplaceSearchPlaceholder}\n className=\"ui-input h-10 w-full rounded-lg border border-edge bg-surface-base pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted\"\n />\n </div>\n\n {error ? (\n <p className=\"text-sm text-fg-muted\">\n {error instanceof Error ? error.message : copy.marketplaceLoadFailed}\n </p>\n ) : null}\n {actionError ? <p className=\"text-sm text-red-600 dark:text-red-400\">{actionError}</p> : null}\n {restartHint ? <p className=\"text-sm text-fg-muted\">{restartHint}</p> : null}\n\n {isLoading && !data ? (\n <p className=\"text-sm text-fg-muted\">…</p>\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {extensionsList.length === 0 ? (\n <li className=\"text-sm text-fg-muted\">{copy.marketplaceEmpty}</li>\n ) : (\n extensionsList.map((e) => {\n const kind = extensionInstallKind(extensions, e.id);\n const busy = rowBusy === e.id;\n return (\n <li key={e.id} className=\"list-none\">\n <div\n role=\"button\"\n tabIndex={0}\n aria-label={`${e.name}, ${copy.marketplaceDetailTitle}`}\n onClick={() => setDetailPkg(e.id)}\n onKeyDown={(ev) => {\n if (ev.key === 'Enter' || ev.key === ' ') {\n ev.preventDefault();\n setDetailPkg(e.id);\n }\n }}\n className={cn(\n 'flex w-full cursor-pointer flex-wrap items-start gap-3 rounded-xl border border-edge bg-surface-base p-4 text-left shadow-surface',\n 'transition-[transform,background-color,border-color,box-shadow] duration-150 ease-out',\n 'hover:border-edge-subtle hover:bg-surface-hover/40',\n 'active:scale-[0.992] active:bg-surface-hover/55',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-panel',\n 'dark:hover:bg-surface-hover/25 dark:active:bg-surface-hover/35',\n )}\n >\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"font-semibold text-fg\">{e.name}</h3>\n {e.verified ? (\n <CheckCircle\n className=\"size-4 shrink-0 text-emerald-600 dark:text-emerald-400\"\n strokeWidth={1.75}\n aria-label=\"Verified\"\n />\n ) : null}\n {e.version ? (\n <span className=\"text-xs text-fg-muted\">{e.version}</span>\n ) : null}\n </div>\n {e.description ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-fg-muted\">{e.description}</p>\n ) : null}\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n {(e.categories ?? []).map((c) => (\n <span\n key={c}\n className=\"rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-[11px] text-fg-muted\"\n >\n {c}\n </span>\n ))}\n </div>\n <p className=\"mt-2 flex items-center gap-1.5 text-xs text-fg-muted\">\n <Package className=\"size-3.5 shrink-0\" strokeWidth={1.75} aria-hidden />\n <code className=\"rounded bg-surface-panel px-1 py-0.5\">{e.npmPackage}</code>\n </p>\n </div>\n <div\n className=\"flex shrink-0 flex-col items-end gap-2 sm:min-w-[9rem]\"\n onClick={(ev) => ev.stopPropagation()}\n onKeyDown={(ev) => ev.stopPropagation()}\n >\n {kind === 'bundled' ? (\n <span className=\"rounded-md bg-surface-hover px-2 py-1 text-[11px] font-medium text-fg-muted\">\n {copy.marketplaceBuiltin}\n </span>\n ) : kind === 'user' ? (\n <>\n <span className=\"text-[11px] font-medium text-fg-muted\">\n {copy.marketplaceInstalled}\n </span>\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => {\n if (!window.confirm(copy.marketplaceUninstallConfirm)) return;\n void runUninstall(e.id).catch(() => {\n /* error surfaced via actionError */\n });\n }}\n className={cn(\n 'inline-flex items-center justify-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-xs font-medium text-fg',\n 'transition-colors active:scale-[0.98] active:bg-surface-hover/80',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n 'disabled:pointer-events-none disabled:opacity-50',\n )}\n >\n {busy ? (\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n ) : (\n <Trash2 className=\"size-3.5\" strokeWidth={2} aria-hidden />\n )}\n {copy.marketplaceUninstall}\n </button>\n </>\n ) : (\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => {\n void runInstall(e.id, false).catch(() => {\n /* surfaced */\n });\n }}\n className={cn(\n 'inline-flex w-full items-center justify-center rounded-lg bg-accent px-3 py-2 text-xs font-medium text-white',\n 'shadow-surface transition-[transform,background-color] active:scale-[0.98]',\n 'hover:bg-accent-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-base',\n 'disabled:pointer-events-none disabled:opacity-50',\n )}\n >\n {busy ? (\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n ) : null}\n {copy.marketplaceInstall}\n </button>\n )}\n </div>\n </div>\n </li>\n );\n })\n )}\n </ul>\n )}\n\n {detailPkg ? (\n <ExtensionMarketplaceDetailDialog\n packageName={detailPkg}\n copy={copy}\n extensions={extensions}\n onClose={() => setDetailPkg(null)}\n onInstall={runInstall}\n onUninstall={runUninstall}\n />\n ) : null}\n </div>\n );\n}\n\nfunction ExtensionMarketplaceDetailDialog({\n packageName,\n copy,\n extensions,\n onClose,\n onInstall,\n onUninstall,\n}: {\n packageName: string;\n copy: MessageBundle['appsPage'];\n extensions: ExtensionApiRow[];\n onClose: () => void;\n onInstall: (name: string, overwrite: boolean) => Promise<void>;\n onUninstall: (id: string) => Promise<void>;\n}) {\n const [busy, setBusy] = useState(false);\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n const key = hasToken ? `ext-mp-detail-${packageName}` : null;\n const { data, error, isLoading } = useSWR(\n key,\n async () => getExtensionMarketplacePackageDetail(packageName),\n { revalidateOnFocus: false },\n );\n\n const installKind = extensionInstallKind(extensions, packageName);\n const userInstalled = installKind === 'user';\n\n const readmeMd =\n data?.readme?.trim() ||\n (data?.description?.trim() ? `### ${data.name}\\n\\n${data.description}` : `*${copy.marketplaceNoReadme}*`);\n\n return (\n <Dialog.Root defaultOpen onOpenChange={(o) => !o && onClose()}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim\" />\n <Dialog.Content\n className=\"fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailBack}\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg\">\n {copy.marketplaceDetailTitle}\n </Dialog.Title>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailClose}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto px-5 py-5\">\n {isLoading && !data ? (\n <p className=\"text-sm text-fg-muted\">…</p>\n ) : error ? (\n <p className=\"text-sm text-fg-muted\">{copy.marketplaceDetailLoadFailed}</p>\n ) : data ? (\n <>\n <h3 className=\"text-lg font-semibold text-fg\">{data.name}</h3>\n <p className=\"mt-1 text-xs text-fg-muted\">\n <code className=\"rounded bg-surface-panel px-1 py-0.5\">{data.id}</code>\n </p>\n <dl className=\"mt-3 grid gap-2 text-xs text-fg-muted sm:grid-cols-2\">\n <div>\n <dt className=\"font-medium text-fg\">{copy.marketplaceAuthor}</dt>\n <dd>{data.author.username}</dd>\n </div>\n <div>\n <dt className=\"font-medium text-fg\">{copy.marketplaceVersion}</dt>\n <dd>{data.latestVersion.version}</dd>\n </div>\n <div>\n <dt className=\"font-medium text-fg\">{copy.marketplaceDownloads}</dt>\n <dd>{data.downloads}</dd>\n </div>\n </dl>\n {data.readme?.trim() ? (\n <h4 className=\"mb-2 mt-6 text-sm font-semibold text-fg\">\n {copy.marketplaceDetailReadmeHeading}\n </h4>\n ) : null}\n <div className=\"markdown-content min-w-0 break-words text-sm\">\n <MarkdownView content={readmeMd} />\n </div>\n </>\n ) : null}\n </div>\n\n {data ? (\n <div className=\"flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-edge-subtle px-5 py-4\">\n {installKind === 'bundled' ? (\n <p className=\"w-full text-sm leading-relaxed text-fg-muted\">{copy.marketplaceBuiltinManageHint}</p>\n ) : (\n <>\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => {\n if (userInstalled) {\n if (!window.confirm(copy.marketplaceReinstallConfirm)) return;\n }\n setBusy(true);\n void onInstall(packageName, userInstalled)\n .catch(() => {\n /* parent sets actionError */\n })\n .finally(() => setBusy(false));\n }}\n className={cn(\n 'inline-flex items-center justify-center gap-1.5 rounded-lg px-3 py-2 text-sm font-medium',\n 'bg-accent text-white shadow-surface hover:bg-accent-hover',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-panel',\n 'disabled:pointer-events-none disabled:opacity-50',\n )}\n >\n {busy ? <Loader2 className=\"size-4 animate-spin\" aria-hidden /> : null}\n {userInstalled ? copy.marketplaceReinstall : copy.marketplaceInstall}\n </button>\n {userInstalled ? (\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => {\n if (!window.confirm(copy.marketplaceUninstallConfirm)) return;\n setBusy(true);\n void onUninstall(packageName)\n .then(() => onClose())\n .catch(() => {\n /* parent */\n })\n .finally(() => setBusy(false));\n }}\n className={cn(\n 'inline-flex items-center justify-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n 'disabled:pointer-events-none disabled:opacity-50',\n )}\n >\n <Trash2 className=\"size-4 shrink-0\" aria-hidden />\n {copy.marketplaceUninstall}\n </button>\n ) : null}\n </>\n )}\n </div>\n ) : null}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n","import * as Dialog from '@radix-ui/react-dialog';\nimport { ArrowLeft, Check, ExternalLink, Plus, Search, Settings, X } from 'lucide-react';\nimport { useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { Link, useSearchParams } from 'react-router-dom';\n\nimport { parseAppsMainTab, type AppsMainTab } from '@/features/apps/apps-page.constants';\nimport {\n extensionExposesGatewayShellUi,\n useExtensions,\n useExtensionsLoading,\n} from '@/features/extensions/extension-provider';\nimport { ExtensionMarketplacePanel } from '@/features/extensions/extension-marketplace';\nimport { extensionPagePath } from '@/features/extensions/extension-paths';\nimport type { ExtensionApiRow, PageContribution } from '@/features/extensions/types';\nimport { messages } from '@/i18n/messages';\nimport type { MessageBundle } from '@/i18n/messages';\nimport { cn } from '@/lib/cn';\nimport { usePageHeaderStore } from '@/stores/page-header-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\ntype AppsPageCopy = MessageBundle['appsPage'];\n\nexport function AppsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n const extensions = useExtensions();\n const loading = useExtensionsLoading();\n const [searchParams, setSearchParams] = useSearchParams();\n\n const initialTab = parseAppsMainTab(searchParams.get('tab'));\n const initialQ = searchParams.get('q') ?? '';\n const [mainTab, setMainTab] = useState<AppsMainTab>(initialTab);\n const [search, setSearch] = useState(initialQ);\n const [detail, setDetail] = useState<ExtensionApiRow | null>(null);\n\n useEffect(() => {\n const nextTab = parseAppsMainTab(searchParams.get('tab'));\n const nextQ = searchParams.get('q') ?? '';\n setMainTab((prev) => (prev === nextTab ? prev : nextTab));\n setSearch((prev) => (prev === nextQ ? prev : nextQ));\n }, [searchParams]);\n\n useEffect(() => {\n setSearchParams(\n (prev) => {\n const params = new URLSearchParams(prev);\n const qq = search.trim();\n if (qq) params.set('q', qq);\n else params.delete('q');\n if (mainTab !== 'marketplace') params.set('tab', mainTab);\n else params.delete('tab');\n if (params.toString() === prev.toString()) return prev;\n return params;\n },\n { replace: true },\n );\n }, [mainTab, search, setSearchParams]);\n\n const bundledExtensions = useMemo(\n () => extensions.filter((e) => e.source === 'bundled'),\n [extensions],\n );\n const userExtensions = useMemo(\n () => extensions.filter((e) => e.source !== 'bundled'),\n [extensions],\n );\n\n const listForTab = mainTab === 'builtin' ? bundledExtensions : userExtensions;\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n let list = listForTab;\n if (q) {\n list = list.filter(\n (e) =>\n (e.name ?? '').toLowerCase().includes(q) ||\n e.id.toLowerCase().includes(q) ||\n (e.description ?? '').toLowerCase().includes(q),\n );\n }\n return [...list].sort((a, b) => {\n if (a.hasUi !== b.hasUi) return a.hasUi ? -1 : 1;\n return (a.name || a.id).localeCompare(b.name || b.id, language);\n });\n }, [listForTab, search, language]);\n\n /** Keep dialog + cards in sync after SWR refetch (detail was a stale row reference). */\n useEffect(() => {\n setDetail((prev) => {\n if (!prev) return prev;\n const next = extensions.find((e) => e.id === prev.id);\n if (!next) return null;\n const eligPrev = activationEligibleFor(prev);\n const eligNext = activationEligibleFor(next);\n if (eligPrev === eligNext && prev.active === next.active) return prev;\n return next;\n });\n }, [extensions]);\n\n useLayoutEffect(() => {\n setPageHeader({\n startExtra: null,\n main: (\n <div className=\"w-full min-w-0 px-3 sm:px-5 xl:px-6\">\n <h1 className=\"min-w-0 truncate text-base font-semibold tracking-tight text-fg\">{m.appsPage.title}</h1>\n </div>\n ),\n end: null,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, m.appsPage.title, setPageHeader]);\n\n if (loading && mainTab !== 'marketplace') {\n return <AppsPageSkeleton />;\n }\n\n const showSearch = mainTab !== 'marketplace' && listForTab.length > 0;\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto w-full max-w-app-main px-4 py-8\">\n <header className=\"mb-6\">\n <h1 className=\"text-xl font-semibold text-fg\">{m.appsPage.title}</h1>\n <p className=\"mt-1 text-sm text-fg-muted\">{m.appsPage.subtitle}</p>\n </header>\n\n <div className=\"mb-5 flex flex-col gap-3 border-b border-edge-subtle pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-edge-subtle\">\n <div\n className=\"flex flex-wrap gap-x-1 gap-y-1\"\n role=\"tablist\"\n aria-label={m.appsPage.appsNavAria}\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'marketplace'}\n className={cn(\n 'relative max-w-full rounded-md px-3 py-2 text-left text-sm font-medium transition-colors sm:text-center',\n mainTab === 'marketplace' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'marketplace' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('marketplace')}\n >\n {m.appsPage.tabMarketplace}\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'builtin'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'builtin' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'builtin' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('builtin')}\n >\n {m.appsPage.tabBuiltin}\n <span className=\"ml-1 tabular-nums text-fg-muted\">({bundledExtensions.length})</span>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'user'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'user' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'user' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('user')}\n >\n {m.appsPage.tabUser}\n <span className=\"ml-1 tabular-nums text-fg-muted\">({userExtensions.length})</span>\n </button>\n </div>\n {showSearch ? (\n <div className=\"relative w-full min-w-0 sm:max-w-xs\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted\"\n aria-hidden\n />\n <input\n type=\"search\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder={m.appsPage.searchPlaceholder}\n className=\"w-full rounded-lg border border-edge bg-surface-base py-2 pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n autoComplete=\"off\"\n />\n </div>\n ) : null}\n </div>\n\n {mainTab === 'marketplace' ? (\n <ExtensionMarketplacePanel />\n ) : mainTab === 'builtin' && bundledExtensions.length === 0 ? (\n <EmptyAppsState message={m.appsPage.emptyBuiltin} />\n ) : mainTab === 'user' && userExtensions.length === 0 ? (\n <EmptyAppsState message={m.appsPage.emptyUser} />\n ) : filtered.length === 0 ? (\n <p className=\"rounded-xl border border-dashed border-edge-subtle bg-surface-hover/30 px-4 py-8 text-center text-sm text-fg-muted dark:bg-surface-hover/15\">\n {m.appsPage.noSearchResults}\n </p>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((ext) => (\n <ExtensionAppCard\n key={ext.id}\n extension={ext}\n copy={m.appsPage}\n showSourceBadge={mainTab === 'user'}\n onOpen={() => setDetail(ext)}\n />\n ))}\n </div>\n )}\n </div>\n\n {detail ? (\n <ExtensionDetailDialog key={detail.id} extension={detail} copy={m.appsPage} onClose={() => setDetail(null)} />\n ) : null}\n </div>\n );\n}\n\nfunction activationEligibleFor(ext: ExtensionApiRow): boolean {\n return ext.activationEligible ?? ext.active;\n}\n\nfunction providerLabel(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n if (ext.source === 'bundled') return copy.providerBundled;\n if (ext.source === 'global') return copy.providerGlobal;\n if (ext.source === 'workspace') return copy.providerWorkspace;\n return copy.providerOther;\n}\n\nfunction installSourceBadgeLabel(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n if (ext.source === 'global') return copy.badgeSourceGlobal;\n if (ext.source === 'workspace') return copy.badgeSourceWorkspace;\n return copy.badgeSourceOther;\n}\n\nfunction bundledRunCaption(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n const eligible = activationEligibleFor(ext);\n if (eligible && ext.active) return copy.runStateLive;\n if (eligible && !ext.active) return copy.runStatePendingOn;\n if (!eligible && ext.active) return copy.runStatePendingOff;\n return copy.runStateOff;\n}\n\nfunction ExtensionAppCard({\n extension: ext,\n copy,\n showSourceBadge,\n onOpen,\n}: {\n extension: ExtensionApiRow;\n copy: AppsPageCopy;\n /** When true, show a short global/workspace/other pill (user-installed tab). */\n showSourceBadge: boolean;\n onOpen: () => void;\n}) {\n const eligible = activationEligibleFor(ext);\n const uiTitle = ext.hasUi ? copy.cardTooltipHasUi : copy.cardTooltipNoUi;\n\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className={cn(\n 'group flex w-full flex-col rounded-xl border border-edge bg-surface-base p-4 text-left shadow-sm transition-colors',\n 'hover:border-edge-subtle hover:bg-surface-hover/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n 'dark:hover:bg-surface-hover/25',\n )}\n >\n <div className=\"flex gap-3\">\n <div\n className=\"flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent-soft text-base font-semibold text-accent-fg\"\n aria-hidden\n >\n {(ext.name || ext.id).charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h2 className=\"truncate text-sm font-semibold text-fg\">{ext.name}</h2>\n {ext.version ? (\n <span className=\"text-[11px] text-fg-muted\">v{ext.version}</span>\n ) : null}\n </div>\n {eligible ? (\n <span className=\"inline-flex shrink-0 items-center gap-1 rounded-full bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted\">\n <Check className=\"size-3\" strokeWidth={2.5} aria-hidden />\n {copy.statusEnabled}\n </span>\n ) : (\n <span\n className=\"flex size-8 shrink-0 items-center justify-center rounded-full border-2 border-accent text-accent\"\n aria-hidden\n >\n <Plus className=\"size-4\" strokeWidth={2.5} />\n </span>\n )}\n </div>\n <p className=\"mt-2 line-clamp-2 text-xs leading-relaxed text-fg-muted\">\n {ext.description?.trim() || copy.cardNoDescription}\n </p>\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n <span\n title={uiTitle}\n className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\"\n >\n {ext.hasUi ? copy.badgeKindUi : copy.badgeKindBackend}\n </span>\n {ext.source === 'bundled' ? (\n <span className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\">\n {copy.badgeBundled}\n </span>\n ) : showSourceBadge ? (\n <span\n title={providerLabel(ext, copy)}\n className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\"\n >\n {installSourceBadgeLabel(ext, copy)}\n </span>\n ) : null}\n </div>\n </div>\n </div>\n </button>\n );\n}\n\nfunction ExtensionDetailDialog({\n extension: ext,\n copy,\n onClose,\n}: {\n extension: ExtensionApiRow;\n copy: AppsPageCopy;\n onClose: () => void;\n}) {\n const pages = ext.ui?.contributions?.pages ?? [];\n const settingsPanels = ext.ui?.contributions?.settingsPanels ?? [];\n const chatWidgets = ext.ui?.contributions?.chatWidgets ?? [];\n const sidebarPanels = ext.ui?.contributions?.sidebarPanels ?? [];\n const primaryPage: PageContribution | undefined = pages.find((p) => p.showInNav) ?? pages[0];\n const primarySettingsPanel = settingsPanels[0];\n const openPath = primaryPage ? extensionPagePath(ext.id, primaryPage) : null;\n const settingsPath = primarySettingsPanel\n ? `/settings/ext/${ext.id}/${primarySettingsPanel.id}`\n : ext.hasConfigSchema\n ? `/settings/ext/${ext.id}`\n : null;\n\n return (\n <Dialog.Root defaultOpen onOpenChange={(o) => !o && onClose()}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim\" />\n <Dialog.Content\n className=\"fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailBack}\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg\">\n {copy.detailTitle}\n </Dialog.Title>\n <Dialog.Description className=\"sr-only\">\n {ext.name} ({ext.id})\n </Dialog.Description>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailClose}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto px-5 py-5\">\n <div className=\"flex flex-wrap items-start gap-4\">\n <div\n className=\"flex size-16 shrink-0 items-center justify-center rounded-2xl bg-accent-soft text-xl font-semibold text-accent-fg\"\n aria-hidden\n >\n {(ext.name || ext.id).charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-lg font-semibold text-fg\">{ext.name}</h3>\n <p className=\"mt-0.5 text-sm text-fg-muted\">\n {copy.detailProviderPrefix} {providerLabel(ext, copy)}\n </p>\n {ext.version ? (\n <p className=\"mt-1 text-xs text-fg-muted\">v{ext.version}</p>\n ) : null}\n </div>\n </div>\n\n <p className=\"mt-5 text-sm leading-relaxed text-fg\">\n {ext.description?.trim() || copy.detailNoDescription}\n </p>\n\n {!ext.hasUi ? (\n <p className=\"mt-3 text-xs text-fg-muted\">{copy.backendOnlyHint}</p>\n ) : null}\n\n <p className=\"mt-2 text-xs text-fg-muted\">{bundledRunCaption(ext, copy)}</p>\n\n {ext.source === 'bundled' ? (\n <p className=\"mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20\">\n {copy.builtinConfigHint}\n </p>\n ) : (\n <p className=\"mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20\">\n {copy.cliManageHint}\n </p>\n )}\n\n {ext.hasUi && (pages.length > 0 || settingsPanels.length > 0 || chatWidgets.length > 0) ? (\n <section className=\"mt-8\">\n <h4 className=\"mb-3 text-sm font-semibold text-fg\">{copy.detailSectionFeatures}</h4>\n <div className=\"flex flex-wrap gap-1.5\">\n <ContributionBadge\n template={copy.badgePages}\n count={pages.length}\n hidden={pages.length === 0}\n />\n <ContributionBadge\n template={copy.badgeSettings}\n count={settingsPanels.length}\n hidden={settingsPanels.length === 0}\n />\n <ContributionBadge\n template={copy.badgeWidgets}\n count={chatWidgets.length}\n hidden={chatWidgets.length === 0}\n />\n <ContributionBadge\n template={copy.badgeSidebar}\n count={sidebarPanels.length}\n hidden={sidebarPanels.length === 0}\n />\n </div>\n </section>\n ) : null}\n\n {extensionExposesGatewayShellUi(ext) && (openPath || settingsPath) ? (\n <div className=\"mt-6 flex flex-wrap gap-2 border-t border-edge-subtle pt-4\">\n {openPath ? (\n <Link\n to={openPath}\n onClick={onClose}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n )}\n >\n <ExternalLink className=\"size-4 shrink-0 opacity-80\" aria-hidden />\n {copy.open}\n </Link>\n ) : null}\n {settingsPath ? (\n <Link\n to={settingsPath}\n onClick={onClose}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n )}\n >\n <Settings className=\"size-4 shrink-0 opacity-80\" aria-hidden />\n {copy.openSettings}\n </Link>\n ) : null}\n </div>\n ) : null}\n\n <p className=\"mt-6 text-[11px] leading-relaxed text-fg-muted\">{copy.restartNote}</p>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n\nfunction ContributionBadge({\n template,\n count,\n hidden,\n}: {\n template: string;\n count: number;\n hidden: boolean;\n}) {\n if (hidden || count === 0) return null;\n return (\n <span className=\"inline-flex items-center rounded-md bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted\">\n {template.replace(/\\{\\{count\\}\\}/g, String(count))}\n </span>\n );\n}\n\nfunction AppsPageSkeleton() {\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto w-full max-w-app-main px-4 py-8\">\n <div className=\"mb-6 h-8 w-40 max-w-full animate-pulse rounded-md bg-surface-hover\" />\n <div className=\"mb-2 h-4 w-full max-w-md animate-pulse rounded bg-surface-hover\" />\n <div className=\"mb-5 h-9 w-full max-w-lg animate-pulse rounded-full bg-surface-hover\" />\n <div className=\"mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {[0, 1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-36 animate-pulse rounded-xl border border-edge bg-surface-base\" />\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nfunction EmptyAppsState({ message }: { message: string }) {\n return (\n <div className=\"flex min-h-[min(40vh,16rem)] flex-col items-center justify-center rounded-xl border border-dashed border-edge-subtle bg-surface-hover/40 px-4 py-12 text-center dark:bg-surface-hover/20\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}