@xopcai/xopc 0.0.8 → 0.0.11

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 (242) hide show
  1. package/dist/extensions/telegram/src/plugin.js +1 -1
  2. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  3. package/dist/extensions/weixin/src/plugin.js +1 -1
  4. package/dist/gateway/static/root/assets/{agents-BSNzJWbQ.js → agents-BdC4Y-HX.js} +2 -2
  5. package/dist/gateway/static/root/assets/agents-BdC4Y-HX.js.map +1 -0
  6. package/dist/gateway/static/root/assets/{apps-page-BKk9SB4D.js → apps-page-C-oaSHkm.js} +2 -2
  7. package/dist/gateway/static/root/assets/{apps-page-BKk9SB4D.js.map → apps-page-C-oaSHkm.js.map} +1 -1
  8. package/dist/gateway/static/root/assets/attachment-load-BDDlItdE.js +1 -0
  9. package/dist/gateway/static/root/assets/{channels-settings-_J6cQN6G.js → channels-settings-BqEUppPO.js} +2 -2
  10. package/dist/gateway/static/root/assets/{channels-settings-_J6cQN6G.js.map → channels-settings-BqEUppPO.js.map} +1 -1
  11. package/dist/gateway/static/root/assets/{chat-agents-api-DPb_0O8M.js → chat-agents-api-BhqjQ7iL.js} +2 -2
  12. package/dist/gateway/static/root/assets/{chat-agents-api-DPb_0O8M.js.map → chat-agents-api-BhqjQ7iL.js.map} +1 -1
  13. package/dist/gateway/static/root/assets/{cron-page-BUJOuuKX.js → cron-page-Cli49RKR.js} +2 -2
  14. package/dist/gateway/static/root/assets/{cron-page-BUJOuuKX.js.map → cron-page-Cli49RKR.js.map} +1 -1
  15. package/dist/gateway/static/root/assets/{cron-utils-Cn0YVg8x.js → cron-utils-Dkj-Ldpf.js} +2 -2
  16. package/dist/gateway/static/root/assets/{cron-utils-Cn0YVg8x.js.map → cron-utils-Dkj-Ldpf.js.map} +1 -1
  17. package/dist/gateway/static/root/assets/{electron-env-D9bm1FIu.js → electron-env-BDtJw9AY.js} +2 -2
  18. package/dist/gateway/static/root/assets/{electron-env-D9bm1FIu.js.map → electron-env-BDtJw9AY.js.map} +1 -1
  19. package/dist/gateway/static/root/assets/{extension-debug-page-DTz4O5Ua.js → extension-debug-page-BMcZlaxF.js} +2 -2
  20. package/dist/gateway/static/root/assets/{extension-debug-page-DTz4O5Ua.js.map → extension-debug-page-BMcZlaxF.js.map} +1 -1
  21. package/dist/gateway/static/root/assets/{extension-iframe-host-Cs1Kde9o.js → extension-iframe-host-D5HEF0KR.js} +2 -2
  22. package/dist/gateway/static/root/assets/{extension-iframe-host-Cs1Kde9o.js.map → extension-iframe-host-D5HEF0KR.js.map} +1 -1
  23. package/dist/gateway/static/root/assets/{extension-page-G52iX0Bo.js → extension-page-CXdCSSPl.js} +2 -2
  24. package/dist/gateway/static/root/assets/{extension-page-G52iX0Bo.js.map → extension-page-CXdCSSPl.js.map} +1 -1
  25. package/dist/gateway/static/root/assets/{extension-provider-CO2jxBA9.js → extension-provider-DZCZgQE2.js} +2 -2
  26. package/dist/gateway/static/root/assets/{extension-provider-CO2jxBA9.js.map → extension-provider-DZCZgQE2.js.map} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-D9Ul8uSt.js → extension-settings-page-CX6STpx3.js} +2 -2
  28. package/dist/gateway/static/root/assets/{extension-settings-page-D9Ul8uSt.js.map → extension-settings-page-CX6STpx3.js.map} +1 -1
  29. package/dist/gateway/static/root/assets/{gateway-config-swr-Bc8SVD15.js → gateway-config-swr-Cph02QZn.js} +2 -2
  30. package/dist/gateway/static/root/assets/{gateway-config-swr-Bc8SVD15.js.map → gateway-config-swr-Cph02QZn.js.map} +1 -1
  31. package/dist/gateway/static/root/assets/index-Bty3m0mS.css +2 -0
  32. package/dist/gateway/static/root/assets/{index-BXUJbteW.js → index-iTUyfzNr.js} +10 -10
  33. package/dist/gateway/static/root/assets/index-iTUyfzNr.js.map +1 -0
  34. package/dist/gateway/static/root/assets/{logs-page-5V25JkQY.js → logs-page-B9O5l3I8.js} +2 -2
  35. package/dist/gateway/static/root/assets/{logs-page-5V25JkQY.js.map → logs-page-B9O5l3I8.js.map} +1 -1
  36. package/dist/gateway/static/root/assets/{model-selector-he3aQfme.js → model-selector-BLiY_O25.js} +2 -2
  37. package/dist/gateway/static/root/assets/{model-selector-he3aQfme.js.map → model-selector-BLiY_O25.js.map} +1 -1
  38. package/dist/gateway/static/root/assets/page-header-store-BFpnFTed.js +2 -0
  39. package/dist/gateway/static/root/assets/{page-header-store-DJHD9Ean.js.map → page-header-store-BFpnFTed.js.map} +1 -1
  40. package/dist/gateway/static/root/assets/{session-api-n-4O5d9U.js → session-api-DEhQXWJg.js} +2 -2
  41. package/dist/gateway/static/root/assets/{session-api-n-4O5d9U.js.map → session-api-DEhQXWJg.js.map} +1 -1
  42. package/dist/gateway/static/root/assets/{session-working-directory-control-B6dHLvbr.js → session-working-directory-control-DKOtWs3-.js} +2 -2
  43. package/dist/gateway/static/root/assets/{session-working-directory-control-B6dHLvbr.js.map → session-working-directory-control-DKOtWs3-.js.map} +1 -1
  44. package/dist/gateway/static/root/assets/{sessions-page-rBUfTdm3.js → sessions-page-BYlWP1ep.js} +2 -2
  45. package/dist/gateway/static/root/assets/{sessions-page-rBUfTdm3.js.map → sessions-page-BYlWP1ep.js.map} +1 -1
  46. package/dist/gateway/static/root/assets/{settings-page-B3QrJm-E.js → settings-page-oCnIavdg.js} +2 -2
  47. package/dist/gateway/static/root/assets/settings-page-oCnIavdg.js.map +1 -0
  48. package/dist/gateway/static/root/assets/{skill-api-vxtE8kI6.js → skill-api-DWrn8Az0.js} +2 -2
  49. package/dist/gateway/static/root/assets/{skill-api-vxtE8kI6.js.map → skill-api-DWrn8Az0.js.map} +1 -1
  50. package/dist/gateway/static/root/assets/{skills-page-D36_O2Ub.js → skills-page-C59WQpM1.js} +2 -2
  51. package/dist/gateway/static/root/assets/{skills-page-D36_O2Ub.js.map → skills-page-C59WQpM1.js.map} +1 -1
  52. package/dist/gateway/static/root/assets/{theme-store-CmiSsYBd.js → theme-store-CywXkKml.js} +2 -2
  53. package/dist/gateway/static/root/assets/{theme-store-CmiSsYBd.js.map → theme-store-CywXkKml.js.map} +1 -1
  54. package/dist/gateway/static/root/assets/url-D7yWllI8.js +2 -0
  55. package/dist/gateway/static/root/assets/url-D7yWllI8.js.map +1 -0
  56. package/dist/gateway/static/root/assets/{useTranslation-DYORQ7x6.js → useTranslation-CACj0DBJ.js} +2 -2
  57. package/dist/gateway/static/root/assets/{useTranslation-DYORQ7x6.js.map → useTranslation-CACj0DBJ.js.map} +1 -1
  58. package/dist/gateway/static/root/index.html +15 -15
  59. package/dist/package.js +1 -1
  60. package/dist/src/agent/agent-manager.d.ts +1 -0
  61. package/dist/src/agent/agent-manager.js +20 -12
  62. package/dist/src/agent/agent-manager.js.map +1 -1
  63. package/dist/src/agent/background-review/run-background-review.js +2 -0
  64. package/dist/src/agent/background-review/run-background-review.js.map +1 -1
  65. package/dist/src/agent/child-agent-factory.js +2 -0
  66. package/dist/src/agent/child-agent-factory.js.map +1 -1
  67. package/dist/src/agent/context/expand-at-file-mentions.d.ts +4 -0
  68. package/dist/src/agent/context/expand-at-file-mentions.js +69 -0
  69. package/dist/src/agent/context/expand-at-file-mentions.js.map +1 -0
  70. package/dist/src/agent/context/workspace-seed.js +1 -1
  71. package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
  72. package/dist/src/agent/ipc/bus.js +1 -1
  73. package/dist/src/agent/ipc/inbox.js +1 -1
  74. package/dist/src/agent/ipc/socket.js +1 -1
  75. package/dist/src/agent/memory/compaction.d.ts +1 -1
  76. package/dist/src/agent/memory/compaction.js +38 -11
  77. package/dist/src/agent/memory/compaction.js.map +1 -1
  78. package/dist/src/agent/messaging/command-handler.d.ts +13 -0
  79. package/dist/src/agent/messaging/command-handler.js +14 -2
  80. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  81. package/dist/src/agent/models/manager.js +1 -1
  82. package/dist/src/agent/orchestration/agent-orchestrator.js +6 -1
  83. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  84. package/dist/src/agent/prompt/service-prompt-builder.js +1 -1
  85. package/dist/src/agent/service.d.ts +16 -1
  86. package/dist/src/agent/service.js +178 -20
  87. package/dist/src/agent/service.js.map +1 -1
  88. package/dist/src/agent/skills/format-skills-prompt.js.map +1 -1
  89. package/dist/src/agent/skills/index.js +1 -1
  90. package/dist/src/agent/skills/scanner.js +1 -1
  91. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  92. package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
  93. package/dist/src/agent/skills/skill-manager.js +1 -1
  94. package/dist/src/agent/tools/browser/tools.js.map +1 -1
  95. package/dist/src/agent/tools/factory.js +1 -1
  96. package/dist/src/agent/tools/image-tool.js.map +1 -1
  97. package/dist/src/agent/tools/send-media.js +1 -1
  98. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  99. package/dist/src/agent/tools/write.js +1 -1
  100. package/dist/src/auth/credentials.js +2 -2
  101. package/dist/src/auth/sync-provider-auth.js +1 -1
  102. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  103. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  104. package/dist/src/channels/index.d.ts +1 -1
  105. package/dist/src/channels/index.js +2 -2
  106. package/dist/src/channels/pipeline.d.ts +8 -1
  107. package/dist/src/channels/pipeline.js +49 -4
  108. package/dist/src/channels/pipeline.js.map +1 -1
  109. package/dist/src/chat-commands/builtins/config.d.ts +4 -0
  110. package/dist/src/chat-commands/builtins/config.js +197 -0
  111. package/dist/src/chat-commands/builtins/config.js.map +1 -0
  112. package/dist/src/chat-commands/builtins/context.d.ts +4 -0
  113. package/dist/src/chat-commands/builtins/context.js +44 -0
  114. package/dist/src/chat-commands/builtins/context.js.map +1 -0
  115. package/dist/src/chat-commands/builtins/session.js +111 -0
  116. package/dist/src/chat-commands/builtins/session.js.map +1 -1
  117. package/dist/src/chat-commands/builtins/thinking.js +49 -21
  118. package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
  119. package/dist/src/chat-commands/config-paths.d.ts +10 -0
  120. package/dist/src/chat-commands/config-paths.js +45 -0
  121. package/dist/src/chat-commands/config-paths.js.map +1 -0
  122. package/dist/src/chat-commands/config-value.d.ts +12 -0
  123. package/dist/src/chat-commands/config-value.js +53 -0
  124. package/dist/src/chat-commands/config-value.js.map +1 -0
  125. package/dist/src/chat-commands/context.d.ts +24 -1
  126. package/dist/src/chat-commands/context.js +41 -0
  127. package/dist/src/chat-commands/context.js.map +1 -1
  128. package/dist/src/chat-commands/index.d.ts +2 -0
  129. package/dist/src/chat-commands/index.js +5 -1
  130. package/dist/src/chat-commands/index.js.map +1 -1
  131. package/dist/src/chat-commands/types.d.ts +33 -1
  132. package/dist/src/cli/commands/agent/interactive.js +1 -1
  133. package/dist/src/cli/commands/agent/interactive.js.map +1 -1
  134. package/dist/src/cli/commands/agent.js +22 -10
  135. package/dist/src/cli/commands/agent.js.map +1 -1
  136. package/dist/src/cli/commands/auth.js.map +1 -1
  137. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  138. package/dist/src/cli/commands/extension.js +10 -0
  139. package/dist/src/cli/commands/extension.js.map +1 -1
  140. package/dist/src/cli/commands/init.js +3 -4
  141. package/dist/src/cli/commands/init.js.map +1 -1
  142. package/dist/src/cli/commands/session/utils.js.map +1 -1
  143. package/dist/src/cli/commands/update.d.ts +1 -0
  144. package/dist/src/cli/commands/update.js +171 -0
  145. package/dist/src/cli/commands/update.js.map +1 -0
  146. package/dist/src/cli/index.d.ts +1 -1
  147. package/dist/src/cli/index.js +3 -1
  148. package/dist/src/cli/index.js.map +1 -1
  149. package/dist/src/config/index.d.ts +1 -0
  150. package/dist/src/config/index.js +5 -4
  151. package/dist/src/config/index.js.map +1 -1
  152. package/dist/src/config/loader.js +1 -1
  153. package/dist/src/config/models-json.js +1 -1
  154. package/dist/src/config/paths.js.map +1 -1
  155. package/dist/src/config/profile.js +2 -2
  156. package/dist/src/config/runtime-overrides.d.ts +8 -0
  157. package/dist/src/config/runtime-overrides.js +40 -0
  158. package/dist/src/config/runtime-overrides.js.map +1 -0
  159. package/dist/src/config/schema.d.ts +35 -0
  160. package/dist/src/config/schema.js +19 -3
  161. package/dist/src/config/schema.js.map +1 -1
  162. package/dist/src/cron/executor.js +2 -2
  163. package/dist/src/cron/persistence.js +1 -1
  164. package/dist/src/cron/run-log-store.js +1 -1
  165. package/dist/src/extensions/health.js +1 -1
  166. package/dist/src/extensions/loader.d.ts +1 -1
  167. package/dist/src/extensions/loader.js +6 -9
  168. package/dist/src/extensions/loader.js.map +1 -1
  169. package/dist/src/extensions/lockfile.js +1 -1
  170. package/dist/src/extensions/sdk/index.js +6 -1
  171. package/dist/src/extensions/sdk/index.js.map +1 -0
  172. package/dist/src/gateway/agents-admin.js +2 -2
  173. package/dist/src/gateway/agents-admin.js.map +1 -1
  174. package/dist/src/gateway/hono/oauth.js +1 -1
  175. package/dist/src/gateway/hono/routes/config.js +1 -1
  176. package/dist/src/gateway/hono/routes/index.js +2 -0
  177. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  178. package/dist/src/gateway/hono/routes/models.js +64 -11
  179. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  180. package/dist/src/gateway/hono/routes/public-gateway.js +10 -0
  181. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  182. package/dist/src/gateway/hono/routes/update.d.ts +3 -0
  183. package/dist/src/gateway/hono/routes/update.js +141 -0
  184. package/dist/src/gateway/hono/routes/update.js.map +1 -0
  185. package/dist/src/gateway/hono/routes/workspace.js +84 -4
  186. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  187. package/dist/src/gateway/hono/sse.js +2 -2
  188. package/dist/src/gateway/service.d.ts +1 -0
  189. package/dist/src/gateway/service.js +16 -4
  190. package/dist/src/gateway/service.js.map +1 -1
  191. package/dist/src/gateway/workspace-fs-file-list.d.ts +5 -0
  192. package/dist/src/gateway/workspace-fs-file-list.js +56 -0
  193. package/dist/src/gateway/workspace-fs-file-list.js.map +1 -0
  194. package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
  195. package/dist/src/gateway/workspace-ripgrep.d.ts +5 -0
  196. package/dist/src/gateway/workspace-ripgrep.js +88 -4
  197. package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
  198. package/dist/src/infra/update-channels.d.ts +14 -0
  199. package/dist/src/infra/update-channels.js +30 -0
  200. package/dist/src/infra/update-channels.js.map +1 -0
  201. package/dist/src/infra/update-check.d.ts +53 -0
  202. package/dist/src/infra/update-check.js +155 -0
  203. package/dist/src/infra/update-check.js.map +1 -0
  204. package/dist/src/infra/update-runner.d.ts +18 -0
  205. package/dist/src/infra/update-runner.js +112 -0
  206. package/dist/src/infra/update-runner.js.map +1 -0
  207. package/dist/src/infra/update-startup.d.ts +20 -0
  208. package/dist/src/infra/update-startup.js +246 -0
  209. package/dist/src/infra/update-startup.js.map +1 -0
  210. package/dist/src/providers/extension-stream-bridge.d.ts +3 -0
  211. package/dist/src/providers/extension-stream-bridge.js +239 -0
  212. package/dist/src/providers/extension-stream-bridge.js.map +1 -0
  213. package/dist/src/providers/index.d.ts +7 -2
  214. package/dist/src/providers/index.js +77 -14
  215. package/dist/src/providers/index.js.map +1 -1
  216. package/dist/src/providers/model-registry.js +1 -1
  217. package/dist/src/providers/plugin-registry.js +92 -87
  218. package/dist/src/providers/plugin-registry.js.map +1 -1
  219. package/dist/src/session/chat-export.d.ts +5 -0
  220. package/dist/src/session/chat-export.js +35 -0
  221. package/dist/src/session/chat-export.js.map +1 -0
  222. package/dist/src/session/config-store.js +1 -1
  223. package/dist/src/session/manager.d.ts +1 -1
  224. package/dist/src/session/manager.js +2 -2
  225. package/dist/src/session/manager.js.map +1 -1
  226. package/dist/src/session/session-title.js +1 -1
  227. package/dist/src/session/store.d.ts +1 -1
  228. package/dist/src/session/store.js +5 -5
  229. package/dist/src/session/store.js.map +1 -1
  230. package/dist/src/utils/logger/audit.js +1 -1
  231. package/dist/src/utils/logger/log-store.js +1 -1
  232. package/dist/src/utils/logger/rotation.js +1 -1
  233. package/dist/src/voice/tts/audio.js +1 -1
  234. package/package.json +2 -1
  235. package/dist/gateway/static/root/assets/agents-BSNzJWbQ.js.map +0 -1
  236. package/dist/gateway/static/root/assets/attachment-load-DXcJLSWT.js +0 -1
  237. package/dist/gateway/static/root/assets/index-BXUJbteW.js.map +0 -1
  238. package/dist/gateway/static/root/assets/index-CQLMxWSA.css +0 -2
  239. package/dist/gateway/static/root/assets/page-header-store-DJHD9Ean.js +0 -2
  240. package/dist/gateway/static/root/assets/settings-page-B3QrJm-E.js.map +0 -1
  241. package/dist/gateway/static/root/assets/url-CtSqjF9J.js +0 -2
  242. package/dist/gateway/static/root/assets/url-CtSqjF9J.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{t as e}from"./vendor-react-QAsRxa6t.js";import{c as t,l as n,s as r}from"./url-CtSqjF9J.js";import{r as i,t as a}from"./cn-DPF56z7S.js";import{o}from"./form-field-width-BlpNwrfn.js";import{a as s,i as c}from"./theme-store-CmiSsYBd.js";var l=i(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),u=i(`circle-alert`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`12`,x2:`12`,y1:`8`,y2:`12`,key:`1pkeuh`}],[`line`,{x1:`12`,x2:`12.01`,y1:`16`,y2:`16`,key:`4dfq90`}]]),d=i(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),f=i(`heart`,[[`path`,{d:`M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5`,key:`mvr1a0`}]]),p=i(`key-round`,[[`path`,{d:`M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z`,key:`1s6t7t`}],[`circle`,{cx:`16.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`w0ekpg`}]]),m=i(`log-in`,[[`path`,{d:`m10 17 5-5-5-5`,key:`1bsop3`}],[`path`,{d:`M15 12H3`,key:`6jk70r`}],[`path`,{d:`M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4`,key:`u53s6r`}]]),h=i(`log-out`,[[`path`,{d:`m16 17 5-5-5-5`,key:`1bji2h`}],[`path`,{d:`M21 12H9`,key:`dn1m92`}],[`path`,{d:`M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4`,key:`1uf3rs`}]]),g=i(`mic`,[[`path`,{d:`M12 19v3`,key:`npa21l`}],[`path`,{d:`M19 10v2a7 7 0 0 1-14 0v-2`,key:`1vc78b`}],[`rect`,{x:`9`,y:`2`,width:`6`,height:`13`,rx:`3`,key:`s6n7sd`}]]),_=i(`play`,[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]),v=i(`server`,[[`rect`,{width:`20`,height:`8`,x:`2`,y:`2`,rx:`2`,ry:`2`,key:`ngkwjq`}],[`rect`,{width:`20`,height:`8`,x:`2`,y:`14`,rx:`2`,ry:`2`,key:`iecqi9`}],[`line`,{x1:`6`,x2:`6.01`,y1:`6`,y2:`6`,key:`16zg32`}],[`line`,{x1:`6`,x2:`6.01`,y1:`18`,y2:`18`,key:`nzw8ys`}]]),y=i(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),b=i(`volume-2`,[[`path`,{d:`M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z`,key:`uqj9uw`}],[`path`,{d:`M16 9a5 5 0 0 1 0 6`,key:`1q6k2b`}],[`path`,{d:`M19.364 18.364a9 9 0 0 0 0-12.728`,key:`ijwkga`}]]),x=[`compact`,`default`,`large`];function S(e){document.documentElement.dataset.fontScale=e}function C(){try{let e=localStorage.getItem(`xopc-web-font-scale`),t=`default`;if(e){let n=JSON.parse(e).state?.preference;n&&x.includes(n)&&(t=n)}S(t)}catch{S(`default`)}}var w=t(s(e=>({preference:`default`,setPreference:t=>{S(t),e({preference:t})}}),{name:`xopc-web-font-scale`}));function T(){S(w.getState().preference)}var E=e(),D=[`language`,`theme`,`font`];function O({variant:e,sections:t=D}){let i=r(e=>e.language),s=r(e=>e.setLanguage),l=c(e=>e.preference),u=c(e=>e.setPreference),d=w(e=>e.preference),f=w(e=>e.setPreference),p=n(i).appearanceSettings,m=a(o,e===`page`?`w-full max-w-[min(100%,12rem)] shrink-0 sm:ml-auto sm:w-auto sm:max-w-[11rem]`:e===`toolbar`?`w-auto min-w-[6.5rem] max-w-[10rem] shrink-0 sm:min-w-[7.5rem]`:`w-full`),h=e===`page`?`flex flex-col gap-2 border-b border-edge-subtle py-3.5 last:border-b-0 sm:flex-row sm:items-center sm:justify-between sm:gap-6 sm:py-4`:`flex flex-col gap-1.5`,g=e=>t.includes(e);return e===`toolbar`?(0,E.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[g(`language`)?(0,E.jsxs)(`select`,{className:m,value:i,"aria-label":p.languageTitle,onChange:e=>s(e.target.value),children:[(0,E.jsx)(`option`,{value:`en`,children:p.langOptionEn}),(0,E.jsx)(`option`,{value:`zh`,children:p.langOptionZh})]}):null,g(`theme`)?(0,E.jsxs)(`select`,{className:m,value:l,"aria-label":p.themeTitle,onChange:e=>u(e.target.value),children:[(0,E.jsx)(`option`,{value:`light`,children:p.themeOptionLight}),(0,E.jsx)(`option`,{value:`dark`,children:p.themeOptionDark}),(0,E.jsx)(`option`,{value:`system`,children:p.themeOptionSystem})]}):null,g(`font`)?(0,E.jsxs)(`select`,{className:m,value:d,"aria-label":p.fontScaleTitle,onChange:e=>f(e.target.value),children:[(0,E.jsx)(`option`,{value:`compact`,children:p.fontScaleCompact}),(0,E.jsx)(`option`,{value:`default`,children:p.fontScaleDefault}),(0,E.jsx)(`option`,{value:`large`,children:p.fontScaleLarge})]}):null]}):(0,E.jsxs)(`div`,{className:a(e===`sidebar`&&`flex flex-col gap-4`),children:[g(`language`)?(0,E.jsxs)(`div`,{className:h,children:[(0,E.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`div`,{className:`text-sm font-semibold text-fg`,children:p.languageTitle}),(0,E.jsx)(`p`,{className:`mt-0.5 text-xs text-fg-muted`,children:p.languageDescription})]}),(0,E.jsxs)(`select`,{className:m,value:i,"aria-label":p.languageTitle,onChange:e=>s(e.target.value),children:[(0,E.jsx)(`option`,{value:`en`,children:p.langOptionEn}),(0,E.jsx)(`option`,{value:`zh`,children:p.langOptionZh})]})]}):null,g(`theme`)?(0,E.jsxs)(`div`,{className:h,children:[(0,E.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`div`,{className:`text-sm font-semibold text-fg`,children:p.themeTitle}),(0,E.jsx)(`p`,{className:`mt-0.5 text-xs text-fg-muted`,children:p.themeDescription})]}),(0,E.jsxs)(`select`,{className:m,value:l,"aria-label":p.themeTitle,onChange:e=>u(e.target.value),children:[(0,E.jsx)(`option`,{value:`light`,children:p.themeOptionLight}),(0,E.jsx)(`option`,{value:`dark`,children:p.themeOptionDark}),(0,E.jsx)(`option`,{value:`system`,children:p.themeOptionSystem})]})]}):null,g(`font`)?(0,E.jsxs)(`div`,{className:h,children:[(0,E.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`div`,{className:`text-sm font-semibold text-fg`,children:p.fontScaleTitle}),(0,E.jsx)(`p`,{className:`mt-0.5 text-xs text-fg-muted`,children:p.fontScaleDescription})]}),(0,E.jsxs)(`select`,{className:m,value:d,"aria-label":p.fontScaleTitle,onChange:e=>f(e.target.value),children:[(0,E.jsx)(`option`,{value:`compact`,children:p.fontScaleCompact}),(0,E.jsx)(`option`,{value:`default`,children:p.fontScaleDefault}),(0,E.jsx)(`option`,{value:`large`,children:p.fontScaleLarge})]})]}):null]})}function k(){return typeof window<`u`&&!!window.electronAPI}export{l as _,w as a,v as c,h as d,m as f,u as g,d as h,T as i,_ as l,f as m,O as n,b as o,p,C as r,y as s,k as t,g as u};
2
- //# sourceMappingURL=electron-env-D9bm1FIu.js.map
1
+ import{t as e}from"./vendor-react-QAsRxa6t.js";import{c as t,l as n,s as r}from"./url-D7yWllI8.js";import{r as i,t as a}from"./cn-DPF56z7S.js";import{o}from"./form-field-width-BlpNwrfn.js";import{a as s,i as c}from"./theme-store-CywXkKml.js";var l=i(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),u=i(`circle-alert`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`12`,x2:`12`,y1:`8`,y2:`12`,key:`1pkeuh`}],[`line`,{x1:`12`,x2:`12.01`,y1:`16`,y2:`16`,key:`4dfq90`}]]),d=i(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),f=i(`heart`,[[`path`,{d:`M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5`,key:`mvr1a0`}]]),p=i(`key-round`,[[`path`,{d:`M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z`,key:`1s6t7t`}],[`circle`,{cx:`16.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`w0ekpg`}]]),m=i(`log-in`,[[`path`,{d:`m10 17 5-5-5-5`,key:`1bsop3`}],[`path`,{d:`M15 12H3`,key:`6jk70r`}],[`path`,{d:`M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4`,key:`u53s6r`}]]),h=i(`log-out`,[[`path`,{d:`m16 17 5-5-5-5`,key:`1bji2h`}],[`path`,{d:`M21 12H9`,key:`dn1m92`}],[`path`,{d:`M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4`,key:`1uf3rs`}]]),g=i(`mic`,[[`path`,{d:`M12 19v3`,key:`npa21l`}],[`path`,{d:`M19 10v2a7 7 0 0 1-14 0v-2`,key:`1vc78b`}],[`rect`,{x:`9`,y:`2`,width:`6`,height:`13`,rx:`3`,key:`s6n7sd`}]]),_=i(`play`,[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]),v=i(`server`,[[`rect`,{width:`20`,height:`8`,x:`2`,y:`2`,rx:`2`,ry:`2`,key:`ngkwjq`}],[`rect`,{width:`20`,height:`8`,x:`2`,y:`14`,rx:`2`,ry:`2`,key:`iecqi9`}],[`line`,{x1:`6`,x2:`6.01`,y1:`6`,y2:`6`,key:`16zg32`}],[`line`,{x1:`6`,x2:`6.01`,y1:`18`,y2:`18`,key:`nzw8ys`}]]),y=i(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),b=i(`volume-2`,[[`path`,{d:`M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z`,key:`uqj9uw`}],[`path`,{d:`M16 9a5 5 0 0 1 0 6`,key:`1q6k2b`}],[`path`,{d:`M19.364 18.364a9 9 0 0 0 0-12.728`,key:`ijwkga`}]]),x=[`compact`,`default`,`large`];function S(e){document.documentElement.dataset.fontScale=e}function C(){try{let e=localStorage.getItem(`xopc-web-font-scale`),t=`default`;if(e){let n=JSON.parse(e).state?.preference;n&&x.includes(n)&&(t=n)}S(t)}catch{S(`default`)}}var w=t(s(e=>({preference:`default`,setPreference:t=>{S(t),e({preference:t})}}),{name:`xopc-web-font-scale`}));function T(){S(w.getState().preference)}var E=e(),D=[`language`,`theme`,`font`];function O({variant:e,sections:t=D}){let i=r(e=>e.language),s=r(e=>e.setLanguage),l=c(e=>e.preference),u=c(e=>e.setPreference),d=w(e=>e.preference),f=w(e=>e.setPreference),p=n(i).appearanceSettings,m=a(o,e===`page`?`w-full max-w-[min(100%,12rem)] shrink-0 sm:ml-auto sm:w-auto sm:max-w-[11rem]`:e===`toolbar`?`w-auto min-w-[6.5rem] max-w-[10rem] shrink-0 sm:min-w-[7.5rem]`:`w-full`),h=e===`page`?`flex flex-col gap-2 border-b border-edge-subtle py-3.5 last:border-b-0 sm:flex-row sm:items-center sm:justify-between sm:gap-6 sm:py-4`:`flex flex-col gap-1.5`,g=e=>t.includes(e);return e===`toolbar`?(0,E.jsxs)(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[g(`language`)?(0,E.jsxs)(`select`,{className:m,value:i,"aria-label":p.languageTitle,onChange:e=>s(e.target.value),children:[(0,E.jsx)(`option`,{value:`en`,children:p.langOptionEn}),(0,E.jsx)(`option`,{value:`zh`,children:p.langOptionZh})]}):null,g(`theme`)?(0,E.jsxs)(`select`,{className:m,value:l,"aria-label":p.themeTitle,onChange:e=>u(e.target.value),children:[(0,E.jsx)(`option`,{value:`light`,children:p.themeOptionLight}),(0,E.jsx)(`option`,{value:`dark`,children:p.themeOptionDark}),(0,E.jsx)(`option`,{value:`system`,children:p.themeOptionSystem})]}):null,g(`font`)?(0,E.jsxs)(`select`,{className:m,value:d,"aria-label":p.fontScaleTitle,onChange:e=>f(e.target.value),children:[(0,E.jsx)(`option`,{value:`compact`,children:p.fontScaleCompact}),(0,E.jsx)(`option`,{value:`default`,children:p.fontScaleDefault}),(0,E.jsx)(`option`,{value:`large`,children:p.fontScaleLarge})]}):null]}):(0,E.jsxs)(`div`,{className:a(e===`sidebar`&&`flex flex-col gap-4`),children:[g(`language`)?(0,E.jsxs)(`div`,{className:h,children:[(0,E.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`div`,{className:`text-sm font-semibold text-fg`,children:p.languageTitle}),(0,E.jsx)(`p`,{className:`mt-0.5 text-xs text-fg-muted`,children:p.languageDescription})]}),(0,E.jsxs)(`select`,{className:m,value:i,"aria-label":p.languageTitle,onChange:e=>s(e.target.value),children:[(0,E.jsx)(`option`,{value:`en`,children:p.langOptionEn}),(0,E.jsx)(`option`,{value:`zh`,children:p.langOptionZh})]})]}):null,g(`theme`)?(0,E.jsxs)(`div`,{className:h,children:[(0,E.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`div`,{className:`text-sm font-semibold text-fg`,children:p.themeTitle}),(0,E.jsx)(`p`,{className:`mt-0.5 text-xs text-fg-muted`,children:p.themeDescription})]}),(0,E.jsxs)(`select`,{className:m,value:l,"aria-label":p.themeTitle,onChange:e=>u(e.target.value),children:[(0,E.jsx)(`option`,{value:`light`,children:p.themeOptionLight}),(0,E.jsx)(`option`,{value:`dark`,children:p.themeOptionDark}),(0,E.jsx)(`option`,{value:`system`,children:p.themeOptionSystem})]})]}):null,g(`font`)?(0,E.jsxs)(`div`,{className:h,children:[(0,E.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`div`,{className:`text-sm font-semibold text-fg`,children:p.fontScaleTitle}),(0,E.jsx)(`p`,{className:`mt-0.5 text-xs text-fg-muted`,children:p.fontScaleDescription})]}),(0,E.jsxs)(`select`,{className:m,value:d,"aria-label":p.fontScaleTitle,onChange:e=>f(e.target.value),children:[(0,E.jsx)(`option`,{value:`compact`,children:p.fontScaleCompact}),(0,E.jsx)(`option`,{value:`default`,children:p.fontScaleDefault}),(0,E.jsx)(`option`,{value:`large`,children:p.fontScaleLarge})]})]}):null]})}function k(){return typeof window<`u`&&!!window.electronAPI}export{l as _,w as a,v as c,h as d,m as f,u as g,d as h,T as i,_ as l,f as m,O as n,b as o,p,C as r,y as s,k as t,g as u};
2
+ //# sourceMappingURL=electron-env-BDtJw9AY.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"electron-env-D9bm1FIu.js","names":["__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode"],"sources":["../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/box.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/circle-alert.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/circle-check.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/heart.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/key-round.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/log-in.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/log-out.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/mic.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/play.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/server.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/shield.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/volume-2.js","../../../../../web/src/stores/font-scale-store.ts","../../../../../web/src/components/shell/preference-select-fields.tsx","../../../../../web/src/lib/electron-env.ts"],"sourcesContent":["/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z\",\n key: \"hh9hay\"\n }\n ],\n [\"path\", { d: \"m3.3 7 8.7 5 8.7-5\", key: \"g66t2b\" }],\n [\"path\", { d: \"M12 22V12\", key: \"d0xqtd\" }]\n];\nconst Box = createLucideIcon(\"box\", __iconNode);\n\nexport { __iconNode, Box as default };\n//# sourceMappingURL=box.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n];\nconst CircleAlert = createLucideIcon(\"circle-alert\", __iconNode);\n\nexport { __iconNode, CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m9 12 2 2 4-4\", key: \"dzmm74\" }]\n];\nconst CircleCheck = createLucideIcon(\"circle-check\", __iconNode);\n\nexport { __iconNode, CircleCheck as default };\n//# sourceMappingURL=circle-check.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5\",\n key: \"mvr1a0\"\n }\n ]\n];\nconst Heart = createLucideIcon(\"heart\", __iconNode);\n\nexport { __iconNode, Heart as default };\n//# sourceMappingURL=heart.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z\",\n key: \"1s6t7t\"\n }\n ],\n [\"circle\", { cx: \"16.5\", cy: \"7.5\", r: \".5\", fill: \"currentColor\", key: \"w0ekpg\" }]\n];\nconst KeyRound = createLucideIcon(\"key-round\", __iconNode);\n\nexport { __iconNode, KeyRound as default };\n//# sourceMappingURL=key-round.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"m10 17 5-5-5-5\", key: \"1bsop3\" }],\n [\"path\", { d: \"M15 12H3\", key: \"6jk70r\" }],\n [\"path\", { d: \"M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4\", key: \"u53s6r\" }]\n];\nconst LogIn = createLucideIcon(\"log-in\", __iconNode);\n\nexport { __iconNode, LogIn as default };\n//# sourceMappingURL=log-in.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"m16 17 5-5-5-5\", key: \"1bji2h\" }],\n [\"path\", { d: \"M21 12H9\", key: \"dn1m92\" }],\n [\"path\", { d: \"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\", key: \"1uf3rs\" }]\n];\nconst LogOut = createLucideIcon(\"log-out\", __iconNode);\n\nexport { __iconNode, LogOut as default };\n//# sourceMappingURL=log-out.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 19v3\", key: \"npa21l\" }],\n [\"path\", { d: \"M19 10v2a7 7 0 0 1-14 0v-2\", key: \"1vc78b\" }],\n [\"rect\", { x: \"9\", y: \"2\", width: \"6\", height: \"13\", rx: \"3\", key: \"s6n7sd\" }]\n];\nconst Mic = createLucideIcon(\"mic\", __iconNode);\n\nexport { __iconNode, Mic as default };\n//# sourceMappingURL=mic.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\",\n key: \"10ikf1\"\n }\n ]\n];\nconst Play = createLucideIcon(\"play\", __iconNode);\n\nexport { __iconNode, Play as default };\n//# sourceMappingURL=play.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"rect\", { width: \"20\", height: \"8\", x: \"2\", y: \"2\", rx: \"2\", ry: \"2\", key: \"ngkwjq\" }],\n [\"rect\", { width: \"20\", height: \"8\", x: \"2\", y: \"14\", rx: \"2\", ry: \"2\", key: \"iecqi9\" }],\n [\"line\", { x1: \"6\", x2: \"6.01\", y1: \"6\", y2: \"6\", key: \"16zg32\" }],\n [\"line\", { x1: \"6\", x2: \"6.01\", y1: \"18\", y2: \"18\", key: \"nzw8ys\" }]\n];\nconst Server = createLucideIcon(\"server\", __iconNode);\n\nexport { __iconNode, Server as default };\n//# sourceMappingURL=server.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\",\n key: \"oel41y\"\n }\n ]\n];\nconst Shield = createLucideIcon(\"shield\", __iconNode);\n\nexport { __iconNode, Shield as default };\n//# sourceMappingURL=shield.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z\",\n key: \"uqj9uw\"\n }\n ],\n [\"path\", { d: \"M16 9a5 5 0 0 1 0 6\", key: \"1q6k2b\" }],\n [\"path\", { d: \"M19.364 18.364a9 9 0 0 0 0-12.728\", key: \"ijwkga\" }]\n];\nconst Volume2 = createLucideIcon(\"volume-2\", __iconNode);\n\nexport { __iconNode, Volume2 as default };\n//# sourceMappingURL=volume-2.js.map\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\nexport type FontScalePreference = 'compact' | 'default' | 'large';\n\nconst VALID: readonly FontScalePreference[] = ['compact', 'default', 'large'];\n\nfunction applyDomFontScale(pref: FontScalePreference) {\n document.documentElement.dataset.fontScale = pref;\n}\n\n/** Sync DOM from localStorage before React paint (zustand persist hydrates async). */\nexport function bootstrapFontScale() {\n try {\n const raw = localStorage.getItem('xopc-web-font-scale');\n let pref: FontScalePreference = 'default';\n if (raw) {\n const parsed = JSON.parse(raw) as { state?: { preference?: FontScalePreference } };\n const p = parsed.state?.preference;\n if (p && (VALID as readonly string[]).includes(p)) pref = p;\n }\n applyDomFontScale(pref);\n } catch {\n applyDomFontScale('default');\n }\n}\n\ntype FontScaleState = {\n preference: FontScalePreference;\n setPreference: (p: FontScalePreference) => void;\n};\n\nexport const useFontScaleStore = create(\n persist<FontScaleState>(\n (set) => ({\n preference: 'default',\n\n setPreference: (preference) => {\n applyDomFontScale(preference);\n set({ preference });\n },\n }),\n {\n name: 'xopc-web-font-scale',\n },\n ),\n);\n\nexport function syncFontScaleAfterHydration() {\n applyDomFontScale(useFontScaleStore.getState().preference);\n}\n","import type { StoredLanguage } from '@/lib/storage';\nimport { selectControlBaseClass } from '@/lib/form-field-width';\nimport { cn } from '@/lib/cn';\nimport { messages } from '@/i18n/messages';\nimport { useLocaleStore } from '@/stores/locale-store';\nimport { type FontScalePreference, useFontScaleStore } from '@/stores/font-scale-store';\nimport { type ThemePreference, useThemeStore } from '@/stores/theme-store';\n\ntype Variant = 'page' | 'sidebar' | 'toolbar';\n\nexport type PreferenceSection = 'language' | 'theme' | 'font';\n\nconst ALL_SECTIONS: readonly PreferenceSection[] = ['language', 'theme', 'font'];\n\nexport function PreferenceSelectFields({\n variant,\n sections = ALL_SECTIONS,\n}: {\n variant: Variant;\n sections?: readonly PreferenceSection[];\n}) {\n const language = useLocaleStore((s) => s.language);\n const setLanguage = useLocaleStore((s) => s.setLanguage);\n const themePref = useThemeStore((s) => s.preference);\n const setThemePref = useThemeStore((s) => s.setPreference);\n const fontPref = useFontScaleStore((s) => s.preference);\n const setFontPref = useFontScaleStore((s) => s.setPreference);\n\n const m = messages(language);\n const a = m.appearanceSettings;\n\n /** Page layout: short control width (labels are short); avoid `w-full` stretching on wide rows. */\n const selectClass = cn(\n selectControlBaseClass,\n variant === 'page'\n ? 'w-full max-w-[min(100%,12rem)] shrink-0 sm:ml-auto sm:w-auto sm:max-w-[11rem]'\n : variant === 'toolbar'\n ? 'w-auto min-w-[6.5rem] max-w-[10rem] shrink-0 sm:min-w-[7.5rem]'\n : 'w-full',\n );\n\n const rowClass =\n variant === 'page'\n ? 'flex flex-col gap-2 border-b border-edge-subtle py-3.5 last:border-b-0 sm:flex-row sm:items-center sm:justify-between sm:gap-6 sm:py-4'\n : 'flex flex-col gap-1.5';\n\n const show = (id: PreferenceSection) => sections.includes(id);\n\n if (variant === 'toolbar') {\n return (\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n {show('language') ? (\n <select\n className={selectClass}\n value={language}\n aria-label={a.languageTitle}\n onChange={(e) => setLanguage(e.target.value as StoredLanguage)}\n >\n <option value=\"en\">{a.langOptionEn}</option>\n <option value=\"zh\">{a.langOptionZh}</option>\n </select>\n ) : null}\n {show('theme') ? (\n <select\n className={selectClass}\n value={themePref}\n aria-label={a.themeTitle}\n onChange={(e) => setThemePref(e.target.value as ThemePreference)}\n >\n <option value=\"light\">{a.themeOptionLight}</option>\n <option value=\"dark\">{a.themeOptionDark}</option>\n <option value=\"system\">{a.themeOptionSystem}</option>\n </select>\n ) : null}\n {show('font') ? (\n <select\n className={selectClass}\n value={fontPref}\n aria-label={a.fontScaleTitle}\n onChange={(e) => setFontPref(e.target.value as FontScalePreference)}\n >\n <option value=\"compact\">{a.fontScaleCompact}</option>\n <option value=\"default\">{a.fontScaleDefault}</option>\n <option value=\"large\">{a.fontScaleLarge}</option>\n </select>\n ) : null}\n </div>\n );\n }\n\n return (\n <div className={cn(variant === 'sidebar' && 'flex flex-col gap-4')}>\n {show('language') ? (\n <div className={rowClass}>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold text-fg\">{a.languageTitle}</div>\n <p className=\"mt-0.5 text-xs text-fg-muted\">{a.languageDescription}</p>\n </div>\n <select\n className={selectClass}\n value={language}\n aria-label={a.languageTitle}\n onChange={(e) => setLanguage(e.target.value as StoredLanguage)}\n >\n <option value=\"en\">{a.langOptionEn}</option>\n <option value=\"zh\">{a.langOptionZh}</option>\n </select>\n </div>\n ) : null}\n\n {show('theme') ? (\n <div className={rowClass}>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold text-fg\">{a.themeTitle}</div>\n <p className=\"mt-0.5 text-xs text-fg-muted\">{a.themeDescription}</p>\n </div>\n <select\n className={selectClass}\n value={themePref}\n aria-label={a.themeTitle}\n onChange={(e) => setThemePref(e.target.value as ThemePreference)}\n >\n <option value=\"light\">{a.themeOptionLight}</option>\n <option value=\"dark\">{a.themeOptionDark}</option>\n <option value=\"system\">{a.themeOptionSystem}</option>\n </select>\n </div>\n ) : null}\n\n {show('font') ? (\n <div className={rowClass}>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold text-fg\">{a.fontScaleTitle}</div>\n <p className=\"mt-0.5 text-xs text-fg-muted\">{a.fontScaleDescription}</p>\n </div>\n <select\n className={selectClass}\n value={fontPref}\n aria-label={a.fontScaleTitle}\n onChange={(e) => setFontPref(e.target.value as FontScalePreference)}\n >\n <option value=\"compact\">{a.fontScaleCompact}</option>\n <option value=\"default\">{a.fontScaleDefault}</option>\n <option value=\"large\">{a.fontScaleLarge}</option>\n </select>\n </div>\n ) : null}\n </div>\n );\n}\n","/** True when running inside Electron with preload bridge (not gateway-only web). */\nexport function isElectron(): boolean {\n return typeof window !== 'undefined' && Boolean(window.electronAPI);\n}\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11],"mappings":"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"}
1
+ {"version":3,"file":"electron-env-BDtJw9AY.js","names":["__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode","__iconNode"],"sources":["../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/box.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/circle-alert.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/circle-check.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/heart.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/key-round.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/log-in.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/log-out.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/mic.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/play.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/server.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/shield.js","../../../../../node_modules/.pnpm/lucide-react@1.8.0_react@19.2.5/node_modules/lucide-react/dist/esm/icons/volume-2.js","../../../../../web/src/stores/font-scale-store.ts","../../../../../web/src/components/shell/preference-select-fields.tsx","../../../../../web/src/lib/electron-env.ts"],"sourcesContent":["/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z\",\n key: \"hh9hay\"\n }\n ],\n [\"path\", { d: \"m3.3 7 8.7 5 8.7-5\", key: \"g66t2b\" }],\n [\"path\", { d: \"M12 22V12\", key: \"d0xqtd\" }]\n];\nconst Box = createLucideIcon(\"box\", __iconNode);\n\nexport { __iconNode, Box as default };\n//# sourceMappingURL=box.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n];\nconst CircleAlert = createLucideIcon(\"circle-alert\", __iconNode);\n\nexport { __iconNode, CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m9 12 2 2 4-4\", key: \"dzmm74\" }]\n];\nconst CircleCheck = createLucideIcon(\"circle-check\", __iconNode);\n\nexport { __iconNode, CircleCheck as default };\n//# sourceMappingURL=circle-check.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5\",\n key: \"mvr1a0\"\n }\n ]\n];\nconst Heart = createLucideIcon(\"heart\", __iconNode);\n\nexport { __iconNode, Heart as default };\n//# sourceMappingURL=heart.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z\",\n key: \"1s6t7t\"\n }\n ],\n [\"circle\", { cx: \"16.5\", cy: \"7.5\", r: \".5\", fill: \"currentColor\", key: \"w0ekpg\" }]\n];\nconst KeyRound = createLucideIcon(\"key-round\", __iconNode);\n\nexport { __iconNode, KeyRound as default };\n//# sourceMappingURL=key-round.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"m10 17 5-5-5-5\", key: \"1bsop3\" }],\n [\"path\", { d: \"M15 12H3\", key: \"6jk70r\" }],\n [\"path\", { d: \"M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4\", key: \"u53s6r\" }]\n];\nconst LogIn = createLucideIcon(\"log-in\", __iconNode);\n\nexport { __iconNode, LogIn as default };\n//# sourceMappingURL=log-in.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"m16 17 5-5-5-5\", key: \"1bji2h\" }],\n [\"path\", { d: \"M21 12H9\", key: \"dn1m92\" }],\n [\"path\", { d: \"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\", key: \"1uf3rs\" }]\n];\nconst LogOut = createLucideIcon(\"log-out\", __iconNode);\n\nexport { __iconNode, LogOut as default };\n//# sourceMappingURL=log-out.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 19v3\", key: \"npa21l\" }],\n [\"path\", { d: \"M19 10v2a7 7 0 0 1-14 0v-2\", key: \"1vc78b\" }],\n [\"rect\", { x: \"9\", y: \"2\", width: \"6\", height: \"13\", rx: \"3\", key: \"s6n7sd\" }]\n];\nconst Mic = createLucideIcon(\"mic\", __iconNode);\n\nexport { __iconNode, Mic as default };\n//# sourceMappingURL=mic.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\",\n key: \"10ikf1\"\n }\n ]\n];\nconst Play = createLucideIcon(\"play\", __iconNode);\n\nexport { __iconNode, Play as default };\n//# sourceMappingURL=play.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"rect\", { width: \"20\", height: \"8\", x: \"2\", y: \"2\", rx: \"2\", ry: \"2\", key: \"ngkwjq\" }],\n [\"rect\", { width: \"20\", height: \"8\", x: \"2\", y: \"14\", rx: \"2\", ry: \"2\", key: \"iecqi9\" }],\n [\"line\", { x1: \"6\", x2: \"6.01\", y1: \"6\", y2: \"6\", key: \"16zg32\" }],\n [\"line\", { x1: \"6\", x2: \"6.01\", y1: \"18\", y2: \"18\", key: \"nzw8ys\" }]\n];\nconst Server = createLucideIcon(\"server\", __iconNode);\n\nexport { __iconNode, Server as default };\n//# sourceMappingURL=server.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\",\n key: \"oel41y\"\n }\n ]\n];\nconst Shield = createLucideIcon(\"shield\", __iconNode);\n\nexport { __iconNode, Shield as default };\n//# sourceMappingURL=shield.js.map\n","/**\n * @license lucide-react v1.8.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z\",\n key: \"uqj9uw\"\n }\n ],\n [\"path\", { d: \"M16 9a5 5 0 0 1 0 6\", key: \"1q6k2b\" }],\n [\"path\", { d: \"M19.364 18.364a9 9 0 0 0 0-12.728\", key: \"ijwkga\" }]\n];\nconst Volume2 = createLucideIcon(\"volume-2\", __iconNode);\n\nexport { __iconNode, Volume2 as default };\n//# sourceMappingURL=volume-2.js.map\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\nexport type FontScalePreference = 'compact' | 'default' | 'large';\n\nconst VALID: readonly FontScalePreference[] = ['compact', 'default', 'large'];\n\nfunction applyDomFontScale(pref: FontScalePreference) {\n document.documentElement.dataset.fontScale = pref;\n}\n\n/** Sync DOM from localStorage before React paint (zustand persist hydrates async). */\nexport function bootstrapFontScale() {\n try {\n const raw = localStorage.getItem('xopc-web-font-scale');\n let pref: FontScalePreference = 'default';\n if (raw) {\n const parsed = JSON.parse(raw) as { state?: { preference?: FontScalePreference } };\n const p = parsed.state?.preference;\n if (p && (VALID as readonly string[]).includes(p)) pref = p;\n }\n applyDomFontScale(pref);\n } catch {\n applyDomFontScale('default');\n }\n}\n\ntype FontScaleState = {\n preference: FontScalePreference;\n setPreference: (p: FontScalePreference) => void;\n};\n\nexport const useFontScaleStore = create(\n persist<FontScaleState>(\n (set) => ({\n preference: 'default',\n\n setPreference: (preference) => {\n applyDomFontScale(preference);\n set({ preference });\n },\n }),\n {\n name: 'xopc-web-font-scale',\n },\n ),\n);\n\nexport function syncFontScaleAfterHydration() {\n applyDomFontScale(useFontScaleStore.getState().preference);\n}\n","import type { StoredLanguage } from '@/lib/storage';\nimport { selectControlBaseClass } from '@/lib/form-field-width';\nimport { cn } from '@/lib/cn';\nimport { messages } from '@/i18n/messages';\nimport { useLocaleStore } from '@/stores/locale-store';\nimport { type FontScalePreference, useFontScaleStore } from '@/stores/font-scale-store';\nimport { type ThemePreference, useThemeStore } from '@/stores/theme-store';\n\ntype Variant = 'page' | 'sidebar' | 'toolbar';\n\nexport type PreferenceSection = 'language' | 'theme' | 'font';\n\nconst ALL_SECTIONS: readonly PreferenceSection[] = ['language', 'theme', 'font'];\n\nexport function PreferenceSelectFields({\n variant,\n sections = ALL_SECTIONS,\n}: {\n variant: Variant;\n sections?: readonly PreferenceSection[];\n}) {\n const language = useLocaleStore((s) => s.language);\n const setLanguage = useLocaleStore((s) => s.setLanguage);\n const themePref = useThemeStore((s) => s.preference);\n const setThemePref = useThemeStore((s) => s.setPreference);\n const fontPref = useFontScaleStore((s) => s.preference);\n const setFontPref = useFontScaleStore((s) => s.setPreference);\n\n const m = messages(language);\n const a = m.appearanceSettings;\n\n /** Page layout: short control width (labels are short); avoid `w-full` stretching on wide rows. */\n const selectClass = cn(\n selectControlBaseClass,\n variant === 'page'\n ? 'w-full max-w-[min(100%,12rem)] shrink-0 sm:ml-auto sm:w-auto sm:max-w-[11rem]'\n : variant === 'toolbar'\n ? 'w-auto min-w-[6.5rem] max-w-[10rem] shrink-0 sm:min-w-[7.5rem]'\n : 'w-full',\n );\n\n const rowClass =\n variant === 'page'\n ? 'flex flex-col gap-2 border-b border-edge-subtle py-3.5 last:border-b-0 sm:flex-row sm:items-center sm:justify-between sm:gap-6 sm:py-4'\n : 'flex flex-col gap-1.5';\n\n const show = (id: PreferenceSection) => sections.includes(id);\n\n if (variant === 'toolbar') {\n return (\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n {show('language') ? (\n <select\n className={selectClass}\n value={language}\n aria-label={a.languageTitle}\n onChange={(e) => setLanguage(e.target.value as StoredLanguage)}\n >\n <option value=\"en\">{a.langOptionEn}</option>\n <option value=\"zh\">{a.langOptionZh}</option>\n </select>\n ) : null}\n {show('theme') ? (\n <select\n className={selectClass}\n value={themePref}\n aria-label={a.themeTitle}\n onChange={(e) => setThemePref(e.target.value as ThemePreference)}\n >\n <option value=\"light\">{a.themeOptionLight}</option>\n <option value=\"dark\">{a.themeOptionDark}</option>\n <option value=\"system\">{a.themeOptionSystem}</option>\n </select>\n ) : null}\n {show('font') ? (\n <select\n className={selectClass}\n value={fontPref}\n aria-label={a.fontScaleTitle}\n onChange={(e) => setFontPref(e.target.value as FontScalePreference)}\n >\n <option value=\"compact\">{a.fontScaleCompact}</option>\n <option value=\"default\">{a.fontScaleDefault}</option>\n <option value=\"large\">{a.fontScaleLarge}</option>\n </select>\n ) : null}\n </div>\n );\n }\n\n return (\n <div className={cn(variant === 'sidebar' && 'flex flex-col gap-4')}>\n {show('language') ? (\n <div className={rowClass}>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold text-fg\">{a.languageTitle}</div>\n <p className=\"mt-0.5 text-xs text-fg-muted\">{a.languageDescription}</p>\n </div>\n <select\n className={selectClass}\n value={language}\n aria-label={a.languageTitle}\n onChange={(e) => setLanguage(e.target.value as StoredLanguage)}\n >\n <option value=\"en\">{a.langOptionEn}</option>\n <option value=\"zh\">{a.langOptionZh}</option>\n </select>\n </div>\n ) : null}\n\n {show('theme') ? (\n <div className={rowClass}>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold text-fg\">{a.themeTitle}</div>\n <p className=\"mt-0.5 text-xs text-fg-muted\">{a.themeDescription}</p>\n </div>\n <select\n className={selectClass}\n value={themePref}\n aria-label={a.themeTitle}\n onChange={(e) => setThemePref(e.target.value as ThemePreference)}\n >\n <option value=\"light\">{a.themeOptionLight}</option>\n <option value=\"dark\">{a.themeOptionDark}</option>\n <option value=\"system\">{a.themeOptionSystem}</option>\n </select>\n </div>\n ) : null}\n\n {show('font') ? (\n <div className={rowClass}>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold text-fg\">{a.fontScaleTitle}</div>\n <p className=\"mt-0.5 text-xs text-fg-muted\">{a.fontScaleDescription}</p>\n </div>\n <select\n className={selectClass}\n value={fontPref}\n aria-label={a.fontScaleTitle}\n onChange={(e) => setFontPref(e.target.value as FontScalePreference)}\n >\n <option value=\"compact\">{a.fontScaleCompact}</option>\n <option value=\"default\">{a.fontScaleDefault}</option>\n <option value=\"large\">{a.fontScaleLarge}</option>\n </select>\n </div>\n ) : null}\n </div>\n );\n}\n","/** True when running inside Electron with preload bridge (not gateway-only web). */\nexport function isElectron(): boolean {\n return typeof window !== 'undefined' && Boolean(window.electronAPI);\n}\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{i as t,t as n}from"./vendor-react-QAsRxa6t.js";import{t as r}from"./useTranslation-DYORQ7x6.js";import{i}from"./extension-provider-CO2jxBA9.js";var a=e(t(),1),o=n(),s=`xopc.extensionUiGrants.v1`;function c(){let{t:e}=r(),t=i(),[n,s]=(0,a.useState)(()=>l()),c=(0,a.useMemo)(()=>[...t].sort((e,t)=>e.id.localeCompare(t.id)),[t]);return(0,o.jsxs)(`div`,{className:`mx-auto flex w-full max-w-app-main flex-col gap-6 px-4 py-8`,children:[(0,o.jsxs)(`div`,{children:[(0,o.jsx)(`h1`,{className:`text-lg font-semibold text-fg`,children:e(`extensionDebug.title`)}),(0,o.jsx)(`p`,{className:`mt-1 text-sm text-fg-muted`,children:e(`extensionDebug.subtitle`)})]}),(0,o.jsxs)(`section`,{className:`rounded-xl border border-edge bg-surface-base p-4`,children:[(0,o.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:e(`extensionDebug.grantsHeading`)}),(0,o.jsx)(`p`,{className:`mt-1 text-xs text-fg-muted`,children:e(`extensionDebug.grantsHint`)}),(0,o.jsx)(`pre`,{className:`mt-3 max-h-48 overflow-auto rounded-lg border border-edge-subtle bg-surface-muted p-3 font-mono text-xs text-fg`,children:n}),(0,o.jsx)(`button`,{type:`button`,className:`mt-3 rounded-lg border border-edge px-3 py-1.5 text-xs font-medium text-fg hover:bg-surface-hover`,onClick:()=>s(l()),children:e(`extensionDebug.refresh`)})]}),(0,o.jsxs)(`section`,{className:`rounded-xl border border-edge bg-surface-base p-4`,children:[(0,o.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:e(`extensionDebug.listHeading`)}),(0,o.jsx)(`div`,{className:`mt-3 overflow-x-auto`,children:(0,o.jsxs)(`table`,{className:`w-full min-w-[32rem] border-collapse text-left text-sm`,children:[(0,o.jsx)(`thead`,{children:(0,o.jsxs)(`tr`,{className:`border-b border-edge text-xs uppercase text-fg-muted`,children:[(0,o.jsx)(`th`,{className:`py-2 pr-2`,children:e(`extensionDebug.colId`)}),(0,o.jsx)(`th`,{className:`py-2 pr-2`,children:e(`extensionDebug.colName`)}),(0,o.jsx)(`th`,{className:`py-2`,children:e(`extensionDebug.colPermissions`)})]})}),(0,o.jsx)(`tbody`,{children:c.map(e=>(0,o.jsxs)(`tr`,{className:`border-b border-edge-subtle`,children:[(0,o.jsx)(`td`,{className:`py-2 pr-2 font-mono text-xs text-fg`,children:e.id}),(0,o.jsx)(`td`,{className:`py-2 pr-2 text-fg`,children:e.name}),(0,o.jsx)(`td`,{className:`py-2 font-mono text-xs text-fg-muted`,children:(e.ui?.permissions??[]).join(`, `)||`—`})]},e.id))})]})})]}),(0,o.jsxs)(`section`,{className:`rounded-xl border border-dashed border-edge-subtle bg-surface-muted/50 p-4 text-sm text-fg-muted`,children:[(0,o.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:e(`extensionDebug.futureHeading`)}),(0,o.jsx)(`p`,{className:`mt-2`,children:e(`extensionDebug.futureBody`)})]})]})}function l(){try{let e=localStorage.getItem(s);if(!e)return`{}`;let t=JSON.parse(e);return JSON.stringify(t,null,2)}catch(e){return e instanceof Error?e.message:String(e)}}export{c as ExtensionDebugPage};
2
- //# sourceMappingURL=extension-debug-page-DTz4O5Ua.js.map
1
+ import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{i as t,t as n}from"./vendor-react-QAsRxa6t.js";import{t as r}from"./useTranslation-CACj0DBJ.js";import{i}from"./extension-provider-DZCZgQE2.js";var a=e(t(),1),o=n(),s=`xopc.extensionUiGrants.v1`;function c(){let{t:e}=r(),t=i(),[n,s]=(0,a.useState)(()=>l()),c=(0,a.useMemo)(()=>[...t].sort((e,t)=>e.id.localeCompare(t.id)),[t]);return(0,o.jsxs)(`div`,{className:`mx-auto flex w-full max-w-app-main flex-col gap-6 px-4 py-8`,children:[(0,o.jsxs)(`div`,{children:[(0,o.jsx)(`h1`,{className:`text-lg font-semibold text-fg`,children:e(`extensionDebug.title`)}),(0,o.jsx)(`p`,{className:`mt-1 text-sm text-fg-muted`,children:e(`extensionDebug.subtitle`)})]}),(0,o.jsxs)(`section`,{className:`rounded-xl border border-edge bg-surface-base p-4`,children:[(0,o.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:e(`extensionDebug.grantsHeading`)}),(0,o.jsx)(`p`,{className:`mt-1 text-xs text-fg-muted`,children:e(`extensionDebug.grantsHint`)}),(0,o.jsx)(`pre`,{className:`mt-3 max-h-48 overflow-auto rounded-lg border border-edge-subtle bg-surface-muted p-3 font-mono text-xs text-fg`,children:n}),(0,o.jsx)(`button`,{type:`button`,className:`mt-3 rounded-lg border border-edge px-3 py-1.5 text-xs font-medium text-fg hover:bg-surface-hover`,onClick:()=>s(l()),children:e(`extensionDebug.refresh`)})]}),(0,o.jsxs)(`section`,{className:`rounded-xl border border-edge bg-surface-base p-4`,children:[(0,o.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:e(`extensionDebug.listHeading`)}),(0,o.jsx)(`div`,{className:`mt-3 overflow-x-auto`,children:(0,o.jsxs)(`table`,{className:`w-full min-w-[32rem] border-collapse text-left text-sm`,children:[(0,o.jsx)(`thead`,{children:(0,o.jsxs)(`tr`,{className:`border-b border-edge text-xs uppercase text-fg-muted`,children:[(0,o.jsx)(`th`,{className:`py-2 pr-2`,children:e(`extensionDebug.colId`)}),(0,o.jsx)(`th`,{className:`py-2 pr-2`,children:e(`extensionDebug.colName`)}),(0,o.jsx)(`th`,{className:`py-2`,children:e(`extensionDebug.colPermissions`)})]})}),(0,o.jsx)(`tbody`,{children:c.map(e=>(0,o.jsxs)(`tr`,{className:`border-b border-edge-subtle`,children:[(0,o.jsx)(`td`,{className:`py-2 pr-2 font-mono text-xs text-fg`,children:e.id}),(0,o.jsx)(`td`,{className:`py-2 pr-2 text-fg`,children:e.name}),(0,o.jsx)(`td`,{className:`py-2 font-mono text-xs text-fg-muted`,children:(e.ui?.permissions??[]).join(`, `)||`—`})]},e.id))})]})})]}),(0,o.jsxs)(`section`,{className:`rounded-xl border border-dashed border-edge-subtle bg-surface-muted/50 p-4 text-sm text-fg-muted`,children:[(0,o.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:e(`extensionDebug.futureHeading`)}),(0,o.jsx)(`p`,{className:`mt-2`,children:e(`extensionDebug.futureBody`)})]})]})}function l(){try{let e=localStorage.getItem(s);if(!e)return`{}`;let t=JSON.parse(e);return JSON.stringify(t,null,2)}catch(e){return e instanceof Error?e.message:String(e)}}export{c as ExtensionDebugPage};
2
+ //# sourceMappingURL=extension-debug-page-BMcZlaxF.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension-debug-page-DTz4O5Ua.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-debug-page.tsx"],"sourcesContent":["/**\n * Extension debug — Settings panel: extension list, declared permissions, UI grant fingerprints.\n */\n\nimport { useMemo, useState } from 'react';\n\nimport { useTranslation } from 'react-i18next';\n\nimport { useExtensions } from '@/features/extensions/extension-provider';\n\nconst GRANTS_STORAGE_KEY = 'xopc.extensionUiGrants.v1';\n\nexport function ExtensionDebugPage() {\n const { t } = useTranslation();\n const extensions = useExtensions();\n const [grantsRaw, setGrantsRaw] = useState(() => readGrantsSafe());\n\n const sorted = useMemo(\n () => [...extensions].sort((a, b) => a.id.localeCompare(b.id)),\n [extensions],\n );\n\n return (\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-6 px-4 py-8\">\n <div>\n <h1 className=\"text-lg font-semibold text-fg\">{t('extensionDebug.title')}</h1>\n <p className=\"mt-1 text-sm text-fg-muted\">{t('extensionDebug.subtitle')}</p>\n </div>\n\n <section className=\"rounded-xl border border-edge bg-surface-base p-4\">\n <h2 className=\"text-sm font-semibold text-fg\">{t('extensionDebug.grantsHeading')}</h2>\n <p className=\"mt-1 text-xs text-fg-muted\">{t('extensionDebug.grantsHint')}</p>\n <pre className=\"mt-3 max-h-48 overflow-auto rounded-lg border border-edge-subtle bg-surface-muted p-3 font-mono text-xs text-fg\">\n {grantsRaw}\n </pre>\n <button\n type=\"button\"\n className=\"mt-3 rounded-lg border border-edge px-3 py-1.5 text-xs font-medium text-fg hover:bg-surface-hover\"\n onClick={() => setGrantsRaw(readGrantsSafe())}\n >\n {t('extensionDebug.refresh')}\n </button>\n </section>\n\n <section className=\"rounded-xl border border-edge bg-surface-base p-4\">\n <h2 className=\"text-sm font-semibold text-fg\">{t('extensionDebug.listHeading')}</h2>\n <div className=\"mt-3 overflow-x-auto\">\n <table className=\"w-full min-w-[32rem] border-collapse text-left text-sm\">\n <thead>\n <tr className=\"border-b border-edge text-xs uppercase text-fg-muted\">\n <th className=\"py-2 pr-2\">{t('extensionDebug.colId')}</th>\n <th className=\"py-2 pr-2\">{t('extensionDebug.colName')}</th>\n <th className=\"py-2\">{t('extensionDebug.colPermissions')}</th>\n </tr>\n </thead>\n <tbody>\n {sorted.map((e) => (\n <tr key={e.id} className=\"border-b border-edge-subtle\">\n <td className=\"py-2 pr-2 font-mono text-xs text-fg\">{e.id}</td>\n <td className=\"py-2 pr-2 text-fg\">{e.name}</td>\n <td className=\"py-2 font-mono text-xs text-fg-muted\">\n {(e.ui?.permissions ?? []).join(', ') || '—'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </section>\n\n <section className=\"rounded-xl border border-dashed border-edge-subtle bg-surface-muted/50 p-4 text-sm text-fg-muted\">\n <h2 className=\"text-sm font-semibold text-fg\">{t('extensionDebug.futureHeading')}</h2>\n <p className=\"mt-2\">{t('extensionDebug.futureBody')}</p>\n </section>\n </div>\n );\n}\n\nfunction readGrantsSafe(): string {\n try {\n const raw = localStorage.getItem(GRANTS_STORAGE_KEY);\n if (!raw) return '{}';\n const parsed = JSON.parse(raw) as unknown;\n return JSON.stringify(parsed, null, 2);\n } catch (e) {\n return e instanceof Error ? e.message : String(e);\n }\n}\n"],"mappings":"+NAUM,EAAqB,4BAE3B,SAAgB,GAAqB,CACnC,GAAM,CAAE,KAAM,GAAgB,CACxB,EAAa,GAAe,CAC5B,CAAC,EAAW,IAAA,EAAA,EAAA,cAA+B,GAAgB,CAAC,CAE5D,GAAA,EAAA,EAAA,aACE,CAAC,GAAG,EAAW,CAAC,MAAM,EAAG,IAAM,EAAE,GAAG,cAAc,EAAE,GAAG,CAAC,CAC9D,CAAC,EAAW,CACb,CAED,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,uEAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,uBAAuB,CAAM,CAAA,EAC9E,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,sCAA8B,EAAE,0BAA0B,CAAK,CAAA,CACxE,CAAA,CAAA,EAEN,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,6DAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,+BAA+B,CAAM,CAAA,EACtF,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,sCAA8B,EAAE,4BAA4B,CAAK,CAAA,EAC9E,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,2HACZ,EACG,CAAA,EACN,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,UAAU,oGACV,YAAe,EAAa,GAAgB,CAAC,UAE5C,EAAE,yBAAyB,CACrB,CAAA,CACD,IAEV,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,6DAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,6BAA6B,CAAM,CAAA,EACpF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iCACb,EAAA,EAAA,MAAC,QAAD,CAAO,UAAU,kEAAjB,EACE,EAAA,EAAA,KAAC,QAAD,CAAA,UACE,EAAA,EAAA,MAAC,KAAD,CAAI,UAAU,gEAAd,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,qBAAa,EAAE,uBAAuB,CAAM,CAAA,EAC1D,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,qBAAa,EAAE,yBAAyB,CAAM,CAAA,EAC5D,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,gBAAQ,EAAE,gCAAgC,CAAM,CAAA,CAC3D,GACC,CAAA,EACR,EAAA,EAAA,KAAC,QAAD,CAAA,SACG,EAAO,IAAK,IACX,EAAA,EAAA,MAAC,KAAD,CAAe,UAAU,uCAAzB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,+CAAuC,EAAE,GAAQ,CAAA,EAC/D,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,6BAAqB,EAAE,KAAU,CAAA,EAC/C,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,iDACV,EAAE,IAAI,aAAe,EAAE,EAAE,KAAK,KAAK,EAAI,IACtC,CAAA,CACF,EANI,EAAE,GAMN,CACL,CACI,CAAA,CACF,GACJ,CAAA,CACE,IAEV,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,4GAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,+BAA+B,CAAM,CAAA,EACtF,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,gBAAQ,EAAE,4BAA4B,CAAK,CAAA,CAChD,GACN,GAIV,SAAS,GAAyB,CAChC,GAAI,CACF,IAAM,EAAM,aAAa,QAAQ,EAAmB,CACpD,GAAI,CAAC,EAAK,MAAO,KACjB,IAAM,EAAS,KAAK,MAAM,EAAI,CAC9B,OAAO,KAAK,UAAU,EAAQ,KAAM,EAAE,OAC/B,EAAG,CACV,OAAO,aAAa,MAAQ,EAAE,QAAU,OAAO,EAAE"}
1
+ {"version":3,"file":"extension-debug-page-BMcZlaxF.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-debug-page.tsx"],"sourcesContent":["/**\n * Extension debug — Settings panel: extension list, declared permissions, UI grant fingerprints.\n */\n\nimport { useMemo, useState } from 'react';\n\nimport { useTranslation } from 'react-i18next';\n\nimport { useExtensions } from '@/features/extensions/extension-provider';\n\nconst GRANTS_STORAGE_KEY = 'xopc.extensionUiGrants.v1';\n\nexport function ExtensionDebugPage() {\n const { t } = useTranslation();\n const extensions = useExtensions();\n const [grantsRaw, setGrantsRaw] = useState(() => readGrantsSafe());\n\n const sorted = useMemo(\n () => [...extensions].sort((a, b) => a.id.localeCompare(b.id)),\n [extensions],\n );\n\n return (\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-6 px-4 py-8\">\n <div>\n <h1 className=\"text-lg font-semibold text-fg\">{t('extensionDebug.title')}</h1>\n <p className=\"mt-1 text-sm text-fg-muted\">{t('extensionDebug.subtitle')}</p>\n </div>\n\n <section className=\"rounded-xl border border-edge bg-surface-base p-4\">\n <h2 className=\"text-sm font-semibold text-fg\">{t('extensionDebug.grantsHeading')}</h2>\n <p className=\"mt-1 text-xs text-fg-muted\">{t('extensionDebug.grantsHint')}</p>\n <pre className=\"mt-3 max-h-48 overflow-auto rounded-lg border border-edge-subtle bg-surface-muted p-3 font-mono text-xs text-fg\">\n {grantsRaw}\n </pre>\n <button\n type=\"button\"\n className=\"mt-3 rounded-lg border border-edge px-3 py-1.5 text-xs font-medium text-fg hover:bg-surface-hover\"\n onClick={() => setGrantsRaw(readGrantsSafe())}\n >\n {t('extensionDebug.refresh')}\n </button>\n </section>\n\n <section className=\"rounded-xl border border-edge bg-surface-base p-4\">\n <h2 className=\"text-sm font-semibold text-fg\">{t('extensionDebug.listHeading')}</h2>\n <div className=\"mt-3 overflow-x-auto\">\n <table className=\"w-full min-w-[32rem] border-collapse text-left text-sm\">\n <thead>\n <tr className=\"border-b border-edge text-xs uppercase text-fg-muted\">\n <th className=\"py-2 pr-2\">{t('extensionDebug.colId')}</th>\n <th className=\"py-2 pr-2\">{t('extensionDebug.colName')}</th>\n <th className=\"py-2\">{t('extensionDebug.colPermissions')}</th>\n </tr>\n </thead>\n <tbody>\n {sorted.map((e) => (\n <tr key={e.id} className=\"border-b border-edge-subtle\">\n <td className=\"py-2 pr-2 font-mono text-xs text-fg\">{e.id}</td>\n <td className=\"py-2 pr-2 text-fg\">{e.name}</td>\n <td className=\"py-2 font-mono text-xs text-fg-muted\">\n {(e.ui?.permissions ?? []).join(', ') || '—'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </section>\n\n <section className=\"rounded-xl border border-dashed border-edge-subtle bg-surface-muted/50 p-4 text-sm text-fg-muted\">\n <h2 className=\"text-sm font-semibold text-fg\">{t('extensionDebug.futureHeading')}</h2>\n <p className=\"mt-2\">{t('extensionDebug.futureBody')}</p>\n </section>\n </div>\n );\n}\n\nfunction readGrantsSafe(): string {\n try {\n const raw = localStorage.getItem(GRANTS_STORAGE_KEY);\n if (!raw) return '{}';\n const parsed = JSON.parse(raw) as unknown;\n return JSON.stringify(parsed, null, 2);\n } catch (e) {\n return e instanceof Error ? e.message : String(e);\n }\n}\n"],"mappings":"+NAUM,EAAqB,4BAE3B,SAAgB,GAAqB,CACnC,GAAM,CAAE,KAAM,GAAgB,CACxB,EAAa,GAAe,CAC5B,CAAC,EAAW,IAAA,EAAA,EAAA,cAA+B,GAAgB,CAAC,CAE5D,GAAA,EAAA,EAAA,aACE,CAAC,GAAG,EAAW,CAAC,MAAM,EAAG,IAAM,EAAE,GAAG,cAAc,EAAE,GAAG,CAAC,CAC9D,CAAC,EAAW,CACb,CAED,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,uEAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,uBAAuB,CAAM,CAAA,EAC9E,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,sCAA8B,EAAE,0BAA0B,CAAK,CAAA,CACxE,CAAA,CAAA,EAEN,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,6DAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,+BAA+B,CAAM,CAAA,EACtF,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,sCAA8B,EAAE,4BAA4B,CAAK,CAAA,EAC9E,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,2HACZ,EACG,CAAA,EACN,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,UAAU,oGACV,YAAe,EAAa,GAAgB,CAAC,UAE5C,EAAE,yBAAyB,CACrB,CAAA,CACD,IAEV,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,6DAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,6BAA6B,CAAM,CAAA,EACpF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iCACb,EAAA,EAAA,MAAC,QAAD,CAAO,UAAU,kEAAjB,EACE,EAAA,EAAA,KAAC,QAAD,CAAA,UACE,EAAA,EAAA,MAAC,KAAD,CAAI,UAAU,gEAAd,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,qBAAa,EAAE,uBAAuB,CAAM,CAAA,EAC1D,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,qBAAa,EAAE,yBAAyB,CAAM,CAAA,EAC5D,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,gBAAQ,EAAE,gCAAgC,CAAM,CAAA,CAC3D,GACC,CAAA,EACR,EAAA,EAAA,KAAC,QAAD,CAAA,SACG,EAAO,IAAK,IACX,EAAA,EAAA,MAAC,KAAD,CAAe,UAAU,uCAAzB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,+CAAuC,EAAE,GAAQ,CAAA,EAC/D,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,6BAAqB,EAAE,KAAU,CAAA,EAC/C,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,iDACV,EAAE,IAAI,aAAe,EAAE,EAAE,KAAK,KAAK,EAAI,IACtC,CAAA,CACF,EANI,EAAE,GAMN,CACL,CACI,CAAA,CACF,GACJ,CAAA,CACE,IAEV,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,4GAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,+BAA+B,CAAM,CAAA,EACtF,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,gBAAQ,EAAE,4BAA4B,CAAK,CAAA,CAChD,GACN,GAIV,SAAS,GAAyB,CAChC,GAAI,CACF,IAAM,EAAM,aAAa,QAAQ,EAAmB,CACpD,GAAI,CAAC,EAAK,MAAO,KACjB,IAAM,EAAS,KAAK,MAAM,EAAI,CAC9B,OAAO,KAAK,UAAU,EAAQ,KAAM,EAAE,OAC/B,EAAG,CACV,OAAO,aAAa,MAAQ,EAAE,QAAU,OAAO,EAAE"}
@@ -1,2 +1,2 @@
1
- import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{i as t,t as n}from"./vendor-react-QAsRxa6t.js";import{o as r,s as i,t as a}from"./url-CtSqjF9J.js";import{t as o}from"./useTranslation-DYORQ7x6.js";import{a as s,i as c,n as l,o as u,s as d,t as f}from"./dist-Db1dcLr9.js";import{i as p}from"./theme-store-CmiSsYBd.js";import{r as m,s as h}from"./extension-provider-CO2jxBA9.js";var g=e(t(),1),_=`xopc.extensionUiGrants.v1`;function v(e){return[...e].map(e=>e.trim()).filter(Boolean).sort().join(`\0`)}function y(e,t){try{let n=localStorage.getItem(_);return(n?JSON.parse(n):{})[e]===v(t)}catch{return!1}}function b(e,t){let n=localStorage.getItem(_),r=(n?JSON.parse(n):{})??{};r[e]=v(t),localStorage.setItem(_,JSON.stringify(r))}var x={theme:`Read theme (light / dark)`,"agent.send":`Send messages to the assistant`,"agent.subscribe":`Receive live agent stream events for a chat`,"session.read":`List and open chat sessions`,"session.write":`Modify chat sessions`,"config.read":`Read extension configuration`,"config.write":`Write extension configuration`,storage:`Read and write extension storage`,notification:`Show in-app notifications`,clipboard:`Use the clipboard`,"workspace.read":`Read workspace files`,"workspace.write":`Write workspace files`},S={theme:`读取主题(浅色/深色)`,"agent.send":`向助手发送消息`,"agent.subscribe":`接收会话的实时助手流式事件`,"session.read":`列出并打开聊天会话`,"session.write":`修改聊天会话`,"config.read":`读取扩展配置`,"config.write":`写入扩展配置`,storage:`读写扩展存储`,notification:`显示应用内通知`,clipboard:`使用剪贴板`,"workspace.read":`读取工作区文件`,"workspace.write":`写入工作区文件`};function C(e,t){let n=x[e];return t===`zh`&&S[e]?S[e]:n??e}var w=n();function T({open:e,onOpenChange:t,extensionId:n,extensionName:r,permissions:a,onConfirm:p}){let{t:m}=o(),h=i(e=>e.language);return(0,w.jsx)(u,{open:e,onOpenChange:t,children:(0,w.jsxs)(s,{children:[(0,w.jsx)(c,{className:`xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim`}),(0,w.jsxs)(l,{className:`fixed left-1/2 top-1/2 z-[131] w-[min(28rem,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-edge bg-surface-panel p-5 shadow-elevated`,onOpenAutoFocus:e=>e.preventDefault(),children:[(0,w.jsx)(d,{className:`text-base font-semibold text-fg`,children:m(`extensionUi.permissionTitle`,{name:r})}),(0,w.jsxs)(`p`,{className:`mt-2 text-sm text-fg-muted`,children:[m(`extensionUi.permissionSubtitle`),` `,(0,w.jsxs)(`span`,{className:`font-mono text-xs text-fg-muted`,title:n,children:[`(`,n,`)`]})]}),a.length===0?(0,w.jsx)(`p`,{className:`mt-4 text-sm text-fg-muted`,children:m(`extensionUi.permissionsNone`)}):(0,w.jsx)(`ul`,{className:`mt-4 max-h-48 list-inside list-disc space-y-1 overflow-y-auto text-sm text-fg`,children:a.map(e=>(0,w.jsx)(`li`,{children:C(e,h)},e))}),(0,w.jsxs)(`div`,{className:`mt-6 flex justify-end gap-2`,children:[(0,w.jsx)(f,{asChild:!0,children:(0,w.jsx)(`button`,{type:`button`,className:`rounded-lg border border-edge px-3 py-2 text-sm text-fg hover:bg-surface-muted`,children:m(`extensionUi.deny`)})}),(0,w.jsx)(`button`,{type:`button`,className:`rounded-lg bg-accent px-3 py-2 text-sm font-medium text-white hover:opacity-90`,onClick:()=>{p(),t(!1)},children:m(`extensionUi.allow`)})]})]})]})})}var E=48,D=2e3,O=`allow-scripts allow-forms allow-popups`;function k(e){return e.split(`/`).filter(Boolean).map(e=>encodeURIComponent(e)).join(`/`)}function A({extensionId:e,extensionName:t,entrypoint:n,permissions:s,title:c,className:l,fixedHeight:u,maxHeight:d=D,minHeight:f=E,initialData:_}){let{t:v}=o(),x=m(),S=(0,g.useRef)(null),C=r(e=>e.token),A=p(e=>e.resolved),j=t?.trim()||e,M=(0,g.useMemo)(()=>JSON.stringify([...s??[]].sort()),[s]),N=(0,g.useMemo)(()=>JSON.parse(M),[M]),[P,F]=(0,g.useState)(()=>y(e,N)),[I,L]=(0,g.useState)(()=>!y(e,N));(0,g.useEffect)(()=>{let t=y(e,s??[]);F(t),L(!t)},[e,M]);let[R,z]=(0,g.useState)(0),[B,V]=(0,g.useState)(!1),[H,U]=(0,g.useState)(u??Math.min(d,Math.max(f,320))),W=(0,g.useMemo)(()=>{let t=k(n),r=a(`/api/extensions/${encodeURIComponent(e)}/assets/${t}`);if(!C?.trim())return r;let i=new URL(r);return i.searchParams.set(`token`,C.trim()),i.toString()},[e,n,C]);(0,g.useLayoutEffect)(()=>{if(!P)return;let t=S.current;if(t)return x.registerIframe(e,t,N),()=>x.unregisterIframe(e)},[P,e,N,x]),(0,g.useEffect)(()=>{if(P)return x.subscribeExtensionEvents(e,e=>{if(e.event!==`ui.resize`||!e.data||typeof e.data!=`object`||e.data===null)return;let t=Number(e.data.height);Number.isFinite(t)&&u===void 0&&U(Math.min(d,Math.max(f,t)))})},[P,e,u,d,f,x]),(0,g.useEffect)(()=>{if(!P)return;let t=h(A);x.sendEvent(e,`theme.changed`,t)},[P,e,A,x]);let G=u===void 0?{width:`100%`,height:H,border:`none`}:{width:`100%`,height:u,border:`none`};return P?(0,w.jsxs)(`div`,{className:`flex flex-1 min-h-0 min-w-0 flex-col`,children:[B?(0,w.jsxs)(`div`,{className:`mb-2 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm text-fg`,children:[(0,w.jsx)(`p`,{children:v(`extensionUi.loadFailed`)}),(0,w.jsx)(`p`,{className:`mt-2 text-xs text-fg-muted`,children:v(`extensionUi.loadFailedConnectionHint`)}),(0,w.jsx)(`button`,{type:`button`,className:`mt-2 font-medium text-accent underline-offset-2 hover:underline`,onClick:()=>{V(!1),z(e=>e+1)},children:v(`extensionUi.retryLoad`)})]}):null,(0,w.jsx)(`iframe`,{ref:S,className:l,title:c??`Extension ${e}`,src:W,style:G,sandbox:O,referrerPolicy:`no-referrer`,onError:()=>V(!0),onLoad:()=>{V(!1);let t=i.getState().language;x.sendInit(e,h(p.getState().resolved),t),_!==void 0&&x.sendEvent(e,`widget.data`,_)}},`${e}-${n}-${R}`)]}):(0,w.jsxs)(w.Fragment,{children:[(0,w.jsx)(T,{open:I,onOpenChange:L,extensionId:e,extensionName:j,permissions:N,onConfirm:()=>{b(e,N),F(!0)}}),I?null:(0,w.jsxs)(`div`,{className:l?`${l} rounded-lg border border-edge border-dashed bg-surface-base p-4 text-sm text-fg-muted`:`rounded-lg border border-edge border-dashed bg-surface-base p-4 text-sm text-fg-muted`,children:[(0,w.jsx)(`p`,{children:v(`extensionUi.deniedHint`)}),(0,w.jsx)(`button`,{type:`button`,className:`mt-2 text-sm font-medium text-accent underline-offset-2 hover:underline`,onClick:()=>L(!0),children:v(`extensionUi.reviewPermissions`)})]})]})}export{A as t};
2
- //# sourceMappingURL=extension-iframe-host-Cs1Kde9o.js.map
1
+ import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{i as t,t as n}from"./vendor-react-QAsRxa6t.js";import{o as r,s as i,t as a}from"./url-D7yWllI8.js";import{t as o}from"./useTranslation-CACj0DBJ.js";import{a as s,i as c,n as l,o as u,s as d,t as f}from"./dist-Db1dcLr9.js";import{i as p}from"./theme-store-CywXkKml.js";import{r as m,s as h}from"./extension-provider-DZCZgQE2.js";var g=e(t(),1),_=`xopc.extensionUiGrants.v1`;function v(e){return[...e].map(e=>e.trim()).filter(Boolean).sort().join(`\0`)}function y(e,t){try{let n=localStorage.getItem(_);return(n?JSON.parse(n):{})[e]===v(t)}catch{return!1}}function b(e,t){let n=localStorage.getItem(_),r=(n?JSON.parse(n):{})??{};r[e]=v(t),localStorage.setItem(_,JSON.stringify(r))}var x={theme:`Read theme (light / dark)`,"agent.send":`Send messages to the assistant`,"agent.subscribe":`Receive live agent stream events for a chat`,"session.read":`List and open chat sessions`,"session.write":`Modify chat sessions`,"config.read":`Read extension configuration`,"config.write":`Write extension configuration`,storage:`Read and write extension storage`,notification:`Show in-app notifications`,clipboard:`Use the clipboard`,"workspace.read":`Read workspace files`,"workspace.write":`Write workspace files`},S={theme:`读取主题(浅色/深色)`,"agent.send":`向助手发送消息`,"agent.subscribe":`接收会话的实时助手流式事件`,"session.read":`列出并打开聊天会话`,"session.write":`修改聊天会话`,"config.read":`读取扩展配置`,"config.write":`写入扩展配置`,storage:`读写扩展存储`,notification:`显示应用内通知`,clipboard:`使用剪贴板`,"workspace.read":`读取工作区文件`,"workspace.write":`写入工作区文件`};function C(e,t){let n=x[e];return t===`zh`&&S[e]?S[e]:n??e}var w=n();function T({open:e,onOpenChange:t,extensionId:n,extensionName:r,permissions:a,onConfirm:p}){let{t:m}=o(),h=i(e=>e.language);return(0,w.jsx)(u,{open:e,onOpenChange:t,children:(0,w.jsxs)(s,{children:[(0,w.jsx)(c,{className:`xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim`}),(0,w.jsxs)(l,{className:`fixed left-1/2 top-1/2 z-[131] w-[min(28rem,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-edge bg-surface-panel p-5 shadow-elevated`,onOpenAutoFocus:e=>e.preventDefault(),children:[(0,w.jsx)(d,{className:`text-base font-semibold text-fg`,children:m(`extensionUi.permissionTitle`,{name:r})}),(0,w.jsxs)(`p`,{className:`mt-2 text-sm text-fg-muted`,children:[m(`extensionUi.permissionSubtitle`),` `,(0,w.jsxs)(`span`,{className:`font-mono text-xs text-fg-muted`,title:n,children:[`(`,n,`)`]})]}),a.length===0?(0,w.jsx)(`p`,{className:`mt-4 text-sm text-fg-muted`,children:m(`extensionUi.permissionsNone`)}):(0,w.jsx)(`ul`,{className:`mt-4 max-h-48 list-inside list-disc space-y-1 overflow-y-auto text-sm text-fg`,children:a.map(e=>(0,w.jsx)(`li`,{children:C(e,h)},e))}),(0,w.jsxs)(`div`,{className:`mt-6 flex justify-end gap-2`,children:[(0,w.jsx)(f,{asChild:!0,children:(0,w.jsx)(`button`,{type:`button`,className:`rounded-lg border border-edge px-3 py-2 text-sm text-fg hover:bg-surface-muted`,children:m(`extensionUi.deny`)})}),(0,w.jsx)(`button`,{type:`button`,className:`rounded-lg bg-accent px-3 py-2 text-sm font-medium text-white hover:opacity-90`,onClick:()=>{p(),t(!1)},children:m(`extensionUi.allow`)})]})]})]})})}var E=48,D=2e3,O=`allow-scripts allow-forms allow-popups`;function k(e){return e.split(`/`).filter(Boolean).map(e=>encodeURIComponent(e)).join(`/`)}function A({extensionId:e,extensionName:t,entrypoint:n,permissions:s,title:c,className:l,fixedHeight:u,maxHeight:d=D,minHeight:f=E,initialData:_}){let{t:v}=o(),x=m(),S=(0,g.useRef)(null),C=r(e=>e.token),A=p(e=>e.resolved),j=t?.trim()||e,M=(0,g.useMemo)(()=>JSON.stringify([...s??[]].sort()),[s]),N=(0,g.useMemo)(()=>JSON.parse(M),[M]),[P,F]=(0,g.useState)(()=>y(e,N)),[I,L]=(0,g.useState)(()=>!y(e,N));(0,g.useEffect)(()=>{let t=y(e,s??[]);F(t),L(!t)},[e,M]);let[R,z]=(0,g.useState)(0),[B,V]=(0,g.useState)(!1),[H,U]=(0,g.useState)(u??Math.min(d,Math.max(f,320))),W=(0,g.useMemo)(()=>{let t=k(n),r=a(`/api/extensions/${encodeURIComponent(e)}/assets/${t}`);if(!C?.trim())return r;let i=new URL(r);return i.searchParams.set(`token`,C.trim()),i.toString()},[e,n,C]);(0,g.useLayoutEffect)(()=>{if(!P)return;let t=S.current;if(t)return x.registerIframe(e,t,N),()=>x.unregisterIframe(e)},[P,e,N,x]),(0,g.useEffect)(()=>{if(P)return x.subscribeExtensionEvents(e,e=>{if(e.event!==`ui.resize`||!e.data||typeof e.data!=`object`||e.data===null)return;let t=Number(e.data.height);Number.isFinite(t)&&u===void 0&&U(Math.min(d,Math.max(f,t)))})},[P,e,u,d,f,x]),(0,g.useEffect)(()=>{if(!P)return;let t=h(A);x.sendEvent(e,`theme.changed`,t)},[P,e,A,x]);let G=u===void 0?{width:`100%`,height:H,border:`none`}:{width:`100%`,height:u,border:`none`};return P?(0,w.jsxs)(`div`,{className:`flex flex-1 min-h-0 min-w-0 flex-col`,children:[B?(0,w.jsxs)(`div`,{className:`mb-2 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm text-fg`,children:[(0,w.jsx)(`p`,{children:v(`extensionUi.loadFailed`)}),(0,w.jsx)(`p`,{className:`mt-2 text-xs text-fg-muted`,children:v(`extensionUi.loadFailedConnectionHint`)}),(0,w.jsx)(`button`,{type:`button`,className:`mt-2 font-medium text-accent underline-offset-2 hover:underline`,onClick:()=>{V(!1),z(e=>e+1)},children:v(`extensionUi.retryLoad`)})]}):null,(0,w.jsx)(`iframe`,{ref:S,className:l,title:c??`Extension ${e}`,src:W,style:G,sandbox:O,referrerPolicy:`no-referrer`,onError:()=>V(!0),onLoad:()=>{V(!1);let t=i.getState().language;x.sendInit(e,h(p.getState().resolved),t),_!==void 0&&x.sendEvent(e,`widget.data`,_)}},`${e}-${n}-${R}`)]}):(0,w.jsxs)(w.Fragment,{children:[(0,w.jsx)(T,{open:I,onOpenChange:L,extensionId:e,extensionName:j,permissions:N,onConfirm:()=>{b(e,N),F(!0)}}),I?null:(0,w.jsxs)(`div`,{className:l?`${l} rounded-lg border border-edge border-dashed bg-surface-base p-4 text-sm text-fg-muted`:`rounded-lg border border-edge border-dashed bg-surface-base p-4 text-sm text-fg-muted`,children:[(0,w.jsx)(`p`,{children:v(`extensionUi.deniedHint`)}),(0,w.jsx)(`button`,{type:`button`,className:`mt-2 text-sm font-medium text-accent underline-offset-2 hover:underline`,onClick:()=>L(!0),children:v(`extensionUi.reviewPermissions`)})]})]})}export{A as t};
2
+ //# sourceMappingURL=extension-iframe-host-D5HEF0KR.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension-iframe-host-Cs1Kde9o.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-permission-grants.ts","../../../../../web/src/features/extensions/extension-permission-dialog.tsx","../../../../../web/src/features/extensions/extension-iframe-host.tsx"],"sourcesContent":["const STORAGE_KEY = 'xopc.extensionUiGrants.v1';\n\nfunction permissionFingerprint(permissions: string[]): string {\n return [...permissions].map((p) => p.trim()).filter(Boolean).sort().join('\\0');\n}\n\nexport function hasUiGrant(extensionId: string, permissions: string[]): boolean {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n const map = (raw ? JSON.parse(raw) : {}) as Record<string, string>;\n return map[extensionId] === permissionFingerprint(permissions);\n } catch {\n return false;\n }\n}\n\nexport function saveUiGrant(extensionId: string, permissions: string[]): void {\n const raw = localStorage.getItem(STORAGE_KEY);\n const map = (raw ? (JSON.parse(raw) as Record<string, string>) : {}) ?? {};\n map[extensionId] = permissionFingerprint(permissions);\n localStorage.setItem(STORAGE_KEY, JSON.stringify(map));\n}\n\n/** Short human labels for manifest `ui.permissions` (EN). */\nconst PERMISSION_LABELS_EN: Record<string, string> = {\n theme: 'Read theme (light / dark)',\n 'agent.send': 'Send messages to the assistant',\n 'agent.subscribe': 'Receive live agent stream events for a chat',\n 'session.read': 'List and open chat sessions',\n 'session.write': 'Modify chat sessions',\n 'config.read': 'Read extension configuration',\n 'config.write': 'Write extension configuration',\n storage: 'Read and write extension storage',\n notification: 'Show in-app notifications',\n clipboard: 'Use the clipboard',\n 'workspace.read': 'Read workspace files',\n 'workspace.write': 'Write workspace files',\n};\n\nconst PERMISSION_LABELS_ZH: Record<string, string> = {\n theme: '读取主题(浅色/深色)',\n 'agent.send': '向助手发送消息',\n 'agent.subscribe': '接收会话的实时助手流式事件',\n 'session.read': '列出并打开聊天会话',\n 'session.write': '修改聊天会话',\n 'config.read': '读取扩展配置',\n 'config.write': '写入扩展配置',\n storage: '读写扩展存储',\n notification: '显示应用内通知',\n clipboard: '使用剪贴板',\n 'workspace.read': '读取工作区文件',\n 'workspace.write': '写入工作区文件',\n};\n\nexport function describePermission(permission: string, language: string): string {\n const en = PERMISSION_LABELS_EN[permission];\n if (language === 'zh' && PERMISSION_LABELS_ZH[permission]) {\n return PERMISSION_LABELS_ZH[permission];\n }\n return en ?? permission;\n}\n","import * as Dialog from '@radix-ui/react-dialog';\nimport { useTranslation } from 'react-i18next';\n\nimport { useLocaleStore } from '@/stores/locale-store';\n\nimport { describePermission } from './extension-permission-grants';\n\ntype ExtensionPermissionDialogProps = {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n extensionId: string;\n extensionName: string;\n permissions: string[];\n onConfirm: () => void;\n};\n\nexport function ExtensionPermissionDialog({\n open,\n onOpenChange,\n extensionId,\n extensionName,\n permissions,\n onConfirm,\n}: ExtensionPermissionDialogProps) {\n const { t } = useTranslation();\n const language = useLocaleStore((s) => s.language);\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\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] w-[min(28rem,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-edge bg-surface-panel p-5 shadow-elevated\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <Dialog.Title className=\"text-base font-semibold text-fg\">\n {t('extensionUi.permissionTitle', { name: extensionName })}\n </Dialog.Title>\n <p className=\"mt-2 text-sm text-fg-muted\">\n {t('extensionUi.permissionSubtitle')}{' '}\n <span className=\"font-mono text-xs text-fg-muted\" title={extensionId}>\n ({extensionId})\n </span>\n </p>\n {permissions.length === 0 ? (\n <p className=\"mt-4 text-sm text-fg-muted\">{t('extensionUi.permissionsNone')}</p>\n ) : (\n <ul className=\"mt-4 max-h-48 list-inside list-disc space-y-1 overflow-y-auto text-sm text-fg\">\n {permissions.map((p) => (\n <li key={p}>{describePermission(p, language)}</li>\n ))}\n </ul>\n )}\n <div className=\"mt-6 flex justify-end gap-2\">\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className=\"rounded-lg border border-edge px-3 py-2 text-sm text-fg hover:bg-surface-muted\"\n >\n {t('extensionUi.deny')}\n </button>\n </Dialog.Close>\n <button\n type=\"button\"\n className=\"rounded-lg bg-accent px-3 py-2 text-sm font-medium text-white hover:opacity-90\"\n onClick={() => {\n onConfirm();\n onOpenChange(false);\n }}\n >\n {t('extensionUi.allow')}\n </button>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n","import { type CSSProperties, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport { useLocaleStore } from '@/stores/locale-store';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useThemeStore } from '@/stores/theme-store';\nimport { apiUrl } from '@/lib/url';\n\nimport { ExtensionPermissionDialog } from './extension-permission-dialog';\nimport { hasUiGrant, saveUiGrant } from './extension-permission-grants';\nimport { useExtensionRouter } from './extension-provider';\nimport { buildThemeInfo } from './theme-bridge';\n\nconst DEFAULT_MIN = 48;\nconst DEFAULT_MAX = 2000;\n\n/** Sandboxed extension UI: no `allow-same-origin` so the document is opaque-isolated from the host origin. */\nconst EXTENSION_IFRAME_SANDBOX = 'allow-scripts allow-forms allow-popups';\n\nexport type ExtensionIframeHostProps = {\n extensionId: string;\n /** Display name for the permission dialog; falls back to `extensionId`. */\n extensionName?: string;\n entrypoint: string;\n permissions?: string[];\n title?: string;\n className?: string;\n fixedHeight?: number;\n maxHeight?: number;\n minHeight?: number;\n initialData?: unknown;\n};\n\nfunction encodeAssetPath(entrypoint: string): string {\n return entrypoint\n .split('/')\n .filter(Boolean)\n .map((seg) => encodeURIComponent(seg))\n .join('/');\n}\n\nexport function ExtensionIframeHost({\n extensionId,\n extensionName,\n entrypoint,\n permissions,\n title,\n className,\n fixedHeight,\n maxHeight = DEFAULT_MAX,\n minHeight = DEFAULT_MIN,\n initialData,\n}: ExtensionIframeHostProps) {\n const { t } = useTranslation();\n const router = useExtensionRouter();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const gatewayToken = useGatewayStore((s) => s.token);\n const resolved = useThemeStore((s) => s.resolved);\n const displayName = extensionName?.trim() || extensionId;\n const permsKey = useMemo(\n () => JSON.stringify([...(permissions ?? [])].sort()),\n [permissions],\n );\n /** Stable list so registerIframe effect does not churn every render (permissions ?? [] is a new []). */\n const permList = useMemo(() => JSON.parse(permsKey) as string[], [permsKey]);\n\n const [allowed, setAllowed] = useState(() => hasUiGrant(extensionId, permList));\n const [dialogOpen, setDialogOpen] = useState(() => !hasUiGrant(extensionId, permList));\n\n useEffect(() => {\n const list = permissions ?? [];\n const ok = hasUiGrant(extensionId, list);\n setAllowed(ok);\n setDialogOpen(!ok);\n }, [extensionId, permsKey]);\n const [reloadKey, setReloadKey] = useState(0);\n const [loadError, setLoadError] = useState(false);\n\n const [dynamicHeight, setDynamicHeight] = useState(\n fixedHeight ?? Math.min(maxHeight, Math.max(minHeight, 320)),\n );\n\n const src = useMemo(() => {\n const rel = encodeAssetPath(entrypoint);\n const base = apiUrl(`/api/extensions/${encodeURIComponent(extensionId)}/assets/${rel}`);\n if (!gatewayToken?.trim()) {\n return base;\n }\n const u = new URL(base);\n u.searchParams.set('token', gatewayToken.trim());\n return u.toString();\n }, [extensionId, entrypoint, gatewayToken]);\n\n useLayoutEffect(() => {\n if (!allowed) return;\n const el = iframeRef.current;\n if (!el) return;\n router.registerIframe(extensionId, el, permList);\n return () => router.unregisterIframe(extensionId);\n }, [allowed, extensionId, permList, router]);\n\n useEffect(() => {\n if (!allowed) return;\n return router.subscribeExtensionEvents(extensionId, (msg) => {\n if (msg.event !== 'ui.resize') return;\n if (!msg.data || typeof msg.data !== 'object' || msg.data === null) return;\n const h = Number((msg.data as { height?: unknown }).height);\n if (!Number.isFinite(h)) return;\n const clamped = Math.min(maxHeight, Math.max(minHeight, h));\n if (fixedHeight === undefined) {\n setDynamicHeight(clamped);\n }\n });\n }, [allowed, extensionId, fixedHeight, maxHeight, minHeight, router]);\n\n useEffect(() => {\n if (!allowed) return;\n const th = buildThemeInfo(resolved);\n router.sendEvent(extensionId, 'theme.changed', th);\n }, [allowed, extensionId, resolved, router]);\n\n const style: CSSProperties =\n fixedHeight !== undefined\n ? { width: '100%', height: fixedHeight, border: 'none' }\n : { width: '100%', height: dynamicHeight, border: 'none' };\n\n const handleConfirmGrant = () => {\n saveUiGrant(extensionId, permList);\n setAllowed(true);\n };\n\n if (!allowed) {\n return (\n <>\n <ExtensionPermissionDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n extensionId={extensionId}\n extensionName={displayName}\n permissions={permList}\n onConfirm={handleConfirmGrant}\n />\n {!dialogOpen ? (\n <div\n className={\n className\n ? `${className} rounded-lg border border-edge border-dashed bg-surface-base p-4 text-sm text-fg-muted`\n : 'rounded-lg border border-edge border-dashed bg-surface-base p-4 text-sm text-fg-muted'\n }\n >\n <p>{t('extensionUi.deniedHint')}</p>\n <button\n type=\"button\"\n className=\"mt-2 text-sm font-medium text-accent underline-offset-2 hover:underline\"\n onClick={() => setDialogOpen(true)}\n >\n {t('extensionUi.reviewPermissions')}\n </button>\n </div>\n ) : null}\n </>\n );\n }\n\n return (\n <div className=\"flex flex-1 min-h-0 min-w-0 flex-col\">\n {loadError ? (\n <div className=\"mb-2 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm text-fg\">\n <p>{t('extensionUi.loadFailed')}</p>\n <p className=\"mt-2 text-xs text-fg-muted\">{t('extensionUi.loadFailedConnectionHint')}</p>\n <button\n type=\"button\"\n className=\"mt-2 font-medium text-accent underline-offset-2 hover:underline\"\n onClick={() => {\n setLoadError(false);\n setReloadKey((k) => k + 1);\n }}\n >\n {t('extensionUi.retryLoad')}\n </button>\n </div>\n ) : null}\n <iframe\n key={`${extensionId}-${entrypoint}-${reloadKey}`}\n ref={iframeRef}\n className={className}\n title={title ?? `Extension ${extensionId}`}\n src={src}\n style={style}\n sandbox={EXTENSION_IFRAME_SANDBOX}\n referrerPolicy=\"no-referrer\"\n onError={() => setLoadError(true)}\n onLoad={() => {\n setLoadError(false);\n const locale = useLocaleStore.getState().language;\n router.sendInit(extensionId, buildThemeInfo(useThemeStore.getState().resolved), locale);\n if (initialData !== undefined) {\n router.sendEvent(extensionId, 'widget.data', initialData);\n }\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension-iframe-host-D5HEF0KR.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-permission-grants.ts","../../../../../web/src/features/extensions/extension-permission-dialog.tsx","../../../../../web/src/features/extensions/extension-iframe-host.tsx"],"sourcesContent":["const STORAGE_KEY = 'xopc.extensionUiGrants.v1';\n\nfunction permissionFingerprint(permissions: string[]): string {\n return [...permissions].map((p) => p.trim()).filter(Boolean).sort().join('\\0');\n}\n\nexport function hasUiGrant(extensionId: string, permissions: string[]): boolean {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n const map = (raw ? JSON.parse(raw) : {}) as Record<string, string>;\n return map[extensionId] === permissionFingerprint(permissions);\n } catch {\n return false;\n }\n}\n\nexport function saveUiGrant(extensionId: string, permissions: string[]): void {\n const raw = localStorage.getItem(STORAGE_KEY);\n const map = (raw ? (JSON.parse(raw) as Record<string, string>) : {}) ?? {};\n map[extensionId] = permissionFingerprint(permissions);\n localStorage.setItem(STORAGE_KEY, JSON.stringify(map));\n}\n\n/** Short human labels for manifest `ui.permissions` (EN). */\nconst PERMISSION_LABELS_EN: Record<string, string> = {\n theme: 'Read theme (light / dark)',\n 'agent.send': 'Send messages to the assistant',\n 'agent.subscribe': 'Receive live agent stream events for a chat',\n 'session.read': 'List and open chat sessions',\n 'session.write': 'Modify chat sessions',\n 'config.read': 'Read extension configuration',\n 'config.write': 'Write extension configuration',\n storage: 'Read and write extension storage',\n notification: 'Show in-app notifications',\n clipboard: 'Use the clipboard',\n 'workspace.read': 'Read workspace files',\n 'workspace.write': 'Write workspace files',\n};\n\nconst PERMISSION_LABELS_ZH: Record<string, string> = {\n theme: '读取主题(浅色/深色)',\n 'agent.send': '向助手发送消息',\n 'agent.subscribe': '接收会话的实时助手流式事件',\n 'session.read': '列出并打开聊天会话',\n 'session.write': '修改聊天会话',\n 'config.read': '读取扩展配置',\n 'config.write': '写入扩展配置',\n storage: '读写扩展存储',\n notification: '显示应用内通知',\n clipboard: '使用剪贴板',\n 'workspace.read': '读取工作区文件',\n 'workspace.write': '写入工作区文件',\n};\n\nexport function describePermission(permission: string, language: string): string {\n const en = PERMISSION_LABELS_EN[permission];\n if (language === 'zh' && PERMISSION_LABELS_ZH[permission]) {\n return PERMISSION_LABELS_ZH[permission];\n }\n return en ?? permission;\n}\n","import * as Dialog from '@radix-ui/react-dialog';\nimport { useTranslation } from 'react-i18next';\n\nimport { useLocaleStore } from '@/stores/locale-store';\n\nimport { describePermission } from './extension-permission-grants';\n\ntype ExtensionPermissionDialogProps = {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n extensionId: string;\n extensionName: string;\n permissions: string[];\n onConfirm: () => void;\n};\n\nexport function ExtensionPermissionDialog({\n open,\n onOpenChange,\n extensionId,\n extensionName,\n permissions,\n onConfirm,\n}: ExtensionPermissionDialogProps) {\n const { t } = useTranslation();\n const language = useLocaleStore((s) => s.language);\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\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] w-[min(28rem,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-edge bg-surface-panel p-5 shadow-elevated\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <Dialog.Title className=\"text-base font-semibold text-fg\">\n {t('extensionUi.permissionTitle', { name: extensionName })}\n </Dialog.Title>\n <p className=\"mt-2 text-sm text-fg-muted\">\n {t('extensionUi.permissionSubtitle')}{' '}\n <span className=\"font-mono text-xs text-fg-muted\" title={extensionId}>\n ({extensionId})\n </span>\n </p>\n {permissions.length === 0 ? (\n <p className=\"mt-4 text-sm text-fg-muted\">{t('extensionUi.permissionsNone')}</p>\n ) : (\n <ul className=\"mt-4 max-h-48 list-inside list-disc space-y-1 overflow-y-auto text-sm text-fg\">\n {permissions.map((p) => (\n <li key={p}>{describePermission(p, language)}</li>\n ))}\n </ul>\n )}\n <div className=\"mt-6 flex justify-end gap-2\">\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className=\"rounded-lg border border-edge px-3 py-2 text-sm text-fg hover:bg-surface-muted\"\n >\n {t('extensionUi.deny')}\n </button>\n </Dialog.Close>\n <button\n type=\"button\"\n className=\"rounded-lg bg-accent px-3 py-2 text-sm font-medium text-white hover:opacity-90\"\n onClick={() => {\n onConfirm();\n onOpenChange(false);\n }}\n >\n {t('extensionUi.allow')}\n </button>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n","import { type CSSProperties, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport { useLocaleStore } from '@/stores/locale-store';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useThemeStore } from '@/stores/theme-store';\nimport { apiUrl } from '@/lib/url';\n\nimport { ExtensionPermissionDialog } from './extension-permission-dialog';\nimport { hasUiGrant, saveUiGrant } from './extension-permission-grants';\nimport { useExtensionRouter } from './extension-provider';\nimport { buildThemeInfo } from './theme-bridge';\n\nconst DEFAULT_MIN = 48;\nconst DEFAULT_MAX = 2000;\n\n/** Sandboxed extension UI: no `allow-same-origin` so the document is opaque-isolated from the host origin. */\nconst EXTENSION_IFRAME_SANDBOX = 'allow-scripts allow-forms allow-popups';\n\nexport type ExtensionIframeHostProps = {\n extensionId: string;\n /** Display name for the permission dialog; falls back to `extensionId`. */\n extensionName?: string;\n entrypoint: string;\n permissions?: string[];\n title?: string;\n className?: string;\n fixedHeight?: number;\n maxHeight?: number;\n minHeight?: number;\n initialData?: unknown;\n};\n\nfunction encodeAssetPath(entrypoint: string): string {\n return entrypoint\n .split('/')\n .filter(Boolean)\n .map((seg) => encodeURIComponent(seg))\n .join('/');\n}\n\nexport function ExtensionIframeHost({\n extensionId,\n extensionName,\n entrypoint,\n permissions,\n title,\n className,\n fixedHeight,\n maxHeight = DEFAULT_MAX,\n minHeight = DEFAULT_MIN,\n initialData,\n}: ExtensionIframeHostProps) {\n const { t } = useTranslation();\n const router = useExtensionRouter();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const gatewayToken = useGatewayStore((s) => s.token);\n const resolved = useThemeStore((s) => s.resolved);\n const displayName = extensionName?.trim() || extensionId;\n const permsKey = useMemo(\n () => JSON.stringify([...(permissions ?? [])].sort()),\n [permissions],\n );\n /** Stable list so registerIframe effect does not churn every render (permissions ?? [] is a new []). */\n const permList = useMemo(() => JSON.parse(permsKey) as string[], [permsKey]);\n\n const [allowed, setAllowed] = useState(() => hasUiGrant(extensionId, permList));\n const [dialogOpen, setDialogOpen] = useState(() => !hasUiGrant(extensionId, permList));\n\n useEffect(() => {\n const list = permissions ?? [];\n const ok = hasUiGrant(extensionId, list);\n setAllowed(ok);\n setDialogOpen(!ok);\n }, [extensionId, permsKey]);\n const [reloadKey, setReloadKey] = useState(0);\n const [loadError, setLoadError] = useState(false);\n\n const [dynamicHeight, setDynamicHeight] = useState(\n fixedHeight ?? Math.min(maxHeight, Math.max(minHeight, 320)),\n );\n\n const src = useMemo(() => {\n const rel = encodeAssetPath(entrypoint);\n const base = apiUrl(`/api/extensions/${encodeURIComponent(extensionId)}/assets/${rel}`);\n if (!gatewayToken?.trim()) {\n return base;\n }\n const u = new URL(base);\n u.searchParams.set('token', gatewayToken.trim());\n return u.toString();\n }, [extensionId, entrypoint, gatewayToken]);\n\n useLayoutEffect(() => {\n if (!allowed) return;\n const el = iframeRef.current;\n if (!el) return;\n router.registerIframe(extensionId, el, permList);\n return () => router.unregisterIframe(extensionId);\n }, [allowed, extensionId, permList, router]);\n\n useEffect(() => {\n if (!allowed) return;\n return router.subscribeExtensionEvents(extensionId, (msg) => {\n if (msg.event !== 'ui.resize') return;\n if (!msg.data || typeof msg.data !== 'object' || msg.data === null) return;\n const h = Number((msg.data as { height?: unknown }).height);\n if (!Number.isFinite(h)) return;\n const clamped = Math.min(maxHeight, Math.max(minHeight, h));\n if (fixedHeight === undefined) {\n setDynamicHeight(clamped);\n }\n });\n }, [allowed, extensionId, fixedHeight, maxHeight, minHeight, router]);\n\n useEffect(() => {\n if (!allowed) return;\n const th = buildThemeInfo(resolved);\n router.sendEvent(extensionId, 'theme.changed', th);\n }, [allowed, extensionId, resolved, router]);\n\n const style: CSSProperties =\n fixedHeight !== undefined\n ? { width: '100%', height: fixedHeight, border: 'none' }\n : { width: '100%', height: dynamicHeight, border: 'none' };\n\n const handleConfirmGrant = () => {\n saveUiGrant(extensionId, permList);\n setAllowed(true);\n };\n\n if (!allowed) {\n return (\n <>\n <ExtensionPermissionDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n extensionId={extensionId}\n extensionName={displayName}\n permissions={permList}\n onConfirm={handleConfirmGrant}\n />\n {!dialogOpen ? (\n <div\n className={\n className\n ? `${className} rounded-lg border border-edge border-dashed bg-surface-base p-4 text-sm text-fg-muted`\n : 'rounded-lg border border-edge border-dashed bg-surface-base p-4 text-sm text-fg-muted'\n }\n >\n <p>{t('extensionUi.deniedHint')}</p>\n <button\n type=\"button\"\n className=\"mt-2 text-sm font-medium text-accent underline-offset-2 hover:underline\"\n onClick={() => setDialogOpen(true)}\n >\n {t('extensionUi.reviewPermissions')}\n </button>\n </div>\n ) : null}\n </>\n );\n }\n\n return (\n <div className=\"flex flex-1 min-h-0 min-w-0 flex-col\">\n {loadError ? (\n <div className=\"mb-2 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm text-fg\">\n <p>{t('extensionUi.loadFailed')}</p>\n <p className=\"mt-2 text-xs text-fg-muted\">{t('extensionUi.loadFailedConnectionHint')}</p>\n <button\n type=\"button\"\n className=\"mt-2 font-medium text-accent underline-offset-2 hover:underline\"\n onClick={() => {\n setLoadError(false);\n setReloadKey((k) => k + 1);\n }}\n >\n {t('extensionUi.retryLoad')}\n </button>\n </div>\n ) : null}\n <iframe\n key={`${extensionId}-${entrypoint}-${reloadKey}`}\n ref={iframeRef}\n className={className}\n title={title ?? `Extension ${extensionId}`}\n src={src}\n style={style}\n sandbox={EXTENSION_IFRAME_SANDBOX}\n referrerPolicy=\"no-referrer\"\n onError={() => setLoadError(true)}\n onLoad={() => {\n setLoadError(false);\n const locale = useLocaleStore.getState().language;\n router.sendInit(extensionId, buildThemeInfo(useThemeStore.getState().resolved), locale);\n if (initialData !== undefined) {\n router.sendEvent(extensionId, 'widget.data', initialData);\n }\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{i as t,t as n}from"./vendor-react-QAsRxa6t.js";import{u as r}from"./chunk-QFMPRPBF-DOYp8d2p.js";import{t as i}from"./page-header-store-DJHD9Ean.js";import{o as a}from"./extension-provider-CO2jxBA9.js";import{t as o}from"./extension-iframe-host-Cs1Kde9o.js";var s=e(t(),1),c=n();function l(){let{extensionId:e,pageId:t}=r(),n=a(),l=i(e=>e.setPageHeader),d=i(e=>e.clearPageHeader),f=e?n.find(t=>t.id===e):void 0,p=f?.ui?.contributions?.pages,m=e&&p?.length?t?p.find(n=>n.id===t||n.id===`${e}.${t}`):p[0]:void 0;return(0,s.useLayoutEffect)(()=>{if(!e||!f||!m)return d(),()=>d();let t=m.title?.trim()||f.name||e;return l({startExtra:null,main:(0,c.jsx)(`div`,{className:`w-full min-w-0 px-3 sm:px-5 xl:px-6`,children:(0,c.jsx)(`h1`,{className:`min-w-0 truncate text-base font-semibold tracking-tight text-fg`,title:t,children:t})}),end:null}),()=>d()},[d,f,e,m,l]),e?f?p?.length?m?(0,c.jsx)(`div`,{className:`flex min-h-0 flex-1 flex-col`,children:(0,c.jsx)(o,{extensionId:e,extensionName:f.name,entrypoint:m.entrypoint,permissions:f.ui?.permissions,title:m.title,className:`min-h-0 flex-1`,fixedHeight:void 0,maxHeight:99999})}):(0,c.jsx)(u,{message:`Page "${t}" not found in extension "${e}".`}):(0,c.jsx)(u,{message:`Extension "${e}" has no page contributions.`}):(0,c.jsx)(u,{message:`Extension "${e}" not found or has no UI.`}):(0,c.jsx)(u,{message:`No extension ID provided.`})}function u({message:e}){return(0,c.jsx)(`div`,{className:`flex min-h-[min(40vh,16rem)] flex-1 items-center justify-center`,children:(0,c.jsx)(`div`,{className:`text-center`,children:(0,c.jsx)(`p`,{className:`text-sm text-fg-muted`,children:e})})})}export{l as ExtensionPage};
2
- //# sourceMappingURL=extension-page-G52iX0Bo.js.map
1
+ import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{i as t,t as n}from"./vendor-react-QAsRxa6t.js";import{u as r}from"./chunk-QFMPRPBF-DOYp8d2p.js";import{t as i}from"./page-header-store-BFpnFTed.js";import{o as a}from"./extension-provider-DZCZgQE2.js";import{t as o}from"./extension-iframe-host-D5HEF0KR.js";var s=e(t(),1),c=n();function l(){let{extensionId:e,pageId:t}=r(),n=a(),l=i(e=>e.setPageHeader),d=i(e=>e.clearPageHeader),f=e?n.find(t=>t.id===e):void 0,p=f?.ui?.contributions?.pages,m=e&&p?.length?t?p.find(n=>n.id===t||n.id===`${e}.${t}`):p[0]:void 0;return(0,s.useLayoutEffect)(()=>{if(!e||!f||!m)return d(),()=>d();let t=m.title?.trim()||f.name||e;return l({startExtra:null,main:(0,c.jsx)(`div`,{className:`w-full min-w-0 px-3 sm:px-5 xl:px-6`,children:(0,c.jsx)(`h1`,{className:`min-w-0 truncate text-base font-semibold tracking-tight text-fg`,title:t,children:t})}),end:null}),()=>d()},[d,f,e,m,l]),e?f?p?.length?m?(0,c.jsx)(`div`,{className:`flex min-h-0 flex-1 flex-col`,children:(0,c.jsx)(o,{extensionId:e,extensionName:f.name,entrypoint:m.entrypoint,permissions:f.ui?.permissions,title:m.title,className:`min-h-0 flex-1`,fixedHeight:void 0,maxHeight:99999})}):(0,c.jsx)(u,{message:`Page "${t}" not found in extension "${e}".`}):(0,c.jsx)(u,{message:`Extension "${e}" has no page contributions.`}):(0,c.jsx)(u,{message:`Extension "${e}" not found or has no UI.`}):(0,c.jsx)(u,{message:`No extension ID provided.`})}function u({message:e}){return(0,c.jsx)(`div`,{className:`flex min-h-[min(40vh,16rem)] flex-1 items-center justify-center`,children:(0,c.jsx)(`div`,{className:`text-center`,children:(0,c.jsx)(`p`,{className:`text-sm text-fg-muted`,children:e})})})}export{l as ExtensionPage};
2
+ //# sourceMappingURL=extension-page-CXdCSSPl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension-page-G52iX0Bo.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-page.tsx"],"sourcesContent":["/**\n * ExtensionPage — renders a full-page extension UI via ExtensionIframeHost.\n *\n * Mounted at /apps/:extensionId (or /apps/:extensionId/:pageId for multi-page extensions).\n */\n\nimport { useLayoutEffect } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { usePageHeaderStore } from '@/stores/page-header-store';\n\nimport { ExtensionIframeHost } from './extension-iframe-host';\nimport { useUiExtensions } from './extension-provider';\n\nexport function ExtensionPage() {\n const { extensionId, pageId } = useParams<{ extensionId: string; pageId?: string }>();\n const uiExtensions = useUiExtensions();\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n\n const extension = extensionId ? uiExtensions.find((ext) => ext.id === extensionId) : undefined;\n const pages = extension?.ui?.contributions?.pages;\n const page =\n extensionId && pages?.length\n ? pageId\n ? pages.find((p) => p.id === pageId || p.id === `${extensionId}.${pageId}`)\n : pages[0]\n : undefined;\n\n useLayoutEffect(() => {\n if (!extensionId || !extension || !page) {\n clearPageHeader();\n return () => clearPageHeader();\n }\n const headline = page.title?.trim() || extension.name || extensionId;\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\n className=\"min-w-0 truncate text-base font-semibold tracking-tight text-fg\"\n title={headline}\n >\n {headline}\n </h1>\n </div>\n ),\n end: null,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, extension, extensionId, page, setPageHeader]);\n\n if (!extensionId) {\n return <ExtensionPageNotFound message=\"No extension ID provided.\" />;\n }\n\n if (!extension) {\n return (\n <ExtensionPageNotFound message={`Extension \"${extensionId}\" not found or has no UI.`} />\n );\n }\n\n if (!pages?.length) {\n return (\n <ExtensionPageNotFound message={`Extension \"${extensionId}\" has no page contributions.`} />\n );\n }\n\n if (!page) {\n return (\n <ExtensionPageNotFound message={`Page \"${pageId}\" not found in extension \"${extensionId}\".`} />\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <ExtensionIframeHost\n extensionId={extensionId}\n extensionName={extension.name}\n entrypoint={page.entrypoint}\n permissions={extension.ui?.permissions}\n title={page.title}\n className=\"min-h-0 flex-1\"\n fixedHeight={undefined}\n maxHeight={99999}\n />\n </div>\n );\n}\n\nfunction ExtensionPageNotFound({ message }: { message: string }) {\n return (\n <div className=\"flex min-h-[min(40vh,16rem)] flex-1 items-center justify-center\">\n <div className=\"text-center\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n </div>\n );\n}\n"],"mappings":"gVAcA,SAAgB,GAAgB,CAC9B,GAAM,CAAE,cAAa,UAAW,GAAqD,CAC/E,EAAe,GAAiB,CAChC,EAAgB,EAAoB,GAAM,EAAE,cAAc,CAC1D,EAAkB,EAAoB,GAAM,EAAE,gBAAgB,CAE9D,EAAY,EAAc,EAAa,KAAM,GAAQ,EAAI,KAAO,EAAY,CAAG,IAAA,GAC/E,EAAQ,GAAW,IAAI,eAAe,MACtC,EACJ,GAAe,GAAO,OAClB,EACE,EAAM,KAAM,GAAM,EAAE,KAAO,GAAU,EAAE,KAAO,GAAG,EAAY,GAAG,IAAS,CACzE,EAAM,GACR,IAAA,GA+CN,OA7CA,EAAA,EAAA,qBAAsB,CACpB,GAAI,CAAC,GAAe,CAAC,GAAa,CAAC,EAEjC,OADA,GAAiB,KACJ,GAAiB,CAEhC,IAAM,EAAW,EAAK,OAAO,MAAM,EAAI,EAAU,MAAQ,EAezD,OAdA,EAAc,CACZ,WAAY,KACZ,MACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gDACb,EAAA,EAAA,KAAC,KAAD,CACE,UAAU,kEACV,MAAO,WAEN,EACE,CAAA,CACD,CAAA,CAER,IAAK,KACN,CAAC,KACW,GAAiB,EAC7B,CAAC,EAAiB,EAAW,EAAa,EAAM,EAAc,CAAC,CAE7D,EAIA,EAMA,GAAO,OAMP,GAOH,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,yCACb,EAAA,EAAA,KAAC,EAAD,CACe,cACb,cAAe,EAAU,KACzB,WAAY,EAAK,WACjB,YAAa,EAAU,IAAI,YAC3B,MAAO,EAAK,MACZ,UAAU,iBACV,YAAa,IAAA,GACb,UAAW,MACX,CAAA,CACE,CAAA,EAhBJ,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,SAAS,EAAO,4BAA4B,EAAY,IAAO,CAAA,EAN/F,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,cAAc,EAAY,8BAAiC,CAAA,EAN3F,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,cAAc,EAAY,2BAA8B,CAAA,EALnF,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAQ,4BAA8B,CAAA,CAqCxE,SAAS,EAAsB,CAAE,WAAgC,CAC/D,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,4EACb,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wBACb,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,iCAAyB,EAAY,CAAA,CAC9C,CAAA,CACF,CAAA"}
1
+ {"version":3,"file":"extension-page-CXdCSSPl.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-page.tsx"],"sourcesContent":["/**\n * ExtensionPage — renders a full-page extension UI via ExtensionIframeHost.\n *\n * Mounted at /apps/:extensionId (or /apps/:extensionId/:pageId for multi-page extensions).\n */\n\nimport { useLayoutEffect } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { usePageHeaderStore } from '@/stores/page-header-store';\n\nimport { ExtensionIframeHost } from './extension-iframe-host';\nimport { useUiExtensions } from './extension-provider';\n\nexport function ExtensionPage() {\n const { extensionId, pageId } = useParams<{ extensionId: string; pageId?: string }>();\n const uiExtensions = useUiExtensions();\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n\n const extension = extensionId ? uiExtensions.find((ext) => ext.id === extensionId) : undefined;\n const pages = extension?.ui?.contributions?.pages;\n const page =\n extensionId && pages?.length\n ? pageId\n ? pages.find((p) => p.id === pageId || p.id === `${extensionId}.${pageId}`)\n : pages[0]\n : undefined;\n\n useLayoutEffect(() => {\n if (!extensionId || !extension || !page) {\n clearPageHeader();\n return () => clearPageHeader();\n }\n const headline = page.title?.trim() || extension.name || extensionId;\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\n className=\"min-w-0 truncate text-base font-semibold tracking-tight text-fg\"\n title={headline}\n >\n {headline}\n </h1>\n </div>\n ),\n end: null,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, extension, extensionId, page, setPageHeader]);\n\n if (!extensionId) {\n return <ExtensionPageNotFound message=\"No extension ID provided.\" />;\n }\n\n if (!extension) {\n return (\n <ExtensionPageNotFound message={`Extension \"${extensionId}\" not found or has no UI.`} />\n );\n }\n\n if (!pages?.length) {\n return (\n <ExtensionPageNotFound message={`Extension \"${extensionId}\" has no page contributions.`} />\n );\n }\n\n if (!page) {\n return (\n <ExtensionPageNotFound message={`Page \"${pageId}\" not found in extension \"${extensionId}\".`} />\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <ExtensionIframeHost\n extensionId={extensionId}\n extensionName={extension.name}\n entrypoint={page.entrypoint}\n permissions={extension.ui?.permissions}\n title={page.title}\n className=\"min-h-0 flex-1\"\n fixedHeight={undefined}\n maxHeight={99999}\n />\n </div>\n );\n}\n\nfunction ExtensionPageNotFound({ message }: { message: string }) {\n return (\n <div className=\"flex min-h-[min(40vh,16rem)] flex-1 items-center justify-center\">\n <div className=\"text-center\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n </div>\n );\n}\n"],"mappings":"gVAcA,SAAgB,GAAgB,CAC9B,GAAM,CAAE,cAAa,UAAW,GAAqD,CAC/E,EAAe,GAAiB,CAChC,EAAgB,EAAoB,GAAM,EAAE,cAAc,CAC1D,EAAkB,EAAoB,GAAM,EAAE,gBAAgB,CAE9D,EAAY,EAAc,EAAa,KAAM,GAAQ,EAAI,KAAO,EAAY,CAAG,IAAA,GAC/E,EAAQ,GAAW,IAAI,eAAe,MACtC,EACJ,GAAe,GAAO,OAClB,EACE,EAAM,KAAM,GAAM,EAAE,KAAO,GAAU,EAAE,KAAO,GAAG,EAAY,GAAG,IAAS,CACzE,EAAM,GACR,IAAA,GA+CN,OA7CA,EAAA,EAAA,qBAAsB,CACpB,GAAI,CAAC,GAAe,CAAC,GAAa,CAAC,EAEjC,OADA,GAAiB,KACJ,GAAiB,CAEhC,IAAM,EAAW,EAAK,OAAO,MAAM,EAAI,EAAU,MAAQ,EAezD,OAdA,EAAc,CACZ,WAAY,KACZ,MACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gDACb,EAAA,EAAA,KAAC,KAAD,CACE,UAAU,kEACV,MAAO,WAEN,EACE,CAAA,CACD,CAAA,CAER,IAAK,KACN,CAAC,KACW,GAAiB,EAC7B,CAAC,EAAiB,EAAW,EAAa,EAAM,EAAc,CAAC,CAE7D,EAIA,EAMA,GAAO,OAMP,GAOH,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,yCACb,EAAA,EAAA,KAAC,EAAD,CACe,cACb,cAAe,EAAU,KACzB,WAAY,EAAK,WACjB,YAAa,EAAU,IAAI,YAC3B,MAAO,EAAK,MACZ,UAAU,iBACV,YAAa,IAAA,GACb,UAAW,MACX,CAAA,CACE,CAAA,EAhBJ,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,SAAS,EAAO,4BAA4B,EAAY,IAAO,CAAA,EAN/F,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,cAAc,EAAY,8BAAiC,CAAA,EAN3F,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,cAAc,EAAY,2BAA8B,CAAA,EALnF,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAQ,4BAA8B,CAAA,CAqCxE,SAAS,EAAsB,CAAE,WAAgC,CAC/D,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,4EACb,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wBACb,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,iCAAyB,EAAY,CAAA,CAC9C,CAAA,CACF,CAAA"}
@@ -1,2 +1,2 @@
1
- import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{i as t,t as n}from"./vendor-react-QAsRxa6t.js";import{n as r,o as i,r as a,t as o}from"./url-CtSqjF9J.js";import{r as s}from"./vendor-swr-8rdcElid.js";import{i as c}from"./theme-store-CmiSsYBd.js";var l=function(e){return e[e.PermissionDenied=4001]=`PermissionDenied`,e[e.InvalidRequest=4002]=`InvalidRequest`,e[e.MethodNotFound=4003]=`MethodNotFound`,e[e.InternalError=4004]=`InternalError`,e[e.Timeout=4005]=`Timeout`,e[e.ExtensionNotFound=4006]=`ExtensionNotFound`,e[e.RateLimited=4007]=`RateLimited`,e}({}),u=e(t(),1),d=[`--color-surface-base`,`--color-surface-panel`,`--color-surface-hover`,`--color-fg`,`--color-fg-muted`,`--color-fg-subtle`,`--color-accent`,`--color-accent-hover`,`--color-accent-soft`,`--color-edge`,`--color-edge-subtle`,`--color-danger`,`--color-success`,`--color-warning`,`--radius-sm`,`--radius-lg`,`--radius-xl`];function f(e){let t=getComputedStyle(document.documentElement),n={};for(let e of d){let r=t.getPropertyValue(e).trim();r&&(n[e]=r)}return{mode:e,tokens:n,fontFamily:t.getPropertyValue(`font-family`).trim(),fontFamilyMono:t.getPropertyValue(`--font-mono`).trim()}}var p={"agent.sendMessage":`agent.send`,"session.list":`session.read`,"session.navigate":`session.read`,"config.get":`config.read`,"config.set":`config.write`,"storage.get":`storage`,"storage.set":`storage`,"storage.remove":`storage`,"storage.keys":`storage`,"ui.notification":`notification`,"ui.navigate":`theme`,"theme.get":`theme`},m=class{iframes=new Map;byContentWindow=new WeakMap;handlers=new Map;extensionPermissions=new Map;eventSubscribers=new Map;agentStreamSubscriptions=new Map;boundListener=e=>{this.onWindowMessage(e)};constructor(){window.addEventListener(`message`,this.boundListener)}dispose(){window.removeEventListener(`message`,this.boundListener),this.iframes.clear(),this.handlers.clear(),this.extensionPermissions.clear(),this.eventSubscribers.clear(),this.agentStreamSubscriptions.clear()}registerIframe(e,t,n){let r=this.iframes.get(e);r&&r!==t&&r.contentWindow&&this.byContentWindow.delete(r.contentWindow),this.iframes.set(e,t),this.extensionPermissions.set(e,new Set(n)),this.rememberIframeWindow(e,t)}unregisterIframe(e){let t=this.iframes.get(e);t?.contentWindow&&this.byContentWindow.delete(t.contentWindow),this.iframes.delete(e),this.extensionPermissions.delete(e),this.agentStreamSubscriptions.delete(e)}rememberIframeWindow(e,t){let n=t.contentWindow;n&&this.byContentWindow.set(n,{extensionId:e,iframe:t})}subscribeAgentStream(e,t){let n=this.agentStreamSubscriptions.get(e);n||(n=new Set,this.agentStreamSubscriptions.set(e,n)),n.add(t)}unsubscribeAgentStream(e,t){this.agentStreamSubscriptions.get(e)?.delete(t)}forwardAgentStreamEvent(e,t){for(let[n,r]of this.agentStreamSubscriptions)r.has(e)&&this.sendEvent(n,`agent.stream.${e}`,t)}broadcastExtensionEvent(e,t,n){let r=t.startsWith(`ext.`)?t:`ext.${t}`;for(let[t]of this.iframes)t!==e&&this.sendEvent(t,r,n)}handleExtensionEvent(e,t,n){if(t.startsWith(`ext.`)){let r=t.slice(4);this.broadcastExtensionEvent(e,r,n);return}if(t===`agent.subscribe`||t===`agent.unsubscribe`){if(!(this.extensionPermissions.get(e)??new Set).has(`agent.subscribe`))return;let{sessionKey:r}=n??{};if(typeof r!=`string`||!r.trim())return;let i=r.trim();t===`agent.subscribe`?this.subscribeAgentStream(e,i):this.unsubscribeAgentStream(e,i)}}registerMethod(e,t){this.handlers.set(e,t)}subscribeExtensionEvents(e,t){let n=this.eventSubscribers.get(e);return n||(n=new Set,this.eventSubscribers.set(e,n)),n.add(t),()=>{n.delete(t),n.size===0&&this.eventSubscribers.delete(e)}}sendInit(e,t,n){let r=this.iframes.get(e);if(!r?.contentWindow)return;this.rememberIframeWindow(e,r);let i=[...this.extensionPermissions.get(e)??[]];r.contentWindow.postMessage({source:`xopc-host`,type:`init`,extensionId:e,permissions:i,theme:t,locale:n},`*`)}sendEvent(e,t,n){let r=this.iframes.get(e);r?.contentWindow&&r.contentWindow.postMessage({source:`xopc-host`,type:`event`,event:t,data:n},`*`)}broadcastEvent(e,t){for(let[,n]of this.iframes)n.contentWindow?.postMessage({source:`xopc-host`,type:`event`,event:e,data:t},`*`)}postResponse(e,t,n,r,i){let a=e.contentWindow??(t?.source instanceof Window?t.source:null),o={source:`xopc-host`,type:`response`,requestId:n,result:r,error:i};a&&a.postMessage(o,`*`)}isTrustedExtensionSource(e,t){if(t.source===null)return!0;let n=e.contentWindow;if(t.source===n)return!0;if(n&&typeof Window<`u`&&t.source instanceof Window)try{return t.source.frameElement===e}catch{}return!1}async onWindowMessage(e){let t=e.data;if(!t||t.source!==`xopc-extension`)return;let n,r=t.extensionId;if(e.source instanceof Window){let t=this.byContentWindow.get(e.source);t&&(n=t.iframe,r=t.extensionId)}if(n||(n=this.iframes.get(t.extensionId),r=t.extensionId),!n||!(e.source instanceof Window&&this.byContentWindow.has(e.source))&&!this.isTrustedExtensionSource(n,e))return;if(t.type===`event`){this.handleExtensionEvent(r,t.event,t.data);let e=this.eventSubscribers.get(r);if(e){let n={event:t.event,data:t.data};for(let t of e)try{t(n)}catch{}}return}if(t.type!==`request`)return;let{requestId:i,method:a,params:o}=t,s=this.handlers.get(a);if(!s){this.postResponse(n,e,i,void 0,{code:l.MethodNotFound,message:`Unknown method: ${a}`});return}let c=p[a],u=this.extensionPermissions.get(r)??new Set;if(c&&!u.has(c)){this.postResponse(n,e,i,void 0,{code:l.PermissionDenied,message:`Missing permission: ${c}`});return}try{let t=await s(r,o);this.postResponse(n,e,i,t)}catch(t){let r=t instanceof Error?t.message:String(t);this.postResponse(n,e,i,void 0,{code:l.InternalError,message:r})}}};function h(e){e.registerMethod(`theme.get`,async()=>f(c.getState().resolved)),e.registerMethod(`ui.navigate`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&`path`in t?String(t.path??``):``;n&&window.dispatchEvent(new CustomEvent(`extension-navigate`,{detail:{path:n}}))}),e.registerMethod(`ui.notification`,async(e,t)=>{window.dispatchEvent(new CustomEvent(`extension-notification`,{detail:t}))}),e.registerMethod(`session.navigate`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&`sessionKey`in t?String(t.sessionKey??``):``;n&&window.dispatchEvent(new CustomEvent(`navigate-to-chat`,{detail:{sessionKey:n},bubbles:!0}))}),e.registerMethod(`session.list`,async()=>{let e=await r(o(`/api/sessions`));if(!e.ok)throw Error(`Failed to list sessions: ${e.status}`);return((await e.json()).items??[]).map(e=>({sessionKey:e.key,title:e.name,lastMessageAt:e.updatedAt??e.lastAccessedAt,messageCount:e.messageCount}))}),e.registerMethod(`agent.sendMessage`,async(e,t)=>{let{message:n,sessionKey:i,newSession:a}=t,s=await r(o(`/api/agent`),{method:`POST`,headers:{Accept:`application/json`},body:JSON.stringify({message:n,channel:`webchat`,sessionKey:a?void 0:i,newSession:!!a})});if(!s.ok)throw Error(`Agent request failed: ${s.status}`);let c=await s.json();return{sessionKey:c.payload?.sessionKey??c.payload?.key??c.sessionKey??i??``}}),e.registerMethod(`config.get`,async e=>{let t=await r(o(`/api/extensions/${encodeURIComponent(e)}/config`));if(!t.ok)throw Error(`Failed to get config: ${t.status}`);return t.json()}),e.registerMethod(`config.set`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&!Array.isArray(t)?t:{},i=await r(o(`/api/extensions/${encodeURIComponent(e)}/config`),{method:`PATCH`,body:JSON.stringify(n)});if(!i.ok)throw Error(`Failed to set config: ${i.status}`)}),e.registerMethod(`storage.get`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&`key`in t?String(t.key??``):``,i=await r(o(`/api/extensions/${encodeURIComponent(e)}/storage/${encodeURIComponent(n)}`));if(i.status!==404){if(!i.ok)throw Error(`Failed to get storage key: ${i.status}`);return(await i.json()).value}}),e.registerMethod(`storage.set`,async(e,t)=>{let n=t,i=n&&typeof n.key==`string`?n.key:``,a=await r(o(`/api/extensions/${encodeURIComponent(e)}/storage/${encodeURIComponent(i)}`),{method:`PUT`,body:JSON.stringify({value:n?.value})});if(!a.ok)throw Error(`Failed to set storage key: ${a.status}`)}),e.registerMethod(`storage.remove`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&`key`in t?String(t.key??``):``,i=await r(o(`/api/extensions/${encodeURIComponent(e)}/storage/${encodeURIComponent(n)}`),{method:`DELETE`});if(i.status!==404&&!i.ok)throw Error(`Failed to remove storage key: ${i.status}`)}),e.registerMethod(`storage.keys`,async e=>{let t=await r(o(`/api/extensions/${encodeURIComponent(e)}/storage`));if(!t.ok)throw Error(`Failed to list storage keys: ${t.status}`);return(await t.json()).keys??[]})}var g=n(),_=(0,u.createContext)(null);function v({children:e}){let t=(0,u.useRef)(null);if(!t.current){let e=new m;h(e),t.current=e}let n=t.current,{data:r,isLoading:l}=s(i(e=>!!e.token)?`gateway-extensions-list`:null,()=>a(o(`/api/extensions`)),{revalidateOnFocus:!1}),d=r?.extensions??[],p=c(e=>e.resolved),v=(0,u.useCallback)(e=>{let t=e.detail;t?.sessionKey&&n.forwardAgentStreamEvent(t.sessionKey,t.event??t)},[n]);(0,u.useEffect)(()=>(window.addEventListener(`agent-stream-event`,v),()=>{window.removeEventListener(`agent-stream-event`,v)}),[v]),(0,u.useEffect)(()=>{let e=f(p);n.broadcastEvent(`theme.changed`,e)},[p,n]);let y=(0,u.useRef)(n);y.current=n,(0,u.useEffect)(()=>()=>{y.current.dispose(),t.current=null},[]);let b=(0,u.useMemo)(()=>({router:n,extensions:d,loading:l}),[n,d,l]);return(0,g.jsx)(_.Provider,{value:b,children:e})}function y(){let e=(0,u.useContext)(_);if(!e)throw Error(`useExtensionRouter must be used within ExtensionProvider`);return e.router}function b(){let e=(0,u.useContext)(_);if(!e)throw Error(`useExtensions must be used within ExtensionProvider`);return e.extensions}function x(e){return e.active||e.activationEligible===!0}function S(e){let t=e.ui?.contributions;return t?Array.isArray(t.pages)&&t.pages.length>0||Array.isArray(t.settingsPanels)&&t.settingsPanels.length>0||Array.isArray(t.chatWidgets)&&t.chatWidgets.length>0:!1}function C(e){return!e.hasUi||!x(e)?!1:S(e)}function w(){let e=b();return(0,u.useMemo)(()=>e.filter(C),[e])}function T(){let e=(0,u.useContext)(_);if(!e)throw Error(`useExtensionsLoading must be used within ExtensionProvider`);return e.loading}export{T as a,b as i,C as n,w as o,y as r,f as s,v as t};
2
- //# sourceMappingURL=extension-provider-CO2jxBA9.js.map
1
+ import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{i as t,t as n}from"./vendor-react-QAsRxa6t.js";import{n as r,o as i,r as a,t as o}from"./url-D7yWllI8.js";import{r as s}from"./vendor-swr-8rdcElid.js";import{i as c}from"./theme-store-CywXkKml.js";var l=function(e){return e[e.PermissionDenied=4001]=`PermissionDenied`,e[e.InvalidRequest=4002]=`InvalidRequest`,e[e.MethodNotFound=4003]=`MethodNotFound`,e[e.InternalError=4004]=`InternalError`,e[e.Timeout=4005]=`Timeout`,e[e.ExtensionNotFound=4006]=`ExtensionNotFound`,e[e.RateLimited=4007]=`RateLimited`,e}({}),u=e(t(),1),d=[`--color-surface-base`,`--color-surface-panel`,`--color-surface-hover`,`--color-fg`,`--color-fg-muted`,`--color-fg-subtle`,`--color-accent`,`--color-accent-hover`,`--color-accent-soft`,`--color-edge`,`--color-edge-subtle`,`--color-danger`,`--color-success`,`--color-warning`,`--radius-sm`,`--radius-lg`,`--radius-xl`];function f(e){let t=getComputedStyle(document.documentElement),n={};for(let e of d){let r=t.getPropertyValue(e).trim();r&&(n[e]=r)}return{mode:e,tokens:n,fontFamily:t.getPropertyValue(`font-family`).trim(),fontFamilyMono:t.getPropertyValue(`--font-mono`).trim()}}var p={"agent.sendMessage":`agent.send`,"session.list":`session.read`,"session.navigate":`session.read`,"config.get":`config.read`,"config.set":`config.write`,"storage.get":`storage`,"storage.set":`storage`,"storage.remove":`storage`,"storage.keys":`storage`,"ui.notification":`notification`,"ui.navigate":`theme`,"theme.get":`theme`},m=class{iframes=new Map;byContentWindow=new WeakMap;handlers=new Map;extensionPermissions=new Map;eventSubscribers=new Map;agentStreamSubscriptions=new Map;boundListener=e=>{this.onWindowMessage(e)};constructor(){window.addEventListener(`message`,this.boundListener)}dispose(){window.removeEventListener(`message`,this.boundListener),this.iframes.clear(),this.handlers.clear(),this.extensionPermissions.clear(),this.eventSubscribers.clear(),this.agentStreamSubscriptions.clear()}registerIframe(e,t,n){let r=this.iframes.get(e);r&&r!==t&&r.contentWindow&&this.byContentWindow.delete(r.contentWindow),this.iframes.set(e,t),this.extensionPermissions.set(e,new Set(n)),this.rememberIframeWindow(e,t)}unregisterIframe(e){let t=this.iframes.get(e);t?.contentWindow&&this.byContentWindow.delete(t.contentWindow),this.iframes.delete(e),this.extensionPermissions.delete(e),this.agentStreamSubscriptions.delete(e)}rememberIframeWindow(e,t){let n=t.contentWindow;n&&this.byContentWindow.set(n,{extensionId:e,iframe:t})}subscribeAgentStream(e,t){let n=this.agentStreamSubscriptions.get(e);n||(n=new Set,this.agentStreamSubscriptions.set(e,n)),n.add(t)}unsubscribeAgentStream(e,t){this.agentStreamSubscriptions.get(e)?.delete(t)}forwardAgentStreamEvent(e,t){for(let[n,r]of this.agentStreamSubscriptions)r.has(e)&&this.sendEvent(n,`agent.stream.${e}`,t)}broadcastExtensionEvent(e,t,n){let r=t.startsWith(`ext.`)?t:`ext.${t}`;for(let[t]of this.iframes)t!==e&&this.sendEvent(t,r,n)}handleExtensionEvent(e,t,n){if(t.startsWith(`ext.`)){let r=t.slice(4);this.broadcastExtensionEvent(e,r,n);return}if(t===`agent.subscribe`||t===`agent.unsubscribe`){if(!(this.extensionPermissions.get(e)??new Set).has(`agent.subscribe`))return;let{sessionKey:r}=n??{};if(typeof r!=`string`||!r.trim())return;let i=r.trim();t===`agent.subscribe`?this.subscribeAgentStream(e,i):this.unsubscribeAgentStream(e,i)}}registerMethod(e,t){this.handlers.set(e,t)}subscribeExtensionEvents(e,t){let n=this.eventSubscribers.get(e);return n||(n=new Set,this.eventSubscribers.set(e,n)),n.add(t),()=>{n.delete(t),n.size===0&&this.eventSubscribers.delete(e)}}sendInit(e,t,n){let r=this.iframes.get(e);if(!r?.contentWindow)return;this.rememberIframeWindow(e,r);let i=[...this.extensionPermissions.get(e)??[]];r.contentWindow.postMessage({source:`xopc-host`,type:`init`,extensionId:e,permissions:i,theme:t,locale:n},`*`)}sendEvent(e,t,n){let r=this.iframes.get(e);r?.contentWindow&&r.contentWindow.postMessage({source:`xopc-host`,type:`event`,event:t,data:n},`*`)}broadcastEvent(e,t){for(let[,n]of this.iframes)n.contentWindow?.postMessage({source:`xopc-host`,type:`event`,event:e,data:t},`*`)}postResponse(e,t,n,r,i){let a=e.contentWindow??(t?.source instanceof Window?t.source:null),o={source:`xopc-host`,type:`response`,requestId:n,result:r,error:i};a&&a.postMessage(o,`*`)}isTrustedExtensionSource(e,t){if(t.source===null)return!0;let n=e.contentWindow;if(t.source===n)return!0;if(n&&typeof Window<`u`&&t.source instanceof Window)try{return t.source.frameElement===e}catch{}return!1}async onWindowMessage(e){let t=e.data;if(!t||t.source!==`xopc-extension`)return;let n,r=t.extensionId;if(e.source instanceof Window){let t=this.byContentWindow.get(e.source);t&&(n=t.iframe,r=t.extensionId)}if(n||(n=this.iframes.get(t.extensionId),r=t.extensionId),!n||!(e.source instanceof Window&&this.byContentWindow.has(e.source))&&!this.isTrustedExtensionSource(n,e))return;if(t.type===`event`){this.handleExtensionEvent(r,t.event,t.data);let e=this.eventSubscribers.get(r);if(e){let n={event:t.event,data:t.data};for(let t of e)try{t(n)}catch{}}return}if(t.type!==`request`)return;let{requestId:i,method:a,params:o}=t,s=this.handlers.get(a);if(!s){this.postResponse(n,e,i,void 0,{code:l.MethodNotFound,message:`Unknown method: ${a}`});return}let c=p[a],u=this.extensionPermissions.get(r)??new Set;if(c&&!u.has(c)){this.postResponse(n,e,i,void 0,{code:l.PermissionDenied,message:`Missing permission: ${c}`});return}try{let t=await s(r,o);this.postResponse(n,e,i,t)}catch(t){let r=t instanceof Error?t.message:String(t);this.postResponse(n,e,i,void 0,{code:l.InternalError,message:r})}}};function h(e){e.registerMethod(`theme.get`,async()=>f(c.getState().resolved)),e.registerMethod(`ui.navigate`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&`path`in t?String(t.path??``):``;n&&window.dispatchEvent(new CustomEvent(`extension-navigate`,{detail:{path:n}}))}),e.registerMethod(`ui.notification`,async(e,t)=>{window.dispatchEvent(new CustomEvent(`extension-notification`,{detail:t}))}),e.registerMethod(`session.navigate`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&`sessionKey`in t?String(t.sessionKey??``):``;n&&window.dispatchEvent(new CustomEvent(`navigate-to-chat`,{detail:{sessionKey:n},bubbles:!0}))}),e.registerMethod(`session.list`,async()=>{let e=await r(o(`/api/sessions`));if(!e.ok)throw Error(`Failed to list sessions: ${e.status}`);return((await e.json()).items??[]).map(e=>({sessionKey:e.key,title:e.name,lastMessageAt:e.updatedAt??e.lastAccessedAt,messageCount:e.messageCount}))}),e.registerMethod(`agent.sendMessage`,async(e,t)=>{let{message:n,sessionKey:i,newSession:a}=t,s=await r(o(`/api/agent`),{method:`POST`,headers:{Accept:`application/json`},body:JSON.stringify({message:n,channel:`webchat`,sessionKey:a?void 0:i,newSession:!!a})});if(!s.ok)throw Error(`Agent request failed: ${s.status}`);let c=await s.json();return{sessionKey:c.payload?.sessionKey??c.payload?.key??c.sessionKey??i??``}}),e.registerMethod(`config.get`,async e=>{let t=await r(o(`/api/extensions/${encodeURIComponent(e)}/config`));if(!t.ok)throw Error(`Failed to get config: ${t.status}`);return t.json()}),e.registerMethod(`config.set`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&!Array.isArray(t)?t:{},i=await r(o(`/api/extensions/${encodeURIComponent(e)}/config`),{method:`PATCH`,body:JSON.stringify(n)});if(!i.ok)throw Error(`Failed to set config: ${i.status}`)}),e.registerMethod(`storage.get`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&`key`in t?String(t.key??``):``,i=await r(o(`/api/extensions/${encodeURIComponent(e)}/storage/${encodeURIComponent(n)}`));if(i.status!==404){if(!i.ok)throw Error(`Failed to get storage key: ${i.status}`);return(await i.json()).value}}),e.registerMethod(`storage.set`,async(e,t)=>{let n=t,i=n&&typeof n.key==`string`?n.key:``,a=await r(o(`/api/extensions/${encodeURIComponent(e)}/storage/${encodeURIComponent(i)}`),{method:`PUT`,body:JSON.stringify({value:n?.value})});if(!a.ok)throw Error(`Failed to set storage key: ${a.status}`)}),e.registerMethod(`storage.remove`,async(e,t)=>{let n=t&&typeof t==`object`&&t&&`key`in t?String(t.key??``):``,i=await r(o(`/api/extensions/${encodeURIComponent(e)}/storage/${encodeURIComponent(n)}`),{method:`DELETE`});if(i.status!==404&&!i.ok)throw Error(`Failed to remove storage key: ${i.status}`)}),e.registerMethod(`storage.keys`,async e=>{let t=await r(o(`/api/extensions/${encodeURIComponent(e)}/storage`));if(!t.ok)throw Error(`Failed to list storage keys: ${t.status}`);return(await t.json()).keys??[]})}var g=n(),_=(0,u.createContext)(null);function v({children:e}){let t=(0,u.useRef)(null);if(!t.current){let e=new m;h(e),t.current=e}let n=t.current,{data:r,isLoading:l}=s(i(e=>!!e.token)?`gateway-extensions-list`:null,()=>a(o(`/api/extensions`)),{revalidateOnFocus:!1}),d=r?.extensions??[],p=c(e=>e.resolved),v=(0,u.useCallback)(e=>{let t=e.detail;t?.sessionKey&&n.forwardAgentStreamEvent(t.sessionKey,t.event??t)},[n]);(0,u.useEffect)(()=>(window.addEventListener(`agent-stream-event`,v),()=>{window.removeEventListener(`agent-stream-event`,v)}),[v]),(0,u.useEffect)(()=>{let e=f(p);n.broadcastEvent(`theme.changed`,e)},[p,n]);let y=(0,u.useRef)(n);y.current=n,(0,u.useEffect)(()=>()=>{y.current.dispose(),t.current=null},[]);let b=(0,u.useMemo)(()=>({router:n,extensions:d,loading:l}),[n,d,l]);return(0,g.jsx)(_.Provider,{value:b,children:e})}function y(){let e=(0,u.useContext)(_);if(!e)throw Error(`useExtensionRouter must be used within ExtensionProvider`);return e.router}function b(){let e=(0,u.useContext)(_);if(!e)throw Error(`useExtensions must be used within ExtensionProvider`);return e.extensions}function x(e){return e.active||e.activationEligible===!0}function S(e){let t=e.ui?.contributions;return t?Array.isArray(t.pages)&&t.pages.length>0||Array.isArray(t.settingsPanels)&&t.settingsPanels.length>0||Array.isArray(t.chatWidgets)&&t.chatWidgets.length>0:!1}function C(e){return!e.hasUi||!x(e)?!1:S(e)}function w(){let e=b();return(0,u.useMemo)(()=>e.filter(C),[e])}function T(){let e=(0,u.useContext)(_);if(!e)throw Error(`useExtensionsLoading must be used within ExtensionProvider`);return e.loading}export{T as a,b as i,C as n,w as o,y as r,f as s,v as t};
2
+ //# sourceMappingURL=extension-provider-DZCZgQE2.js.map