@xopcai/xopc 0.0.6 → 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 (412) hide show
  1. package/dist/extensions/weixin/src/api/api.js +1 -1
  2. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  3. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  4. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  5. package/dist/gateway/static/root/assets/{agents-B6s2BvpH.js → agents-BdC4Y-HX.js} +2 -2
  6. package/dist/gateway/static/root/assets/agents-BdC4Y-HX.js.map +1 -0
  7. package/dist/gateway/static/root/assets/{apps-page-BtsZ5ZPx.js → apps-page-C-oaSHkm.js} +2 -2
  8. package/dist/gateway/static/root/assets/{apps-page-BtsZ5ZPx.js.map → apps-page-C-oaSHkm.js.map} +1 -1
  9. package/dist/gateway/static/root/assets/attachment-load-BDDlItdE.js +1 -0
  10. package/dist/gateway/static/root/assets/{channels-settings-BUfWBEVU.js → channels-settings-BqEUppPO.js} +2 -2
  11. package/dist/gateway/static/root/assets/{channels-settings-BUfWBEVU.js.map → channels-settings-BqEUppPO.js.map} +1 -1
  12. package/dist/gateway/static/root/assets/{chat-agents-api-BR30M2YQ.js → chat-agents-api-BhqjQ7iL.js} +2 -2
  13. package/dist/gateway/static/root/assets/{chat-agents-api-BR30M2YQ.js.map → chat-agents-api-BhqjQ7iL.js.map} +1 -1
  14. package/dist/gateway/static/root/assets/{cron-page-CMTx0Mjz.js → cron-page-Cli49RKR.js} +2 -2
  15. package/dist/gateway/static/root/assets/{cron-page-CMTx0Mjz.js.map → cron-page-Cli49RKR.js.map} +1 -1
  16. package/dist/gateway/static/root/assets/{cron-utils-BJma9IcD.js → cron-utils-Dkj-Ldpf.js} +2 -2
  17. package/dist/gateway/static/root/assets/{cron-utils-BJma9IcD.js.map → cron-utils-Dkj-Ldpf.js.map} +1 -1
  18. package/dist/gateway/static/root/assets/electron-env-BDtJw9AY.js +2 -0
  19. package/dist/gateway/static/root/assets/electron-env-BDtJw9AY.js.map +1 -0
  20. package/dist/gateway/static/root/assets/{extension-debug-page-BCVoNSo6.js → extension-debug-page-BMcZlaxF.js} +2 -2
  21. package/dist/gateway/static/root/assets/{extension-debug-page-BCVoNSo6.js.map → extension-debug-page-BMcZlaxF.js.map} +1 -1
  22. package/dist/gateway/static/root/assets/{extension-iframe-host-PWB-Pw2d.js → extension-iframe-host-D5HEF0KR.js} +2 -2
  23. package/dist/gateway/static/root/assets/{extension-iframe-host-PWB-Pw2d.js.map → extension-iframe-host-D5HEF0KR.js.map} +1 -1
  24. package/dist/gateway/static/root/assets/{extension-page-D2tTklsD.js → extension-page-CXdCSSPl.js} +2 -2
  25. package/dist/gateway/static/root/assets/{extension-page-D2tTklsD.js.map → extension-page-CXdCSSPl.js.map} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-provider-BpHodVRj.js → extension-provider-DZCZgQE2.js} +2 -2
  27. package/dist/gateway/static/root/assets/{extension-provider-BpHodVRj.js.map → extension-provider-DZCZgQE2.js.map} +1 -1
  28. package/dist/gateway/static/root/assets/{extension-settings-page-BEu6Xw1Z.js → extension-settings-page-CX6STpx3.js} +2 -2
  29. package/dist/gateway/static/root/assets/{extension-settings-page-BEu6Xw1Z.js.map → extension-settings-page-CX6STpx3.js.map} +1 -1
  30. package/dist/gateway/static/root/assets/{gateway-config-swr-C7ZFPhNj.js → gateway-config-swr-Cph02QZn.js} +2 -2
  31. package/dist/gateway/static/root/assets/{gateway-config-swr-C7ZFPhNj.js.map → gateway-config-swr-Cph02QZn.js.map} +1 -1
  32. package/dist/gateway/static/root/assets/index-Bty3m0mS.css +2 -0
  33. package/dist/gateway/static/root/assets/index-iTUyfzNr.js +16 -0
  34. package/dist/gateway/static/root/assets/index-iTUyfzNr.js.map +1 -0
  35. package/dist/gateway/static/root/assets/{logs-page-BpsxYdcL.js → logs-page-B9O5l3I8.js} +2 -2
  36. package/dist/gateway/static/root/assets/{logs-page-BpsxYdcL.js.map → logs-page-B9O5l3I8.js.map} +1 -1
  37. package/dist/gateway/static/root/assets/{model-selector-BiiDq8Pk.js → model-selector-BLiY_O25.js} +2 -2
  38. package/dist/gateway/static/root/assets/{model-selector-BiiDq8Pk.js.map → model-selector-BLiY_O25.js.map} +1 -1
  39. package/dist/gateway/static/root/assets/navigation-DB9S-C6S.js +2 -0
  40. package/dist/gateway/static/root/assets/navigation-DB9S-C6S.js.map +1 -0
  41. package/dist/gateway/static/root/assets/page-header-store-BFpnFTed.js +2 -0
  42. package/dist/gateway/static/root/assets/{page-header-store-HcRZK5CZ.js.map → page-header-store-BFpnFTed.js.map} +1 -1
  43. package/dist/gateway/static/root/assets/{session-api-DxNaAkmX.js → session-api-DEhQXWJg.js} +2 -2
  44. package/dist/gateway/static/root/assets/{session-api-DxNaAkmX.js.map → session-api-DEhQXWJg.js.map} +1 -1
  45. package/dist/gateway/static/root/assets/{session-working-directory-control-CDH-Wk4E.js → session-working-directory-control-DKOtWs3-.js} +3 -3
  46. package/dist/gateway/static/root/assets/{session-working-directory-control-CDH-Wk4E.js.map → session-working-directory-control-DKOtWs3-.js.map} +1 -1
  47. package/dist/gateway/static/root/assets/{sessions-page-5PK75r1n.js → sessions-page-BYlWP1ep.js} +2 -2
  48. package/dist/gateway/static/root/assets/{sessions-page-5PK75r1n.js.map → sessions-page-BYlWP1ep.js.map} +1 -1
  49. package/dist/gateway/static/root/assets/settings-page-oCnIavdg.js +2 -0
  50. package/dist/gateway/static/root/assets/settings-page-oCnIavdg.js.map +1 -0
  51. package/dist/gateway/static/root/assets/{skill-api-CxbNlOD_.js → skill-api-DWrn8Az0.js} +2 -2
  52. package/dist/gateway/static/root/assets/{skill-api-CxbNlOD_.js.map → skill-api-DWrn8Az0.js.map} +1 -1
  53. package/dist/gateway/static/root/assets/{skills-page-Dd8ZzYJb.js → skills-page-C59WQpM1.js} +2 -2
  54. package/dist/gateway/static/root/assets/{skills-page-Dd8ZzYJb.js.map → skills-page-C59WQpM1.js.map} +1 -1
  55. package/dist/gateway/static/root/assets/{theme-store-CPTH77BE.js → theme-store-CywXkKml.js} +2 -2
  56. package/dist/gateway/static/root/assets/{theme-store-CPTH77BE.js.map → theme-store-CywXkKml.js.map} +1 -1
  57. package/dist/gateway/static/root/assets/url-D7yWllI8.js +2 -0
  58. package/dist/gateway/static/root/assets/url-D7yWllI8.js.map +1 -0
  59. package/dist/gateway/static/root/assets/{useTranslation-BEUWOMuh.js → useTranslation-CACj0DBJ.js} +2 -2
  60. package/dist/gateway/static/root/assets/{useTranslation-BEUWOMuh.js.map → useTranslation-CACj0DBJ.js.map} +1 -1
  61. package/dist/gateway/static/root/index.html +16 -16
  62. package/dist/package.js +1 -1
  63. package/dist/src/agent/agent-manager.d.ts +1 -0
  64. package/dist/src/agent/agent-manager.js +17 -9
  65. package/dist/src/agent/agent-manager.js.map +1 -1
  66. package/dist/src/agent/background-review/run-background-review.js +2 -0
  67. package/dist/src/agent/background-review/run-background-review.js.map +1 -1
  68. package/dist/src/agent/child-agent-factory.js +2 -0
  69. package/dist/src/agent/child-agent-factory.js.map +1 -1
  70. package/dist/src/agent/context/expand-at-file-mentions.d.ts +4 -0
  71. package/dist/src/agent/context/expand-at-file-mentions.js +69 -0
  72. package/dist/src/agent/context/expand-at-file-mentions.js.map +1 -0
  73. package/dist/src/agent/context/workspace-seed.js +1 -1
  74. package/dist/src/agent/image/index.d.ts +0 -1
  75. package/dist/src/agent/image/index.js +1 -2
  76. package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
  77. package/dist/src/agent/ipc/inbox.js +1 -1
  78. package/dist/src/agent/ipc/socket.js +1 -1
  79. package/dist/src/agent/memory/compaction.d.ts +1 -1
  80. package/dist/src/agent/memory/compaction.js +38 -11
  81. package/dist/src/agent/memory/compaction.js.map +1 -1
  82. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  83. package/dist/src/agent/messaging/command-handler.d.ts +13 -0
  84. package/dist/src/agent/messaging/command-handler.js +14 -2
  85. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  86. package/dist/src/agent/orchestration/agent-orchestrator.js +6 -1
  87. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  88. package/dist/src/agent/service.d.ts +16 -1
  89. package/dist/src/agent/service.js +175 -17
  90. package/dist/src/agent/service.js.map +1 -1
  91. package/dist/src/agent/skills/format-skills-prompt.js.map +1 -1
  92. package/dist/src/agent/skills/hub-hash.js +1 -1
  93. package/dist/src/agent/skills/hub-pull.js +1 -1
  94. package/dist/src/agent/skills/scanner.js +1 -1
  95. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  96. package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
  97. package/dist/src/agent/tools/browser/tools.js +2 -2
  98. package/dist/src/agent/tools/browser/tools.js.map +1 -1
  99. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  100. package/dist/src/agent/tools/image-tool.js +2 -2
  101. package/dist/src/agent/tools/image-tool.js.map +1 -1
  102. package/dist/src/agent/tools/index.d.ts +1 -1
  103. package/dist/src/agent/tools/index.js +2 -2
  104. package/dist/src/agent/tools/read.d.ts +0 -2
  105. package/dist/src/agent/tools/read.js +1 -3
  106. package/dist/src/agent/tools/read.js.map +1 -1
  107. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  108. package/dist/src/agent/tools/write.js +1 -1
  109. package/dist/src/auth/credentials.js +2 -2
  110. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  111. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  112. package/dist/src/channels/index.d.ts +1 -1
  113. package/dist/src/channels/index.js +2 -2
  114. package/dist/src/channels/pipeline.d.ts +8 -1
  115. package/dist/src/channels/pipeline.js +49 -4
  116. package/dist/src/channels/pipeline.js.map +1 -1
  117. package/dist/src/channels/plugin-types.d.ts +14 -0
  118. package/dist/src/chat-commands/builtins/config.d.ts +4 -0
  119. package/dist/src/chat-commands/builtins/config.js +197 -0
  120. package/dist/src/chat-commands/builtins/config.js.map +1 -0
  121. package/dist/src/chat-commands/builtins/context.d.ts +4 -0
  122. package/dist/src/chat-commands/builtins/context.js +44 -0
  123. package/dist/src/chat-commands/builtins/context.js.map +1 -0
  124. package/dist/src/chat-commands/builtins/session.js +111 -0
  125. package/dist/src/chat-commands/builtins/session.js.map +1 -1
  126. package/dist/src/chat-commands/builtins/thinking.js +49 -21
  127. package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
  128. package/dist/src/chat-commands/config-paths.d.ts +10 -0
  129. package/dist/src/chat-commands/config-paths.js +45 -0
  130. package/dist/src/chat-commands/config-paths.js.map +1 -0
  131. package/dist/src/chat-commands/config-value.d.ts +12 -0
  132. package/dist/src/chat-commands/config-value.js +53 -0
  133. package/dist/src/chat-commands/config-value.js.map +1 -0
  134. package/dist/src/chat-commands/context.d.ts +24 -1
  135. package/dist/src/chat-commands/context.js +41 -0
  136. package/dist/src/chat-commands/context.js.map +1 -1
  137. package/dist/src/chat-commands/index.d.ts +2 -0
  138. package/dist/src/chat-commands/index.js +5 -1
  139. package/dist/src/chat-commands/index.js.map +1 -1
  140. package/dist/src/chat-commands/types.d.ts +33 -1
  141. package/dist/src/cli/commands/agent/interactive.js +1 -1
  142. package/dist/src/cli/commands/agent/interactive.js.map +1 -1
  143. package/dist/src/cli/commands/agent.js +21 -9
  144. package/dist/src/cli/commands/agent.js.map +1 -1
  145. package/dist/src/cli/commands/auth.js.map +1 -1
  146. package/dist/src/cli/commands/doctor/checks/channel-config.d.ts +2 -0
  147. package/dist/src/cli/commands/doctor/checks/channel-config.js +113 -0
  148. package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -0
  149. package/dist/src/cli/commands/doctor/checks/channel-plugins.d.ts +2 -0
  150. package/dist/src/cli/commands/doctor/checks/channel-plugins.js +47 -0
  151. package/dist/src/cli/commands/doctor/checks/channel-plugins.js.map +1 -0
  152. package/dist/src/cli/commands/doctor/checks/config-health.d.ts +2 -0
  153. package/dist/src/cli/commands/doctor/checks/config-health.js +82 -0
  154. package/dist/src/cli/commands/doctor/checks/config-health.js.map +1 -0
  155. package/dist/src/cli/commands/doctor/checks/cron-health.d.ts +2 -0
  156. package/dist/src/cli/commands/doctor/checks/cron-health.js +116 -0
  157. package/dist/src/cli/commands/doctor/checks/cron-health.js.map +1 -0
  158. package/dist/src/cli/commands/doctor/checks/gateway-health.d.ts +2 -0
  159. package/dist/src/cli/commands/doctor/checks/gateway-health.js +64 -0
  160. package/dist/src/cli/commands/doctor/checks/gateway-health.js.map +1 -0
  161. package/dist/src/cli/commands/doctor/checks/gateway-service.d.ts +2 -0
  162. package/dist/src/cli/commands/doctor/checks/gateway-service.js +64 -0
  163. package/dist/src/cli/commands/doctor/checks/gateway-service.js.map +1 -0
  164. package/dist/src/cli/commands/doctor/checks/node-version.d.ts +2 -0
  165. package/dist/src/cli/commands/doctor/checks/node-version.js +33 -0
  166. package/dist/src/cli/commands/doctor/checks/node-version.js.map +1 -0
  167. package/dist/src/cli/commands/doctor/checks/provider-auth.d.ts +2 -0
  168. package/dist/src/cli/commands/doctor/checks/provider-auth.js +91 -0
  169. package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -0
  170. package/dist/src/cli/commands/doctor/checks/security-audit.d.ts +2 -0
  171. package/dist/src/cli/commands/doctor/checks/security-audit.js +85 -0
  172. package/dist/src/cli/commands/doctor/checks/security-audit.js.map +1 -0
  173. package/dist/src/cli/commands/doctor/checks/session-integrity.d.ts +2 -0
  174. package/dist/src/cli/commands/doctor/checks/session-integrity.js +118 -0
  175. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -0
  176. package/dist/src/cli/commands/doctor/checks/state-integrity.d.ts +2 -0
  177. package/dist/src/cli/commands/doctor/checks/state-integrity.js +99 -0
  178. package/dist/src/cli/commands/doctor/checks/state-integrity.js.map +1 -0
  179. package/dist/src/cli/commands/doctor/checks/version-check.d.ts +2 -0
  180. package/dist/src/cli/commands/doctor/checks/version-check.js +71 -0
  181. package/dist/src/cli/commands/doctor/checks/version-check.js.map +1 -0
  182. package/dist/src/cli/commands/doctor/checks/workspace-status.d.ts +2 -0
  183. package/dist/src/cli/commands/doctor/checks/workspace-status.js +73 -0
  184. package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -0
  185. package/dist/src/cli/commands/doctor/flow.d.ts +9 -0
  186. package/dist/src/cli/commands/doctor/flow.js +51 -0
  187. package/dist/src/cli/commands/doctor/flow.js.map +1 -0
  188. package/dist/src/cli/commands/doctor/format.d.ts +6 -0
  189. package/dist/src/cli/commands/doctor/format.js +61 -0
  190. package/dist/src/cli/commands/doctor/format.js.map +1 -0
  191. package/dist/src/cli/commands/doctor/index.js +44 -0
  192. package/dist/src/cli/commands/doctor/index.js.map +1 -0
  193. package/dist/src/cli/commands/doctor/types.d.ts +20 -0
  194. package/dist/src/cli/commands/doctor/types.js +1 -0
  195. package/dist/src/cli/commands/extension.js +10 -0
  196. package/dist/src/cli/commands/extension.js.map +1 -1
  197. package/dist/src/cli/commands/init.js +1 -2
  198. package/dist/src/cli/commands/init.js.map +1 -1
  199. package/dist/src/cli/commands/session/utils.js.map +1 -1
  200. package/dist/src/cli/commands/update.d.ts +1 -0
  201. package/dist/src/cli/commands/update.js +171 -0
  202. package/dist/src/cli/commands/update.js.map +1 -0
  203. package/dist/src/cli/index.d.ts +2 -2
  204. package/dist/src/cli/index.js +4 -2
  205. package/dist/src/cli/index.js.map +1 -1
  206. package/dist/src/cli/utils/init-workspace.js +1 -1
  207. package/dist/src/config/index.d.ts +1 -0
  208. package/dist/src/config/index.js +4 -3
  209. package/dist/src/config/index.js.map +1 -1
  210. package/dist/src/config/loader.js +1 -1
  211. package/dist/src/config/models-json.d.ts +15 -15
  212. package/dist/src/config/paths.js.map +1 -1
  213. package/dist/src/config/profile.js +1 -1
  214. package/dist/src/config/runtime-overrides.d.ts +8 -0
  215. package/dist/src/config/runtime-overrides.js +40 -0
  216. package/dist/src/config/runtime-overrides.js.map +1 -0
  217. package/dist/src/config/schema.d.ts +34 -104
  218. package/dist/src/config/schema.js +18 -39
  219. package/dist/src/config/schema.js.map +1 -1
  220. package/dist/src/cron/persistence.js +1 -1
  221. package/dist/src/cron/run-log-store.js +1 -1
  222. package/dist/src/daemon/launchd.js +2 -2
  223. package/dist/src/daemon/launchd.js.map +1 -1
  224. package/dist/src/daemon/systemd.js +2 -2
  225. package/dist/src/daemon/systemd.js.map +1 -1
  226. package/dist/src/extensions/health.js +1 -1
  227. package/dist/src/extensions/loader.d.ts +1 -1
  228. package/dist/src/extensions/loader.js +5 -8
  229. package/dist/src/extensions/loader.js.map +1 -1
  230. package/dist/src/extensions/lockfile.js +1 -1
  231. package/dist/src/extensions/sdk/index.js +6 -1
  232. package/dist/src/extensions/sdk/index.js.map +1 -0
  233. package/dist/src/gateway/agents-admin.js +1 -1
  234. package/dist/src/gateway/agents-admin.js.map +1 -1
  235. package/dist/src/gateway/hono/lib/static-ui.js +1 -1
  236. package/dist/src/gateway/hono/oauth.js +1 -1
  237. package/dist/src/gateway/hono/routes/config.js +1 -1
  238. package/dist/src/gateway/hono/routes/doctor.d.ts +3 -0
  239. package/dist/src/gateway/hono/routes/doctor.js +35 -0
  240. package/dist/src/gateway/hono/routes/doctor.js.map +1 -0
  241. package/dist/src/gateway/hono/routes/index.js +4 -0
  242. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  243. package/dist/src/gateway/hono/routes/models.js +64 -11
  244. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  245. package/dist/src/gateway/hono/routes/public-gateway.js +10 -0
  246. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  247. package/dist/src/gateway/hono/routes/update.d.ts +3 -0
  248. package/dist/src/gateway/hono/routes/update.js +141 -0
  249. package/dist/src/gateway/hono/routes/update.js.map +1 -0
  250. package/dist/src/gateway/hono/routes/workspace.js +82 -2
  251. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  252. package/dist/src/gateway/lock.js +1 -1
  253. package/dist/src/gateway/ports.js +98 -3
  254. package/dist/src/gateway/ports.js.map +1 -1
  255. package/dist/src/gateway/service.d.ts +1 -4
  256. package/dist/src/gateway/service.js +13 -20
  257. package/dist/src/gateway/service.js.map +1 -1
  258. package/dist/src/gateway/workspace-fs-file-list.d.ts +5 -0
  259. package/dist/src/gateway/workspace-fs-file-list.js +56 -0
  260. package/dist/src/gateway/workspace-fs-file-list.js.map +1 -0
  261. package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
  262. package/dist/src/gateway/workspace-ripgrep.d.ts +5 -0
  263. package/dist/src/gateway/workspace-ripgrep.js +88 -4
  264. package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
  265. package/dist/src/infra/update-channels.d.ts +14 -0
  266. package/dist/src/infra/update-channels.js +30 -0
  267. package/dist/src/infra/update-channels.js.map +1 -0
  268. package/dist/src/infra/update-check.d.ts +53 -0
  269. package/dist/src/infra/update-check.js +155 -0
  270. package/dist/src/infra/update-check.js.map +1 -0
  271. package/dist/src/infra/update-runner.d.ts +18 -0
  272. package/dist/src/infra/update-runner.js +112 -0
  273. package/dist/src/infra/update-runner.js.map +1 -0
  274. package/dist/src/infra/update-startup.d.ts +20 -0
  275. package/dist/src/infra/update-startup.js +246 -0
  276. package/dist/src/infra/update-startup.js.map +1 -0
  277. package/dist/src/providers/extension-stream-bridge.d.ts +3 -0
  278. package/dist/src/providers/extension-stream-bridge.js +239 -0
  279. package/dist/src/providers/extension-stream-bridge.js.map +1 -0
  280. package/dist/src/providers/index.d.ts +7 -2
  281. package/dist/src/providers/index.js +77 -14
  282. package/dist/src/providers/index.js.map +1 -1
  283. package/dist/src/providers/model-registry.js +1 -1
  284. package/dist/src/providers/plugin-registry.js +92 -87
  285. package/dist/src/providers/plugin-registry.js.map +1 -1
  286. package/dist/src/routing/bindings.js +1 -1
  287. package/dist/src/routing/index.d.ts +1 -1
  288. package/dist/src/routing/index.js +2 -2
  289. package/dist/src/routing/index.js.map +1 -1
  290. package/dist/src/routing/resolve-route.js +1 -1
  291. package/dist/src/routing/session-key.d.ts +0 -5
  292. package/dist/src/routing/session-key.js +1 -27
  293. package/dist/src/routing/session-key.js.map +1 -1
  294. package/dist/src/session/chat-export.d.ts +5 -0
  295. package/dist/src/session/chat-export.js +35 -0
  296. package/dist/src/session/chat-export.js.map +1 -0
  297. package/dist/src/session/config-store.js +1 -1
  298. package/dist/src/session/manager.d.ts +1 -1
  299. package/dist/src/session/manager.js +2 -2
  300. package/dist/src/session/manager.js.map +1 -1
  301. package/dist/src/session/store.d.ts +1 -1
  302. package/dist/src/session/store.js +3 -7
  303. package/dist/src/session/store.js.map +1 -1
  304. package/dist/src/session/types.d.ts +0 -10
  305. package/dist/src/session/types.js.map +1 -1
  306. package/dist/src/utils/logger/audit.js +1 -1
  307. package/dist/src/utils/logger/log-store.js +1 -1
  308. package/dist/src/utils/logger/rotation.js +1 -1
  309. package/dist/src/voice/tts/audio.js +1 -1
  310. package/package.json +2 -2
  311. package/dist/gateway/static/root/assets/agents-B6s2BvpH.js.map +0 -1
  312. package/dist/gateway/static/root/assets/attachment-load-6pRlDPZ8.js +0 -1
  313. package/dist/gateway/static/root/assets/index-DBZ5eXW5.js +0 -16
  314. package/dist/gateway/static/root/assets/index-DBZ5eXW5.js.map +0 -1
  315. package/dist/gateway/static/root/assets/index-KsVMH-Jo.css +0 -2
  316. package/dist/gateway/static/root/assets/navigation-BpLKd2Ca.js +0 -2
  317. package/dist/gateway/static/root/assets/navigation-BpLKd2Ca.js.map +0 -1
  318. package/dist/gateway/static/root/assets/page-header-store-HcRZK5CZ.js +0 -2
  319. package/dist/gateway/static/root/assets/preference-select-fields-B4AJBqUY.js +0 -2
  320. package/dist/gateway/static/root/assets/preference-select-fields-B4AJBqUY.js.map +0 -1
  321. package/dist/gateway/static/root/assets/settings-page-BvSj0JqX.js +0 -2
  322. package/dist/gateway/static/root/assets/settings-page-BvSj0JqX.js.map +0 -1
  323. package/dist/gateway/static/root/assets/url-QmwQTJ-j.js +0 -2
  324. package/dist/gateway/static/root/assets/url-QmwQTJ-j.js.map +0 -1
  325. package/dist/src/acp/commands.d.ts +0 -11
  326. package/dist/src/acp/commands.js +0 -17
  327. package/dist/src/acp/commands.js.map +0 -1
  328. package/dist/src/acp/control-plane/identity-reconcile.d.ts +0 -36
  329. package/dist/src/acp/control-plane/identity-reconcile.js +0 -124
  330. package/dist/src/acp/control-plane/identity-reconcile.js.map +0 -1
  331. package/dist/src/acp/control-plane/index.d.ts +0 -10
  332. package/dist/src/acp/control-plane/index.js +0 -6
  333. package/dist/src/acp/control-plane/manager.d.ts +0 -86
  334. package/dist/src/acp/control-plane/manager.js +0 -502
  335. package/dist/src/acp/control-plane/manager.js.map +0 -1
  336. package/dist/src/acp/control-plane/manager.types.d.ts +0 -125
  337. package/dist/src/acp/control-plane/manager.types.js +0 -14
  338. package/dist/src/acp/control-plane/manager.types.js.map +0 -1
  339. package/dist/src/acp/control-plane/manager.utils.d.ts +0 -29
  340. package/dist/src/acp/control-plane/manager.utils.js +0 -46
  341. package/dist/src/acp/control-plane/manager.utils.js.map +0 -1
  342. package/dist/src/acp/control-plane/runtime-cache-manager.d.ts +0 -49
  343. package/dist/src/acp/control-plane/runtime-cache-manager.js +0 -155
  344. package/dist/src/acp/control-plane/runtime-cache-manager.js.map +0 -1
  345. package/dist/src/acp/control-plane/runtime-cache.d.ts +0 -45
  346. package/dist/src/acp/control-plane/runtime-cache.js +0 -58
  347. package/dist/src/acp/control-plane/runtime-cache.js.map +0 -1
  348. package/dist/src/acp/control-plane/runtime-options.d.ts +0 -30
  349. package/dist/src/acp/control-plane/runtime-options.js +0 -92
  350. package/dist/src/acp/control-plane/runtime-options.js.map +0 -1
  351. package/dist/src/acp/control-plane/session-actor-queue.d.ts +0 -22
  352. package/dist/src/acp/control-plane/session-actor-queue.js +0 -70
  353. package/dist/src/acp/control-plane/session-actor-queue.js.map +0 -1
  354. package/dist/src/acp/control-plane/session-lifecycle-manager.d.ts +0 -59
  355. package/dist/src/acp/control-plane/session-lifecycle-manager.js +0 -209
  356. package/dist/src/acp/control-plane/session-lifecycle-manager.js.map +0 -1
  357. package/dist/src/acp/control-plane/session-store.d.ts +0 -39
  358. package/dist/src/acp/control-plane/session-store.js +0 -149
  359. package/dist/src/acp/control-plane/session-store.js.map +0 -1
  360. package/dist/src/acp/control-plane/turn-manager.d.ts +0 -40
  361. package/dist/src/acp/control-plane/turn-manager.js +0 -134
  362. package/dist/src/acp/control-plane/turn-manager.js.map +0 -1
  363. package/dist/src/acp/event-mapper.d.ts +0 -48
  364. package/dist/src/acp/event-mapper.js +0 -94
  365. package/dist/src/acp/event-mapper.js.map +0 -1
  366. package/dist/src/acp/index.d.ts +0 -10
  367. package/dist/src/acp/index.js +0 -5
  368. package/dist/src/acp/meta.d.ts +0 -15
  369. package/dist/src/acp/meta.js +0 -36
  370. package/dist/src/acp/meta.js.map +0 -1
  371. package/dist/src/acp/routing-integration.d.ts +0 -37
  372. package/dist/src/acp/routing-integration.js +0 -58
  373. package/dist/src/acp/routing-integration.js.map +0 -1
  374. package/dist/src/acp/runtime/backends/index.d.ts +0 -4
  375. package/dist/src/acp/runtime/backends/index.js +0 -2
  376. package/dist/src/acp/runtime/backends/local.d.ts +0 -136
  377. package/dist/src/acp/runtime/backends/local.js +0 -603
  378. package/dist/src/acp/runtime/backends/local.js.map +0 -1
  379. package/dist/src/acp/runtime/error-text.d.ts +0 -16
  380. package/dist/src/acp/runtime/error-text.js +0 -40
  381. package/dist/src/acp/runtime/error-text.js.map +0 -1
  382. package/dist/src/acp/runtime/errors.d.ts +0 -31
  383. package/dist/src/acp/runtime/errors.js +0 -47
  384. package/dist/src/acp/runtime/errors.js.map +0 -1
  385. package/dist/src/acp/runtime/index.d.ts +0 -7
  386. package/dist/src/acp/runtime/index.js +0 -4
  387. package/dist/src/acp/runtime/registry.d.ts +0 -35
  388. package/dist/src/acp/runtime/registry.js +0 -85
  389. package/dist/src/acp/runtime/registry.js.map +0 -1
  390. package/dist/src/acp/runtime/session-identity.d.ts +0 -35
  391. package/dist/src/acp/runtime/session-identity.js +0 -134
  392. package/dist/src/acp/runtime/session-identity.js.map +0 -1
  393. package/dist/src/acp/runtime/types.d.ts +0 -214
  394. package/dist/src/acp/secret-file.d.ts +0 -7
  395. package/dist/src/acp/secret-file.js +0 -19
  396. package/dist/src/acp/secret-file.js.map +0 -1
  397. package/dist/src/acp/server.d.ts +0 -48
  398. package/dist/src/acp/server.js +0 -300
  399. package/dist/src/acp/server.js.map +0 -1
  400. package/dist/src/acp/session.d.ts +0 -29
  401. package/dist/src/acp/session.js +0 -30
  402. package/dist/src/acp/session.js.map +0 -1
  403. package/dist/src/acp/types.d.ts +0 -39
  404. package/dist/src/acp/types.js +0 -13
  405. package/dist/src/acp/types.js.map +0 -1
  406. package/dist/src/agent/image/describe-images.d.ts +0 -18
  407. package/dist/src/agent/image/describe-images.js +0 -19
  408. package/dist/src/agent/image/describe-images.js.map +0 -1
  409. package/dist/src/cli/commands/acp.d.ts +0 -4
  410. package/dist/src/cli/commands/acp.js +0 -200
  411. package/dist/src/cli/commands/acp.js.map +0 -1
  412. /package/dist/src/{acp/runtime/types.js → cli/commands/doctor/index.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../../../web/src/features/skills/skills-page.tsx"],"sourcesContent":["import * as Dialog from '@radix-ui/react-dialog';\nimport * as DropdownMenu from '@radix-ui/react-dropdown-menu';\nimport type { LucideIcon } from 'lucide-react';\nimport {\n BookOpen,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n FileArchive,\n FileText,\n FileType,\n Funnel,\n Info,\n MoreVertical,\n Package,\n Plus,\n Presentation,\n Puzzle,\n RefreshCw,\n Search,\n Sparkles,\n Table2,\n Trash2,\n X,\n} from 'lucide-react';\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { useLocation, useSearchParams } from 'react-router-dom';\n\nimport { MarkdownView } from '@/components/markdown/markdown-view';\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/lib/cn';\nimport { interaction } from '@/lib/interaction';\nimport {\n deleteSkill,\n getMarketplacePackageDetail,\n getMarketplaceSkills,\n getSkillMarkdown,\n getSkills,\n installMarketplaceSkill,\n patchSkillEnabled,\n reloadSkills,\n uploadSkillZip,\n} from '@/features/skills/skill-api';\nimport type { MarketplacePackageItem, SkillCatalogEntry } from '@/features/skills/skill.types';\nimport { messages } from '@/i18n/messages';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\nimport { usePageHeaderStore } from '@/stores/page-header-store';\n\nfunction interpolate(template: string, params: Record<string, string | number>): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key) => String(params[key] ?? ''));\n}\n\n/** Distinct glyph per skill id — avoids duplicate “first letter” collisions (e.g. create-skill vs install-skill-dependency). */\nfunction resolveSkillIcon(name: string): LucideIcon {\n const n = name.toLowerCase().replace(/_/g, '-');\n if (n.includes('find-skill')) return Search;\n if (n.includes('install') && (n.includes('depend') || n.includes('dependency'))) return Package;\n if (n.includes('create-skill')) return Sparkles;\n if (n === 'docx' || n.endsWith('-docx')) return FileText;\n if (n === 'pdf' || n.endsWith('-pdf')) return FileType;\n if (n === 'pptx' || n.includes('pptx')) return Presentation;\n if (n === 'xlsx' || n.includes('xlsx')) return Table2;\n if (n.includes('markdown') || n.includes('md')) return BookOpen;\n return Puzzle;\n}\n\nfunction SkillCardIcon({ name, className }: { name: string; className?: string }) {\n const Icon = resolveSkillIcon(name);\n return (\n <div\n className={cn(\n 'flex size-11 shrink-0 items-center justify-center rounded-xl',\n 'bg-surface-hover/90 shadow-surface ring-1 ring-inset ring-edge/35 dark:bg-surface-active/80 dark:ring-edge/50',\n 'transition-[transform,box-shadow] duration-200 ease-out group-hover:ring-edge/55 dark:group-hover:ring-edge/65',\n 'group-hover:-translate-y-px',\n className,\n )}\n aria-hidden\n >\n <Icon\n className=\"size-[1.35rem] text-fg-muted transition-colors duration-200 group-hover:text-fg\"\n strokeWidth={1.75}\n />\n </div>\n );\n}\n\ntype MainTab = 'builtin' | 'user' | 'marketplace';\ntype SourceFilter = 'all' | 'global' | 'workspace' | 'extra';\nconst MAIN_TAB_SET = new Set<MainTab>(['builtin', 'user', 'marketplace']);\nconst SOURCE_FILTER_SET = new Set<SourceFilter>(['all', 'global', 'workspace', 'extra']);\n\nfunction normalizeCatalogEntry(r: SkillCatalogEntry): SkillCatalogEntry {\n return {\n ...r,\n enabled: r.enabled ?? true,\n disableModelInvocation: r.disableModelInvocation ?? false,\n };\n}\n\nfunction SkillEnableSwitch({\n checked,\n onChange,\n}: {\n checked: boolean;\n onChange: (next: boolean) => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n className={cn(\n 'relative h-6 w-10 shrink-0 overflow-hidden rounded-full border border-edge p-0.5',\n 'transition-[border-color,background-color] duration-200 ease-out',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-base',\n 'active:scale-[0.97] motion-reduce:transition-none motion-reduce:active:scale-100',\n checked ? 'bg-accent' : 'bg-surface-hover',\n )}\n onClick={() => onChange(!checked)}\n >\n <span\n className={cn(\n 'pointer-events-none absolute left-0.5 top-1/2 block size-4 -translate-y-1/2 rounded-full bg-surface-panel shadow-surface ring-1 ring-edge/40 dark:ring-edge/55',\n 'transition-transform duration-200 ease-out motion-reduce:transition-none',\n checked ? 'translate-x-5' : 'translate-x-0',\n )}\n aria-hidden\n />\n </button>\n );\n}\n\nasync function fileToZipUpload(file: File): Promise<File> {\n const lower = file.name.toLowerCase();\n if (lower.endsWith('.zip')) return file;\n if (lower.endsWith('skill.md')) {\n const JSZip = (await import('jszip')).default;\n const zip = new JSZip();\n zip.file('SKILL.md', await file.arrayBuffer());\n const blob = await zip.generateAsync({ type: 'blob', compression: 'DEFLATE' });\n const base = file.name.replace(/\\.md$/i, '').replace(/\\s+/g, '-') || 'skill';\n return new File([blob], `${base}.zip`, { type: 'application/zip' });\n }\n throw new Error('invalid');\n}\n\nconst SKILL_LIST_SKELETON_COUNT = 6;\n\nfunction SkillListRowSkeleton() {\n const skel =\n 'animate-pulse motion-reduce:animate-none rounded-md bg-surface-hover dark:bg-surface-active/50';\n return (\n <div className=\"flex items-center gap-4 px-4 py-3.5\" aria-hidden>\n <div className={cn('size-11 shrink-0 rounded-xl', skel)} />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className={cn('h-4 max-w-[10rem]', skel)} />\n <div className={cn('h-3 w-full max-w-xl rounded', skel)} />\n </div>\n <div className={cn('h-6 w-10 shrink-0 rounded-full', skel)} />\n </div>\n );\n}\n\nexport function SkillsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const sk = m.skills;\n const token = useGatewayStore((st) => st.token);\n const hasToken = Boolean(token);\n const [searchParams, setSearchParams] = useSearchParams();\n\n const [catalog, setCatalog] = useState<SkillCatalogEntry[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [uploading, setUploading] = useState(false);\n const initialSearch = searchParams.get('q') ?? '';\n const initialTabRaw = searchParams.get('tab');\n const initialSourceRaw = searchParams.get('source');\n const initialTab: MainTab = MAIN_TAB_SET.has(initialTabRaw as MainTab)\n ? (initialTabRaw as MainTab)\n : 'builtin';\n const initialSourceFilter: SourceFilter = SOURCE_FILTER_SET.has(initialSourceRaw as SourceFilter)\n ? (initialSourceRaw as SourceFilter)\n : 'all';\n\n const [searchQuery, setSearchQuery] = useState(initialSearch);\n const [actionFeedback, setActionFeedback] = useState<{\n kind: 'success' | 'error';\n message: string;\n } | null>(null);\n\n const [mainTab, setMainTab] = useState<MainTab>(initialTab);\n const [sourceFilter, setSourceFilter] = useState<SourceFilter>(initialSourceFilter);\n\n const [installOpen, setInstallOpen] = useState(false);\n const [pendingFile, setPendingFile] = useState<File | null>(null);\n const [dropActive, setDropActive] = useState(false);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [confirmId, setConfirmId] = useState<string | null>(null);\n const [togglingSkillName, setTogglingSkillName] = useState<string | null>(null);\n /** Optimistic `enabled` until `load` completes — avoids switch lag + disabled/opacity flicker. */\n const [enabledOverride, setEnabledOverride] = useState<Record<string, boolean>>({});\n\n const [detailOpen, setDetailOpen] = useState(false);\n const [detailSource, setDetailSource] = useState<'catalog' | 'store'>('catalog');\n const [detailTitle, setDetailTitle] = useState('');\n const [detailMarkdown, setDetailMarkdown] = useState('');\n const [detailLoading, setDetailLoading] = useState(false);\n const [detailError, setDetailError] = useState<string | null>(null);\n\n const [marketSort, setMarketSort] = useState<'downloads' | 'newest'>('downloads');\n const [marketPage, setMarketPage] = useState(1);\n const [mpLoading, setMpLoading] = useState(false);\n const [mpError, setMpError] = useState<string | null>(null);\n const [mpPayload, setMpPayload] = useState<{\n items: MarketplacePackageItem[];\n meta: { page: number; pageSize: number; total: number; totalPages: number };\n } | null>(null);\n const [installingMarketName, setInstallingMarketName] = useState<string | null>(null);\n\n const load = useCallback(\n async (opts?: { silent?: boolean }): Promise<{ ok: true } | { ok: false; message: string }> => {\n const silent = opts?.silent === true;\n if (!silent) {\n setLoading(true);\n }\n setError(null);\n try {\n const data = await getSkills();\n setCatalog(data.catalog.map(normalizeCatalogEntry));\n return { ok: true };\n } catch (e) {\n const message = e instanceof Error ? e.message : sk.loadFailed;\n setError(message);\n return { ok: false, message };\n } finally {\n if (!silent) {\n setLoading(false);\n }\n }\n },\n [sk.loadFailed],\n );\n\n useEffect(() => {\n if (!hasToken) return;\n void load();\n }, [hasToken, load]);\n\n useEffect(() => {\n const nextQ = searchParams.get('q') ?? '';\n const nextTabRaw = searchParams.get('tab');\n const nextSourceRaw = searchParams.get('source');\n const nextTab: MainTab = MAIN_TAB_SET.has(nextTabRaw as MainTab)\n ? (nextTabRaw as MainTab)\n : 'builtin';\n const nextSource: SourceFilter = SOURCE_FILTER_SET.has(nextSourceRaw as SourceFilter)\n ? (nextSourceRaw as SourceFilter)\n : 'all';\n setSearchQuery((prev) => (prev === nextQ ? prev : nextQ));\n setMainTab((prev) => (prev === nextTab ? prev : nextTab));\n setSourceFilter((prev) => (prev === nextSource ? prev : nextSource));\n }, [searchParams]);\n\n useEffect(() => {\n if (mainTab !== 'marketplace') return;\n setMarketPage(1);\n }, [searchQuery, marketSort, mainTab]);\n\n useEffect(() => {\n if (!hasToken || mainTab !== 'marketplace') return;\n let cancelled = false;\n setMpLoading(true);\n setMpError(null);\n void getMarketplaceSkills({\n q: searchQuery.trim() || undefined,\n page: marketPage,\n pageSize: 20,\n sort: marketSort,\n })\n .then((payload) => {\n if (!cancelled) setMpPayload(payload);\n })\n .catch((e) => {\n if (!cancelled) {\n setMpError(e instanceof Error ? e.message : sk.marketplaceLoadFailed);\n setMpPayload(null);\n }\n })\n .finally(() => {\n if (!cancelled) setMpLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [hasToken, mainTab, marketPage, marketSort, searchQuery, sk.marketplaceLoadFailed]);\n\n useEffect(() => {\n const params = new URLSearchParams(searchParams);\n const nextQ = searchQuery.trim();\n if (nextQ) params.set('q', nextQ);\n else params.delete('q');\n if (mainTab !== 'builtin') params.set('tab', mainTab);\n else params.delete('tab');\n if (sourceFilter !== 'all') params.set('source', sourceFilter);\n else params.delete('source');\n const next = params.toString();\n if (next !== searchParams.toString()) {\n setSearchParams(params, { replace: true });\n }\n }, [mainTab, searchParams, searchQuery, setSearchParams, sourceFilter]);\n\n const showFeedback = useCallback((kind: 'success' | 'error', message: string, durationMs = 5000) => {\n setActionFeedback({ kind, message });\n window.setTimeout(() => setActionFeedback(null), durationMs);\n }, []);\n\n const openSkillDetail = useCallback(\n async (row: SkillCatalogEntry) => {\n setDetailSource('catalog');\n setDetailOpen(true);\n setDetailTitle(row.name);\n setDetailMarkdown('');\n setDetailError(null);\n setDetailLoading(true);\n try {\n const { markdown, name } = await getSkillMarkdown(row.name);\n setDetailMarkdown(markdown);\n setDetailTitle(name);\n } catch (e) {\n setDetailError(e instanceof Error ? e.message : sk.detailLoadFailed);\n } finally {\n setDetailLoading(false);\n }\n },\n [sk.detailLoadFailed],\n );\n\n const openMarketplaceDetail = useCallback(\n async (name: string) => {\n setDetailSource('store');\n setDetailOpen(true);\n setDetailTitle(name);\n setDetailMarkdown('');\n setDetailError(null);\n setDetailLoading(true);\n try {\n const pkg = await getMarketplacePackageDetail(name);\n setDetailTitle(pkg.name);\n const readme = pkg.readme?.trim();\n if (readme) {\n setDetailMarkdown(readme);\n } else if (pkg.description?.trim()) {\n setDetailMarkdown(`## ${pkg.name}\\n\\n${pkg.description.trim()}`);\n } else {\n setDetailMarkdown(`*${sk.marketplaceNoReadme}*`);\n }\n } catch (e) {\n setDetailError(e instanceof Error ? e.message : sk.detailLoadFailed);\n } finally {\n setDetailLoading(false);\n }\n },\n [sk.detailLoadFailed, sk.marketplaceNoReadme],\n );\n\n const onSkillToggle = useCallback(\n async (name: string, next: boolean): Promise<boolean> => {\n setTogglingSkillName(name);\n setEnabledOverride((prev) => ({ ...prev, [name]: next }));\n setActionFeedback(null);\n try {\n await patchSkillEnabled(name, next);\n await load({ silent: true });\n return true;\n } catch (e) {\n setEnabledOverride((prev) => {\n const { [name]: _, ...rest } = prev;\n return rest;\n });\n const msg = e instanceof Error ? e.message : sk.skillToggleFailed;\n showFeedback('error', msg);\n return false;\n } finally {\n setTogglingSkillName(null);\n setEnabledOverride((prev) => {\n const { [name]: _, ...rest } = prev;\n return rest;\n });\n }\n },\n [load, showFeedback, sk.skillToggleFailed],\n );\n\n const onReloadClick = useCallback(async () => {\n setActionFeedback(null);\n setLoading(true);\n setError(null);\n try {\n await reloadSkills();\n } catch (e) {\n const msg = e instanceof Error ? e.message : sk.reloadFailed;\n setError(msg);\n setLoading(false);\n return;\n }\n await load();\n }, [load, sk.reloadFailed]);\n\n const builtinTabStats = useMemo(() => {\n const rows = catalog.filter((r) => r.source === 'builtin');\n return {\n total: rows.length,\n enabled: rows.filter((r) => enabledOverride[r.name] ?? r.enabled).length,\n };\n }, [catalog, enabledOverride]);\n\n const userTabStats = useMemo(() => {\n const rows = catalog.filter((r) => r.source !== 'builtin');\n return {\n total: rows.length,\n enabled: rows.filter((r) => enabledOverride[r.name] ?? r.enabled).length,\n };\n }, [catalog, enabledOverride]);\n\n const detailFromCatalog = useMemo(\n () => (detailTitle ? catalog.find((r) => r.name === detailTitle) : undefined),\n [catalog, detailTitle],\n );\n const detailEnabled =\n detailFromCatalog == null\n ? true\n : (enabledOverride[detailTitle] ?? detailFromCatalog.enabled);\n\n const filteredCatalog = useMemo(() => {\n const q = searchQuery.trim().toLowerCase();\n let rows = catalog;\n\n if (mainTab === 'builtin') {\n rows = rows.filter((r) => r.source === 'builtin');\n } else {\n rows = rows.filter((r) => r.source !== 'builtin');\n if (sourceFilter !== 'all') {\n rows = rows.filter((r) => r.source === sourceFilter);\n }\n }\n\n if (!q) return rows;\n return rows.filter((row) => {\n const blob = [\n row.name,\n row.description,\n row.directoryId,\n row.path,\n row.source,\n row.hub?.source,\n row.hub?.ref,\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n return blob.includes(q);\n });\n }, [catalog, searchQuery, mainTab, sourceFilter]);\n\n const runUpload = async (file: File) => {\n setActionFeedback(null);\n setUploading(true);\n setError(null);\n try {\n let upload: File;\n try {\n upload = await fileToZipUpload(file);\n } catch {\n setError(sk.invalidFile);\n showFeedback('error', sk.invalidFile);\n return;\n }\n await uploadSkillZip(upload, { overwrite: true });\n await load();\n showFeedback('success', sk.installSuccess);\n setInstallOpen(false);\n setPendingFile(null);\n setMainTab('user');\n } catch (err) {\n setError(err instanceof Error ? err.message : sk.uploadFailed);\n showFeedback('error', err instanceof Error ? err.message : sk.uploadFailed);\n } finally {\n setUploading(false);\n }\n };\n\n const onInstallSubmit = () => {\n if (pendingFile) void runUpload(pendingFile);\n };\n\n const onFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (file) setPendingFile(file);\n };\n\n const onModalDragOver = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.dataTransfer.types.includes('Files')) {\n setDropActive(true);\n e.dataTransfer.dropEffect = 'copy';\n }\n };\n\n const onModalDragLeave = (e: React.DragEvent) => {\n const root = e.currentTarget as HTMLElement;\n const to = e.relatedTarget as Node | null;\n if (to && root.contains(to)) return;\n setDropActive(false);\n };\n\n const onModalDrop = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setDropActive(false);\n const file = e.dataTransfer?.files?.[0];\n if (file) setPendingFile(file);\n };\n\n const sourceLabel = (source: SkillCatalogEntry['source']): string => {\n switch (source) {\n case 'builtin':\n return sk.source.builtin;\n case 'workspace':\n return sk.source.workspace;\n case 'global':\n return sk.source.global;\n case 'extra':\n return sk.source.extra;\n default:\n return source;\n }\n };\n\n const runDelete = async () => {\n const id = confirmId;\n setConfirmOpen(false);\n setConfirmId(null);\n if (!id) return;\n setActionFeedback(null);\n try {\n await deleteSkill(id);\n await load();\n } catch (e) {\n setError(e instanceof Error ? e.message : sk.deleteFailed);\n }\n };\n\n const isSkillInstalledByName = useCallback(\n (name: string) => catalog.some((r) => r.name === name),\n [catalog],\n );\n\n const onMarketInstall = useCallback(\n async (name: string) => {\n const installed = isSkillInstalledByName(name);\n if (installed) {\n const ok = window.confirm(sk.marketplaceReinstallConfirm);\n if (!ok) return;\n }\n setActionFeedback(null);\n setInstallingMarketName(name);\n try {\n await installMarketplaceSkill({ name, overwrite: installed });\n await load({ silent: true });\n showFeedback('success', sk.installSuccess);\n setDetailOpen(false);\n setMainTab('user');\n } catch (e) {\n showFeedback('error', e instanceof Error ? e.message : sk.uploadFailed);\n } finally {\n setInstallingMarketName(null);\n }\n },\n [\n isSkillInstalledByName,\n load,\n showFeedback,\n sk.installSuccess,\n sk.marketplaceReinstallConfirm,\n sk.uploadFailed,\n ],\n );\n\n const filterLabel =\n sourceFilter === 'all'\n ? sk.filterAll\n : sourceFilter === 'global'\n ? sk.filterGlobal\n : sourceFilter === 'workspace'\n ? sk.filterWorkspace\n : sk.filterExtra;\n\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n const { pathname } = useLocation();\n const inSettingsShell = pathname.startsWith('/settings/');\n\n const skillsHeaderEnd = useMemo(\n () => (\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 w-9 shrink-0 p-0\"\n disabled={loading}\n title={sk.reloadRuntime}\n aria-label={sk.reloadDiskAria}\n onClick={() => void onReloadClick()}\n >\n <RefreshCw className={cn('size-4', loading && 'animate-spin')} strokeWidth={1.75} />\n </Button>\n <label className=\"relative flex min-h-9 min-w-0 max-w-sm cursor-text items-center rounded-pill border border-edge bg-surface-base py-1.5 pl-9 pr-3 shadow-surface dark:bg-surface-hover/40 sm:max-w-md\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-disabled\"\n strokeWidth={1.75}\n aria-hidden\n />\n <input\n type=\"text\"\n role=\"searchbox\"\n enterKeyHint=\"search\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder={sk.searchPlaceholder}\n autoComplete=\"off\"\n spellCheck={false}\n className=\"min-w-0 flex-1 appearance-none border-0 bg-transparent py-0.5 text-sm leading-normal text-fg caret-current placeholder:text-fg-disabled focus:border-0 focus:shadow-none focus:outline-none focus:ring-0 focus-visible:outline-none\"\n />\n </label>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"shrink-0 gap-2\"\n onClick={() => {\n setPendingFile(null);\n setInstallOpen(true);\n }}\n >\n <Plus className=\"size-4\" strokeWidth={1.75} aria-hidden />\n {sk.installCta}\n </Button>\n </div>\n ),\n [\n loading,\n onReloadClick,\n searchQuery,\n setInstallOpen,\n setPendingFile,\n setSearchQuery,\n sk.installCta,\n sk.reloadDiskAria,\n sk.reloadRuntime,\n sk.searchPlaceholder,\n ],\n );\n\n useLayoutEffect(() => {\n if (!hasToken || inSettingsShell) {\n clearPageHeader();\n return () => clearPageHeader();\n }\n setPageHeader({\n startExtra: null,\n main: null,\n end: skillsHeaderEnd,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, hasToken, inSettingsShell, setPageHeader, skillsHeaderEnd]);\n\n if (!hasToken) {\n return (\n <div className=\"mx-auto w-full max-w-app-main px-4 py-16 text-center text-sm text-fg-muted sm:px-8\">\n {sk.needToken}\n </div>\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-6 px-4 py-6 sm:px-8\">\n {actionFeedback ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n 'rounded-xl border px-3 py-2 text-sm',\n actionFeedback.kind === 'success'\n ? 'border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-900/40 dark:bg-emerald-950/40 dark:text-emerald-200'\n : 'border-red-200 bg-red-50 text-red-800 dark:border-red-900/50 dark:bg-red-950/40 dark:text-red-200',\n )}\n >\n {actionFeedback.message}\n </div>\n ) : error ? (\n <div\n className=\"rounded-xl border border-edge bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-edge dark:bg-red-950/40 dark:text-red-300\"\n role=\"alert\"\n >\n {error}\n </div>\n ) : null}\n\n <header className=\"flex flex-col gap-4\">\n <div className=\"min-w-0\">\n <h1 className=\"text-xl font-semibold tracking-tight text-fg\">{sk.title}</h1>\n <p className=\"mt-1 max-w-2xl text-sm text-fg-muted\">{sk.tagline}</p>\n </div>\n </header>\n\n {inSettingsShell ? (\n <div className=\"flex flex-col gap-3 border-b border-edge-subtle pb-4 dark:border-edge-subtle sm:flex-row sm:flex-wrap sm:items-center sm:justify-end\">\n {skillsHeaderEnd}\n </div>\n ) : null}\n\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-3 border-b border-edge-subtle pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-edge-subtle\">\n <div className=\"flex gap-1\" role=\"tablist\" aria-label={sk.skillsNavAria}>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'builtin'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'builtin' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'builtin' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('builtin')}\n >\n {sk.tabBuiltin}\n <span className=\"ml-1 tabular-nums text-fg-muted\">\n ({builtinTabStats.enabled}/{builtinTabStats.total})\n </span>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'user'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'user' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'user' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('user')}\n >\n {sk.tabUser}\n <span className=\"ml-1 tabular-nums text-fg-muted\">\n ({userTabStats.enabled}/{userTabStats.total})\n </span>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'marketplace'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'marketplace' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'marketplace' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('marketplace')}\n >\n {sk.tabMarketplace}\n </button>\n </div>\n <div\n className={cn(\n 'flex min-w-0 items-center gap-2',\n mainTab === 'user'\n ? 'flex-nowrap overflow-x-auto pb-0.5 sm:justify-end'\n : 'flex-wrap sm:justify-end',\n )}\n >\n {mainTab === 'user' ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'inline-flex h-9 min-h-9 min-w-[9rem] shrink-0 items-center gap-1.5 rounded-lg border border-edge bg-surface-panel px-2.5 text-xs font-medium text-fg shadow-surface',\n interaction.transition,\n interaction.focusRingPanel,\n )}\n >\n <Funnel className=\"size-3.5 text-fg-muted\" strokeWidth={1.75} aria-hidden />\n <span>{filterLabel}</span>\n <ChevronDown className=\"size-3.5 text-fg-subtle\" strokeWidth={1.75} aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[10rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={6}\n align=\"end\"\n >\n {(['all', 'global', 'workspace', 'extra'] as const).map((key) => (\n <DropdownMenu.Item\n key={key}\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setSourceFilter(key)}\n >\n {key === 'all'\n ? sk.filterAll\n : key === 'global'\n ? sk.filterGlobal\n : key === 'workspace'\n ? sk.filterWorkspace\n : sk.filterExtra}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n {mainTab === 'marketplace' ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'inline-flex h-9 min-h-9 min-w-[9rem] shrink-0 items-center gap-1.5 rounded-lg border border-edge bg-surface-panel px-2.5 text-xs font-medium text-fg shadow-surface',\n interaction.transition,\n interaction.focusRingPanel,\n )}\n >\n <Funnel className=\"size-3.5 text-fg-muted\" strokeWidth={1.75} aria-hidden />\n <span>\n {marketSort === 'newest' ? sk.marketplaceSortNewest : sk.marketplaceSortDownloads}\n </span>\n <ChevronDown className=\"size-3.5 text-fg-subtle\" strokeWidth={1.75} aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[10rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={6}\n align=\"end\"\n >\n <DropdownMenu.Item\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setMarketSort('downloads')}\n >\n {sk.marketplaceSortDownloads}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setMarketSort('newest')}\n >\n {sk.marketplaceSortNewest}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n </div>\n </div>\n\n {mainTab === 'marketplace' ? (\n <>\n <p className=\"text-xs font-medium uppercase tracking-wide text-fg-subtle\">\n {sk.sectionMarketplace}\n </p>\n {mpLoading ? (\n <div\n className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: SKILL_LIST_SKELETON_COUNT }, (_, i) => (\n <SkillListRowSkeleton key={i} />\n ))}\n </div>\n ) : mpError ? (\n <div\n className=\"rounded-xl border border-edge bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-edge dark:bg-red-950/40 dark:text-red-300\"\n role=\"alert\"\n >\n {mpError}\n </div>\n ) : !mpPayload || mpPayload.items.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.marketplaceEmpty}\n </div>\n ) : (\n <>\n <div className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\">\n {mpPayload.items.map((row) => {\n const installed = isSkillInstalledByName(row.name);\n const busy = installingMarketName === row.name;\n return (\n <article\n key={row.id}\n className={cn(\n 'group relative flex flex-col gap-3 border-b border-edge-subtle px-4 py-3.5 last:border-b-0 sm:flex-row sm:items-center',\n 'transition-colors hover:bg-surface-hover/50 dark:hover:bg-surface-hover/25',\n )}\n >\n <button\n type=\"button\"\n className={cn(\n 'flex min-w-0 flex-1 cursor-pointer items-start gap-4 rounded-xl text-left outline-none',\n interaction.focusRingPanel,\n )}\n onClick={() => void openMarketplaceDetail(row.name)}\n >\n <SkillCardIcon name={row.name} />\n <div className=\"min-w-0 flex-1 pr-2\">\n <h3 className=\"text-[15px] font-semibold leading-snug tracking-tight text-fg\">\n {row.name}\n </h3>\n <p\n className=\"mt-0.5 line-clamp-2 text-sm leading-relaxed text-fg-muted\"\n title={row.description || undefined}\n >\n {row.description || '—'}\n </p>\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-fg-subtle\">\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceAuthor}: {row.author.username}\n </span>\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceDownloads}: {row.downloads}\n </span>\n {row.latestVersion ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 font-mono text-[10px] dark:bg-surface-active/50\">\n {sk.marketplaceVersion}: {row.latestVersion}\n </span>\n ) : null}\n {installed ? (\n <span className=\"rounded-md bg-emerald-500/15 px-2 py-0.5 text-emerald-800 dark:text-emerald-200\">\n {sk.marketplaceInstalled}\n </span>\n ) : null}\n </div>\n </div>\n </button>\n <div className=\"flex shrink-0 justify-end sm:pl-2\">\n <Button\n type=\"button\"\n variant={installed ? 'secondary' : 'primary'}\n className=\"min-w-[6.5rem]\"\n disabled={busy || mpLoading}\n onClick={() => void onMarketInstall(row.name)}\n >\n {busy ? sk.uploading : installed ? sk.marketplaceReinstall : sk.marketplaceInstall}\n </Button>\n </div>\n </article>\n );\n })}\n </div>\n <div className=\"flex flex-col items-center justify-between gap-3 sm:flex-row\">\n <p className=\"text-center text-xs text-fg-muted sm:text-left\">\n {interpolate(sk.marketplacePageStatus, {\n page: mpPayload.meta.page,\n totalPages: mpPayload.meta.totalPages,\n total: mpPayload.meta.total,\n })}\n </p>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 gap-1 px-2\"\n disabled={mpLoading || marketPage <= 1}\n aria-label={sk.marketplacePagePrev}\n onClick={() => setMarketPage((p) => Math.max(1, p - 1))}\n >\n <ChevronLeft className=\"size-4\" strokeWidth={1.75} aria-hidden />\n <span className=\"sr-only sm:not-sr-only\">{sk.marketplacePagePrev}</span>\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 gap-1 px-2\"\n disabled={mpLoading || marketPage >= mpPayload.meta.totalPages}\n aria-label={sk.marketplacePageNext}\n onClick={() =>\n setMarketPage((p) => Math.min(mpPayload.meta.totalPages, p + 1))\n }\n >\n <span className=\"sr-only sm:not-sr-only\">{sk.marketplacePageNext}</span>\n <ChevronRight className=\"size-4\" strokeWidth={1.75} aria-hidden />\n </Button>\n </div>\n </div>\n </>\n )}\n </>\n ) : (\n <>\n <p className=\"text-xs font-medium uppercase tracking-wide text-fg-subtle\">\n {mainTab === 'builtin' ? sk.sectionBuiltinList : sk.sectionUser}\n </p>\n\n {loading ? (\n <div\n className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: SKILL_LIST_SKELETON_COUNT }, (_, i) => (\n <SkillListRowSkeleton key={i} />\n ))}\n </div>\n ) : catalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.empty}\n </div>\n ) : filteredCatalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.noSearchResults}\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\">\n {filteredCatalog.map((row) => (\n <article\n key={`${row.directoryId}-${row.path}`}\n className={cn(\n 'group relative flex items-center gap-4 border-b border-edge-subtle px-4 py-3.5 last:border-b-0',\n 'transition-colors hover:bg-surface-hover/50 dark:hover:bg-surface-hover/25',\n )}\n >\n <button\n type=\"button\"\n className={cn(\n 'flex min-w-0 flex-1 cursor-pointer items-center gap-4 rounded-lg text-left outline-none',\n interaction.focusRingPanel,\n )}\n onClick={() => void openSkillDetail(row)}\n >\n <SkillCardIcon name={row.name} />\n <div className=\"min-w-0 flex-1 pr-2\">\n <h3 className=\"text-[15px] font-semibold leading-snug tracking-tight text-fg\">\n {row.name}\n </h3>\n <p\n className=\"mt-0.5 truncate text-sm leading-relaxed text-fg-muted\"\n title={row.description ? row.description : undefined}\n >\n {row.description || '—'}\n </p>\n {mainTab !== 'builtin' || row.managed ? (\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-fg-subtle\">\n {mainTab !== 'builtin' ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sourceLabel(row.source)}\n </span>\n ) : null}\n {row.managed ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.col.managed}: {sk.yes}\n </span>\n ) : null}\n {row.hub ? (\n <span\n className=\"max-w-full truncate rounded-md bg-surface-hover/60 px-2 py-0.5 font-mono text-[10px] dark:bg-surface-active/50\"\n title={`${row.hub.source}${row.hub.ref ? `\\nref: ${row.hub.ref}` : ''}\\nupdated: ${row.hub.updatedAt}`}\n >\n {sk.hubRemote} ·{' '}\n {row.hub.kind === 'git' ? sk.hubKindGit : sk.hubKindArchive} ·{' '}\n {row.hub.source.length > 48\n ? `${row.hub.source.slice(0, 48)}…`\n : row.hub.source}\n </span>\n ) : null}\n </div>\n ) : null}\n </div>\n </button>\n <div\n className=\"flex shrink-0 items-center gap-1\"\n onClick={(e) => e.stopPropagation()}\n role=\"presentation\"\n >\n {row.managed ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.col.actions}\n >\n <MoreVertical className=\"size-4\" strokeWidth={1.75} />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[8rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={4}\n align=\"end\"\n >\n <DropdownMenu.Item\n className={cn(\n 'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 outline-none',\n 'hover:bg-red-50 data-[highlighted]:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/40',\n )}\n onSelect={() => {\n setConfirmId(row.directoryId);\n setConfirmOpen(true);\n }}\n >\n <Trash2 className=\"size-4\" strokeWidth={1.75} aria-hidden />\n {sk.delete}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n <SkillEnableSwitch\n checked={enabledOverride[row.name] ?? row.enabled}\n onChange={(next) => void onSkillToggle(row.name, next)}\n />\n </div>\n </article>\n ))}\n </div>\n )}\n </>\n )}\n </section>\n </div>\n\n {/* SKILL.md preview */}\n <Dialog.Root\n open={detailOpen}\n onOpenChange={(open) => {\n setDetailOpen(open);\n if (!open) {\n setDetailSource('catalog');\n setDetailMarkdown('');\n setDetailError(null);\n setDetailTitle('');\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content\n className={cn(\n 'xopc-dialog-content fixed left-1/2 top-1/2 z-[60] flex max-h-[min(90vh,56rem)] w-[min(100%-2rem,min(92vw,56rem))] -translate-x-1/2 -translate-y-1/2 flex-col',\n 'rounded-2xl border border-edge bg-surface-panel shadow-float dark:border-edge',\n )}\n >\n <div className=\"group flex shrink-0 items-center gap-3 border-b border-edge px-4 py-3\">\n <SkillCardIcon name={detailTitle || '?'} />\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-base font-semibold text-fg\">\n {detailTitle || '—'}\n </Dialog.Title>\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className={cn(\n 'rounded-lg p-1.5 text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.detailCloseAria}\n >\n <X className=\"size-5\" strokeWidth={1.75} aria-hidden />\n </button>\n </Dialog.Close>\n </div>\n <div className=\"flex shrink-0 items-start gap-2 border-b border-blue-200/80 bg-blue-50/95 px-4 py-2.5 text-sm text-fg dark:border-blue-900/50 dark:bg-blue-950/45\">\n <Info className=\"mt-0.5 size-4 shrink-0 text-blue-600 dark:text-blue-400\" strokeWidth={1.75} aria-hidden />\n <p className=\"leading-relaxed\">\n {detailSource === 'store' ? sk.detailModalBannerStore : sk.detailModalBanner}\n </p>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto px-4 py-4\">\n {detailLoading ? (\n <div className=\"space-y-2\" aria-busy=\"true\">\n <div className=\"h-4 w-2/3 animate-pulse rounded bg-surface-hover\" />\n <div className=\"h-4 w-full animate-pulse rounded bg-surface-hover\" />\n <div className=\"h-4 w-5/6 animate-pulse rounded bg-surface-hover\" />\n </div>\n ) : detailError ? (\n <p className=\"text-sm text-red-600 dark:text-red-400\">{detailError}</p>\n ) : (\n <div className=\"markdown-content min-w-0\">\n <MarkdownView content={detailMarkdown} />\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 justify-end gap-2 border-t border-edge px-4 py-3\">\n {detailSource === 'store' ? (\n <>\n <Button type=\"button\" variant=\"ghost\" onClick={() => setDetailOpen(false)}>\n {sk.cancel}\n </Button>\n <Button\n type=\"button\"\n variant={isSkillInstalledByName(detailTitle) ? 'secondary' : 'primary'}\n disabled={!detailTitle || installingMarketName === detailTitle}\n onClick={() => {\n if (!detailTitle) return;\n void onMarketInstall(detailTitle);\n }}\n >\n {installingMarketName === detailTitle\n ? sk.uploading\n : isSkillInstalledByName(detailTitle)\n ? sk.marketplaceReinstall\n : sk.marketplaceInstall}\n </Button>\n </>\n ) : (\n <Button\n type=\"button\"\n variant=\"primary\"\n disabled={!detailTitle || togglingSkillName === detailTitle}\n onClick={async () => {\n if (!detailTitle) return;\n const ok = await onSkillToggle(detailTitle, !detailEnabled);\n if (ok) setDetailOpen(false);\n }}\n >\n {detailEnabled ? sk.detailModalDisable : sk.detailModalEnable}\n </Button>\n )}\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n\n {/* Install modal */}\n <Dialog.Root\n open={installOpen}\n onOpenChange={(open) => {\n setInstallOpen(open);\n if (!open) {\n setPendingFile(null);\n setDropActive(false);\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content\n className={cn(\n 'xopc-dialog-content fixed left-1/2 top-1/2 z-[60] max-h-[min(100vh-2rem,44rem)] w-[min(100%-2rem,min(92vw,48rem))] -translate-x-1/2 -translate-y-1/2 overflow-y-auto',\n 'rounded-2xl border border-edge bg-surface-panel p-6 shadow-float dark:border-edge',\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <Dialog.Title className=\"text-base font-semibold text-fg\">{sk.installModalTitle}</Dialog.Title>\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className={cn(\n 'rounded-lg p-1.5 text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.installClose}\n >\n <X className=\"size-5\" strokeWidth={1.75} aria-hidden />\n <span className=\"sr-only\">{sk.installClose}</span>\n </button>\n </Dialog.Close>\n </div>\n\n <label\n className={cn(\n 'mt-4 flex min-h-[11rem] cursor-pointer flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed px-6 py-12 text-center transition-colors',\n dropActive\n ? 'border-accent bg-accent-soft/60 dark:bg-blue-950/40'\n : 'border-edge bg-surface-base dark:bg-surface-hover/30',\n )}\n onDragLeave={onModalDragLeave}\n onDragOver={onModalDragOver}\n onDrop={onModalDrop}\n >\n <input\n type=\"file\"\n accept=\".zip,.md,application/zip,text/markdown\"\n className=\"sr-only\"\n aria-label={sk.installModalDropHint}\n disabled={uploading}\n onChange={onFileInputChange}\n />\n <FileArchive className=\"size-12 text-fg-subtle\" strokeWidth={1.25} aria-hidden />\n <span className=\"text-sm text-fg-muted\">{sk.installModalDropHint}</span>\n {pendingFile ? (\n <span className=\"text-xs font-medium text-fg\">{pendingFile.name}</span>\n ) : null}\n </label>\n\n <div className=\"mt-5 space-y-2\">\n <p className=\"text-sm font-medium text-fg\">{sk.installModalReqTitle}</p>\n <ul className=\"list-inside list-disc space-y-1 text-sm text-fg-muted\">\n <li>{sk.installModalReq1}</li>\n <li>{sk.installModalReq2}</li>\n </ul>\n </div>\n\n <button\n type=\"button\"\n disabled={!pendingFile || uploading}\n className={cn(\n 'mt-6 flex w-full items-center justify-center rounded-xl py-3 text-sm font-semibold',\n 'transition-colors',\n !pendingFile || uploading\n ? 'cursor-not-allowed bg-surface-active text-fg-disabled'\n : 'bg-accent text-white hover:bg-accent-hover',\n interaction.focusRingPanel,\n )}\n onClick={() => void onInstallSubmit()}\n >\n {uploading ? sk.uploading : sk.installAction}\n </button>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n\n <Dialog.Root\n open={confirmOpen}\n onOpenChange={(open) => {\n setConfirmOpen(open);\n if (!open) setConfirmId(null);\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content className=\"xopc-dialog-content fixed left-1/2 top-1/2 z-[60] w-[min(100%-2rem,24rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-edge bg-surface-panel p-4 shadow-popover dark:border-edge\">\n <Dialog.Title className=\"text-base font-semibold text-fg\">{sk.deleteTitle}</Dialog.Title>\n <p className=\"mt-2 text-sm text-fg-muted\">\n {confirmId ? interpolate(sk.deleteMessage, { id: confirmId }) : ''}\n </p>\n <div className=\"mt-4 flex justify-end gap-2\">\n <Button type=\"button\" variant=\"secondary\" onClick={() => setConfirmOpen(false)}>\n {sk.cancel}\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"bg-red-600 hover:bg-red-700\"\n onClick={() => void runDelete()}\n >\n {sk.deleteConfirm}\n </Button>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n </div>\n );\n}\n"],"file":"skills-page-Dd8ZzYJb.js"}
1
+ {"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../../../web/src/features/skills/skills-page.tsx"],"sourcesContent":["import * as Dialog from '@radix-ui/react-dialog';\nimport * as DropdownMenu from '@radix-ui/react-dropdown-menu';\nimport type { LucideIcon } from 'lucide-react';\nimport {\n BookOpen,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n FileArchive,\n FileText,\n FileType,\n Funnel,\n Info,\n MoreVertical,\n Package,\n Plus,\n Presentation,\n Puzzle,\n RefreshCw,\n Search,\n Sparkles,\n Table2,\n Trash2,\n X,\n} from 'lucide-react';\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { useLocation, useSearchParams } from 'react-router-dom';\n\nimport { MarkdownView } from '@/components/markdown/markdown-view';\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/lib/cn';\nimport { interaction } from '@/lib/interaction';\nimport {\n deleteSkill,\n getMarketplacePackageDetail,\n getMarketplaceSkills,\n getSkillMarkdown,\n getSkills,\n installMarketplaceSkill,\n patchSkillEnabled,\n reloadSkills,\n uploadSkillZip,\n} from '@/features/skills/skill-api';\nimport type { MarketplacePackageItem, SkillCatalogEntry } from '@/features/skills/skill.types';\nimport { messages } from '@/i18n/messages';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\nimport { usePageHeaderStore } from '@/stores/page-header-store';\n\nfunction interpolate(template: string, params: Record<string, string | number>): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key) => String(params[key] ?? ''));\n}\n\n/** Distinct glyph per skill id — avoids duplicate “first letter” collisions (e.g. create-skill vs install-skill-dependency). */\nfunction resolveSkillIcon(name: string): LucideIcon {\n const n = name.toLowerCase().replace(/_/g, '-');\n if (n.includes('find-skill')) return Search;\n if (n.includes('install') && (n.includes('depend') || n.includes('dependency'))) return Package;\n if (n.includes('create-skill')) return Sparkles;\n if (n === 'docx' || n.endsWith('-docx')) return FileText;\n if (n === 'pdf' || n.endsWith('-pdf')) return FileType;\n if (n === 'pptx' || n.includes('pptx')) return Presentation;\n if (n === 'xlsx' || n.includes('xlsx')) return Table2;\n if (n.includes('markdown') || n.includes('md')) return BookOpen;\n return Puzzle;\n}\n\nfunction SkillCardIcon({ name, className }: { name: string; className?: string }) {\n const Icon = resolveSkillIcon(name);\n return (\n <div\n className={cn(\n 'flex size-11 shrink-0 items-center justify-center rounded-xl',\n 'bg-surface-hover/90 shadow-surface ring-1 ring-inset ring-edge/35 dark:bg-surface-active/80 dark:ring-edge/50',\n 'transition-[transform,box-shadow] duration-200 ease-out group-hover:ring-edge/55 dark:group-hover:ring-edge/65',\n 'group-hover:-translate-y-px',\n className,\n )}\n aria-hidden\n >\n <Icon\n className=\"size-[1.35rem] text-fg-muted transition-colors duration-200 group-hover:text-fg\"\n strokeWidth={1.75}\n />\n </div>\n );\n}\n\ntype MainTab = 'builtin' | 'user' | 'marketplace';\ntype SourceFilter = 'all' | 'global' | 'workspace' | 'extra';\nconst MAIN_TAB_SET = new Set<MainTab>(['builtin', 'user', 'marketplace']);\nconst SOURCE_FILTER_SET = new Set<SourceFilter>(['all', 'global', 'workspace', 'extra']);\n\nfunction normalizeCatalogEntry(r: SkillCatalogEntry): SkillCatalogEntry {\n return {\n ...r,\n enabled: r.enabled ?? true,\n disableModelInvocation: r.disableModelInvocation ?? false,\n };\n}\n\nfunction SkillEnableSwitch({\n checked,\n onChange,\n}: {\n checked: boolean;\n onChange: (next: boolean) => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n className={cn(\n 'relative h-6 w-10 shrink-0 overflow-hidden rounded-full border border-edge p-0.5',\n 'transition-[border-color,background-color] duration-200 ease-out',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-surface-base',\n 'active:scale-[0.97] motion-reduce:transition-none motion-reduce:active:scale-100',\n checked ? 'bg-accent' : 'bg-surface-hover',\n )}\n onClick={() => onChange(!checked)}\n >\n <span\n className={cn(\n 'pointer-events-none absolute left-0.5 top-1/2 block size-4 -translate-y-1/2 rounded-full bg-surface-panel shadow-surface ring-1 ring-edge/40 dark:ring-edge/55',\n 'transition-transform duration-200 ease-out motion-reduce:transition-none',\n checked ? 'translate-x-5' : 'translate-x-0',\n )}\n aria-hidden\n />\n </button>\n );\n}\n\nasync function fileToZipUpload(file: File): Promise<File> {\n const lower = file.name.toLowerCase();\n if (lower.endsWith('.zip')) return file;\n if (lower.endsWith('skill.md')) {\n const JSZip = (await import('jszip')).default;\n const zip = new JSZip();\n zip.file('SKILL.md', await file.arrayBuffer());\n const blob = await zip.generateAsync({ type: 'blob', compression: 'DEFLATE' });\n const base = file.name.replace(/\\.md$/i, '').replace(/\\s+/g, '-') || 'skill';\n return new File([blob], `${base}.zip`, { type: 'application/zip' });\n }\n throw new Error('invalid');\n}\n\nconst SKILL_LIST_SKELETON_COUNT = 6;\n\nfunction SkillListRowSkeleton() {\n const skel =\n 'animate-pulse motion-reduce:animate-none rounded-md bg-surface-hover dark:bg-surface-active/50';\n return (\n <div className=\"flex items-center gap-4 px-4 py-3.5\" aria-hidden>\n <div className={cn('size-11 shrink-0 rounded-xl', skel)} />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className={cn('h-4 max-w-[10rem]', skel)} />\n <div className={cn('h-3 w-full max-w-xl rounded', skel)} />\n </div>\n <div className={cn('h-6 w-10 shrink-0 rounded-full', skel)} />\n </div>\n );\n}\n\nexport function SkillsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const sk = m.skills;\n const token = useGatewayStore((st) => st.token);\n const hasToken = Boolean(token);\n const [searchParams, setSearchParams] = useSearchParams();\n\n const [catalog, setCatalog] = useState<SkillCatalogEntry[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [uploading, setUploading] = useState(false);\n const initialSearch = searchParams.get('q') ?? '';\n const initialTabRaw = searchParams.get('tab');\n const initialSourceRaw = searchParams.get('source');\n const initialTab: MainTab = MAIN_TAB_SET.has(initialTabRaw as MainTab)\n ? (initialTabRaw as MainTab)\n : 'builtin';\n const initialSourceFilter: SourceFilter = SOURCE_FILTER_SET.has(initialSourceRaw as SourceFilter)\n ? (initialSourceRaw as SourceFilter)\n : 'all';\n\n const [searchQuery, setSearchQuery] = useState(initialSearch);\n const [actionFeedback, setActionFeedback] = useState<{\n kind: 'success' | 'error';\n message: string;\n } | null>(null);\n\n const [mainTab, setMainTab] = useState<MainTab>(initialTab);\n const [sourceFilter, setSourceFilter] = useState<SourceFilter>(initialSourceFilter);\n\n const [installOpen, setInstallOpen] = useState(false);\n const [pendingFile, setPendingFile] = useState<File | null>(null);\n const [dropActive, setDropActive] = useState(false);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [confirmId, setConfirmId] = useState<string | null>(null);\n const [togglingSkillName, setTogglingSkillName] = useState<string | null>(null);\n /** Optimistic `enabled` until `load` completes — avoids switch lag + disabled/opacity flicker. */\n const [enabledOverride, setEnabledOverride] = useState<Record<string, boolean>>({});\n\n const [detailOpen, setDetailOpen] = useState(false);\n const [detailSource, setDetailSource] = useState<'catalog' | 'store'>('catalog');\n const [detailTitle, setDetailTitle] = useState('');\n const [detailMarkdown, setDetailMarkdown] = useState('');\n const [detailLoading, setDetailLoading] = useState(false);\n const [detailError, setDetailError] = useState<string | null>(null);\n\n const [marketSort, setMarketSort] = useState<'downloads' | 'newest'>('downloads');\n const [marketPage, setMarketPage] = useState(1);\n const [mpLoading, setMpLoading] = useState(false);\n const [mpError, setMpError] = useState<string | null>(null);\n const [mpPayload, setMpPayload] = useState<{\n items: MarketplacePackageItem[];\n meta: { page: number; pageSize: number; total: number; totalPages: number };\n } | null>(null);\n const [installingMarketName, setInstallingMarketName] = useState<string | null>(null);\n\n const load = useCallback(\n async (opts?: { silent?: boolean }): Promise<{ ok: true } | { ok: false; message: string }> => {\n const silent = opts?.silent === true;\n if (!silent) {\n setLoading(true);\n }\n setError(null);\n try {\n const data = await getSkills();\n setCatalog(data.catalog.map(normalizeCatalogEntry));\n return { ok: true };\n } catch (e) {\n const message = e instanceof Error ? e.message : sk.loadFailed;\n setError(message);\n return { ok: false, message };\n } finally {\n if (!silent) {\n setLoading(false);\n }\n }\n },\n [sk.loadFailed],\n );\n\n useEffect(() => {\n if (!hasToken) return;\n void load();\n }, [hasToken, load]);\n\n useEffect(() => {\n const nextQ = searchParams.get('q') ?? '';\n const nextTabRaw = searchParams.get('tab');\n const nextSourceRaw = searchParams.get('source');\n const nextTab: MainTab = MAIN_TAB_SET.has(nextTabRaw as MainTab)\n ? (nextTabRaw as MainTab)\n : 'builtin';\n const nextSource: SourceFilter = SOURCE_FILTER_SET.has(nextSourceRaw as SourceFilter)\n ? (nextSourceRaw as SourceFilter)\n : 'all';\n setSearchQuery((prev) => (prev === nextQ ? prev : nextQ));\n setMainTab((prev) => (prev === nextTab ? prev : nextTab));\n setSourceFilter((prev) => (prev === nextSource ? prev : nextSource));\n }, [searchParams]);\n\n useEffect(() => {\n if (mainTab !== 'marketplace') return;\n setMarketPage(1);\n }, [searchQuery, marketSort, mainTab]);\n\n useEffect(() => {\n if (!hasToken || mainTab !== 'marketplace') return;\n let cancelled = false;\n setMpLoading(true);\n setMpError(null);\n void getMarketplaceSkills({\n q: searchQuery.trim() || undefined,\n page: marketPage,\n pageSize: 20,\n sort: marketSort,\n })\n .then((payload) => {\n if (!cancelled) setMpPayload(payload);\n })\n .catch((e) => {\n if (!cancelled) {\n setMpError(e instanceof Error ? e.message : sk.marketplaceLoadFailed);\n setMpPayload(null);\n }\n })\n .finally(() => {\n if (!cancelled) setMpLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [hasToken, mainTab, marketPage, marketSort, searchQuery, sk.marketplaceLoadFailed]);\n\n useEffect(() => {\n const params = new URLSearchParams(searchParams);\n const nextQ = searchQuery.trim();\n if (nextQ) params.set('q', nextQ);\n else params.delete('q');\n if (mainTab !== 'builtin') params.set('tab', mainTab);\n else params.delete('tab');\n if (sourceFilter !== 'all') params.set('source', sourceFilter);\n else params.delete('source');\n const next = params.toString();\n if (next !== searchParams.toString()) {\n setSearchParams(params, { replace: true });\n }\n }, [mainTab, searchParams, searchQuery, setSearchParams, sourceFilter]);\n\n const showFeedback = useCallback((kind: 'success' | 'error', message: string, durationMs = 5000) => {\n setActionFeedback({ kind, message });\n window.setTimeout(() => setActionFeedback(null), durationMs);\n }, []);\n\n const openSkillDetail = useCallback(\n async (row: SkillCatalogEntry) => {\n setDetailSource('catalog');\n setDetailOpen(true);\n setDetailTitle(row.name);\n setDetailMarkdown('');\n setDetailError(null);\n setDetailLoading(true);\n try {\n const { markdown, name } = await getSkillMarkdown(row.name);\n setDetailMarkdown(markdown);\n setDetailTitle(name);\n } catch (e) {\n setDetailError(e instanceof Error ? e.message : sk.detailLoadFailed);\n } finally {\n setDetailLoading(false);\n }\n },\n [sk.detailLoadFailed],\n );\n\n const openMarketplaceDetail = useCallback(\n async (name: string) => {\n setDetailSource('store');\n setDetailOpen(true);\n setDetailTitle(name);\n setDetailMarkdown('');\n setDetailError(null);\n setDetailLoading(true);\n try {\n const pkg = await getMarketplacePackageDetail(name);\n setDetailTitle(pkg.name);\n const readme = pkg.readme?.trim();\n if (readme) {\n setDetailMarkdown(readme);\n } else if (pkg.description?.trim()) {\n setDetailMarkdown(`## ${pkg.name}\\n\\n${pkg.description.trim()}`);\n } else {\n setDetailMarkdown(`*${sk.marketplaceNoReadme}*`);\n }\n } catch (e) {\n setDetailError(e instanceof Error ? e.message : sk.detailLoadFailed);\n } finally {\n setDetailLoading(false);\n }\n },\n [sk.detailLoadFailed, sk.marketplaceNoReadme],\n );\n\n const onSkillToggle = useCallback(\n async (name: string, next: boolean): Promise<boolean> => {\n setTogglingSkillName(name);\n setEnabledOverride((prev) => ({ ...prev, [name]: next }));\n setActionFeedback(null);\n try {\n await patchSkillEnabled(name, next);\n await load({ silent: true });\n return true;\n } catch (e) {\n setEnabledOverride((prev) => {\n const { [name]: _, ...rest } = prev;\n return rest;\n });\n const msg = e instanceof Error ? e.message : sk.skillToggleFailed;\n showFeedback('error', msg);\n return false;\n } finally {\n setTogglingSkillName(null);\n setEnabledOverride((prev) => {\n const { [name]: _, ...rest } = prev;\n return rest;\n });\n }\n },\n [load, showFeedback, sk.skillToggleFailed],\n );\n\n const onReloadClick = useCallback(async () => {\n setActionFeedback(null);\n setLoading(true);\n setError(null);\n try {\n await reloadSkills();\n } catch (e) {\n const msg = e instanceof Error ? e.message : sk.reloadFailed;\n setError(msg);\n setLoading(false);\n return;\n }\n await load();\n }, [load, sk.reloadFailed]);\n\n const builtinTabStats = useMemo(() => {\n const rows = catalog.filter((r) => r.source === 'builtin');\n return {\n total: rows.length,\n enabled: rows.filter((r) => enabledOverride[r.name] ?? r.enabled).length,\n };\n }, [catalog, enabledOverride]);\n\n const userTabStats = useMemo(() => {\n const rows = catalog.filter((r) => r.source !== 'builtin');\n return {\n total: rows.length,\n enabled: rows.filter((r) => enabledOverride[r.name] ?? r.enabled).length,\n };\n }, [catalog, enabledOverride]);\n\n const detailFromCatalog = useMemo(\n () => (detailTitle ? catalog.find((r) => r.name === detailTitle) : undefined),\n [catalog, detailTitle],\n );\n const detailEnabled =\n detailFromCatalog == null\n ? true\n : (enabledOverride[detailTitle] ?? detailFromCatalog.enabled);\n\n const filteredCatalog = useMemo(() => {\n const q = searchQuery.trim().toLowerCase();\n let rows = catalog;\n\n if (mainTab === 'builtin') {\n rows = rows.filter((r) => r.source === 'builtin');\n } else {\n rows = rows.filter((r) => r.source !== 'builtin');\n if (sourceFilter !== 'all') {\n rows = rows.filter((r) => r.source === sourceFilter);\n }\n }\n\n if (!q) return rows;\n return rows.filter((row) => {\n const blob = [\n row.name,\n row.description,\n row.directoryId,\n row.path,\n row.source,\n row.hub?.source,\n row.hub?.ref,\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n return blob.includes(q);\n });\n }, [catalog, searchQuery, mainTab, sourceFilter]);\n\n const runUpload = async (file: File) => {\n setActionFeedback(null);\n setUploading(true);\n setError(null);\n try {\n let upload: File;\n try {\n upload = await fileToZipUpload(file);\n } catch {\n setError(sk.invalidFile);\n showFeedback('error', sk.invalidFile);\n return;\n }\n await uploadSkillZip(upload, { overwrite: true });\n await load();\n showFeedback('success', sk.installSuccess);\n setInstallOpen(false);\n setPendingFile(null);\n setMainTab('user');\n } catch (err) {\n setError(err instanceof Error ? err.message : sk.uploadFailed);\n showFeedback('error', err instanceof Error ? err.message : sk.uploadFailed);\n } finally {\n setUploading(false);\n }\n };\n\n const onInstallSubmit = () => {\n if (pendingFile) void runUpload(pendingFile);\n };\n\n const onFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (file) setPendingFile(file);\n };\n\n const onModalDragOver = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.dataTransfer.types.includes('Files')) {\n setDropActive(true);\n e.dataTransfer.dropEffect = 'copy';\n }\n };\n\n const onModalDragLeave = (e: React.DragEvent) => {\n const root = e.currentTarget as HTMLElement;\n const to = e.relatedTarget as Node | null;\n if (to && root.contains(to)) return;\n setDropActive(false);\n };\n\n const onModalDrop = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setDropActive(false);\n const file = e.dataTransfer?.files?.[0];\n if (file) setPendingFile(file);\n };\n\n const sourceLabel = (source: SkillCatalogEntry['source']): string => {\n switch (source) {\n case 'builtin':\n return sk.source.builtin;\n case 'workspace':\n return sk.source.workspace;\n case 'global':\n return sk.source.global;\n case 'extra':\n return sk.source.extra;\n default:\n return source;\n }\n };\n\n const runDelete = async () => {\n const id = confirmId;\n setConfirmOpen(false);\n setConfirmId(null);\n if (!id) return;\n setActionFeedback(null);\n try {\n await deleteSkill(id);\n await load();\n } catch (e) {\n setError(e instanceof Error ? e.message : sk.deleteFailed);\n }\n };\n\n const isSkillInstalledByName = useCallback(\n (name: string) => catalog.some((r) => r.name === name),\n [catalog],\n );\n\n const onMarketInstall = useCallback(\n async (name: string) => {\n const installed = isSkillInstalledByName(name);\n if (installed) {\n const ok = window.confirm(sk.marketplaceReinstallConfirm);\n if (!ok) return;\n }\n setActionFeedback(null);\n setInstallingMarketName(name);\n try {\n await installMarketplaceSkill({ name, overwrite: installed });\n await load({ silent: true });\n showFeedback('success', sk.installSuccess);\n setDetailOpen(false);\n setMainTab('user');\n } catch (e) {\n showFeedback('error', e instanceof Error ? e.message : sk.uploadFailed);\n } finally {\n setInstallingMarketName(null);\n }\n },\n [\n isSkillInstalledByName,\n load,\n showFeedback,\n sk.installSuccess,\n sk.marketplaceReinstallConfirm,\n sk.uploadFailed,\n ],\n );\n\n const filterLabel =\n sourceFilter === 'all'\n ? sk.filterAll\n : sourceFilter === 'global'\n ? sk.filterGlobal\n : sourceFilter === 'workspace'\n ? sk.filterWorkspace\n : sk.filterExtra;\n\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n const { pathname } = useLocation();\n const inSettingsShell = pathname.startsWith('/settings/');\n\n const skillsHeaderEnd = useMemo(\n () => (\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 w-9 shrink-0 p-0\"\n disabled={loading}\n title={sk.reloadRuntime}\n aria-label={sk.reloadDiskAria}\n onClick={() => void onReloadClick()}\n >\n <RefreshCw className={cn('size-4', loading && 'animate-spin')} strokeWidth={1.75} />\n </Button>\n <label className=\"relative flex min-h-9 min-w-0 max-w-sm cursor-text items-center rounded-pill border border-edge bg-surface-base py-1.5 pl-9 pr-3 shadow-surface dark:bg-surface-hover/40 sm:max-w-md\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-disabled\"\n strokeWidth={1.75}\n aria-hidden\n />\n <input\n type=\"text\"\n role=\"searchbox\"\n enterKeyHint=\"search\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder={sk.searchPlaceholder}\n autoComplete=\"off\"\n spellCheck={false}\n className=\"min-w-0 flex-1 appearance-none border-0 bg-transparent py-0.5 text-sm leading-normal text-fg caret-current placeholder:text-fg-disabled focus:border-0 focus:shadow-none focus:outline-none focus:ring-0 focus-visible:outline-none\"\n />\n </label>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"shrink-0 gap-2\"\n onClick={() => {\n setPendingFile(null);\n setInstallOpen(true);\n }}\n >\n <Plus className=\"size-4\" strokeWidth={1.75} aria-hidden />\n {sk.installCta}\n </Button>\n </div>\n ),\n [\n loading,\n onReloadClick,\n searchQuery,\n setInstallOpen,\n setPendingFile,\n setSearchQuery,\n sk.installCta,\n sk.reloadDiskAria,\n sk.reloadRuntime,\n sk.searchPlaceholder,\n ],\n );\n\n useLayoutEffect(() => {\n if (!hasToken || inSettingsShell) {\n clearPageHeader();\n return () => clearPageHeader();\n }\n setPageHeader({\n startExtra: null,\n main: null,\n end: skillsHeaderEnd,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, hasToken, inSettingsShell, setPageHeader, skillsHeaderEnd]);\n\n if (!hasToken) {\n return (\n <div className=\"mx-auto w-full max-w-app-main px-4 py-16 text-center text-sm text-fg-muted sm:px-8\">\n {sk.needToken}\n </div>\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-6 px-4 py-6 sm:px-8\">\n {actionFeedback ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n 'rounded-xl border px-3 py-2 text-sm',\n actionFeedback.kind === 'success'\n ? 'border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-900/40 dark:bg-emerald-950/40 dark:text-emerald-200'\n : 'border-red-200 bg-red-50 text-red-800 dark:border-red-900/50 dark:bg-red-950/40 dark:text-red-200',\n )}\n >\n {actionFeedback.message}\n </div>\n ) : error ? (\n <div\n className=\"rounded-xl border border-edge bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-edge dark:bg-red-950/40 dark:text-red-300\"\n role=\"alert\"\n >\n {error}\n </div>\n ) : null}\n\n <header className=\"flex flex-col gap-4\">\n <div className=\"min-w-0\">\n <h1 className=\"text-xl font-semibold tracking-tight text-fg\">{sk.title}</h1>\n <p className=\"mt-1 max-w-2xl text-sm text-fg-muted\">{sk.tagline}</p>\n </div>\n </header>\n\n {inSettingsShell ? (\n <div className=\"flex flex-col gap-3 border-b border-edge-subtle pb-4 dark:border-edge-subtle sm:flex-row sm:flex-wrap sm:items-center sm:justify-end\">\n {skillsHeaderEnd}\n </div>\n ) : null}\n\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-3 border-b border-edge-subtle pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-edge-subtle\">\n <div className=\"flex gap-1\" role=\"tablist\" aria-label={sk.skillsNavAria}>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'builtin'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'builtin' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'builtin' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('builtin')}\n >\n {sk.tabBuiltin}\n <span className=\"ml-1 tabular-nums text-fg-muted\">\n ({builtinTabStats.enabled}/{builtinTabStats.total})\n </span>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'user'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'user' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'user' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('user')}\n >\n {sk.tabUser}\n <span className=\"ml-1 tabular-nums text-fg-muted\">\n ({userTabStats.enabled}/{userTabStats.total})\n </span>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mainTab === 'marketplace'}\n className={cn(\n 'relative rounded-md px-3 py-2 text-sm font-medium transition-colors',\n mainTab === 'marketplace' ? 'text-fg' : 'text-fg-muted hover:text-fg',\n mainTab === 'marketplace' &&\n 'after:absolute after:bottom-0 after:left-1/2 after:h-0.5 after:w-9 after:-translate-x-1/2 after:rounded-full after:bg-accent',\n )}\n onClick={() => setMainTab('marketplace')}\n >\n {sk.tabMarketplace}\n </button>\n </div>\n <div\n className={cn(\n 'flex min-w-0 items-center gap-2',\n mainTab === 'user'\n ? 'flex-nowrap overflow-x-auto pb-0.5 sm:justify-end'\n : 'flex-wrap sm:justify-end',\n )}\n >\n {mainTab === 'user' ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'inline-flex h-9 min-h-9 min-w-[9rem] shrink-0 items-center gap-1.5 rounded-lg border border-edge bg-surface-panel px-2.5 text-xs font-medium text-fg shadow-surface',\n interaction.transition,\n interaction.focusRingPanel,\n )}\n >\n <Funnel className=\"size-3.5 text-fg-muted\" strokeWidth={1.75} aria-hidden />\n <span>{filterLabel}</span>\n <ChevronDown className=\"size-3.5 text-fg-subtle\" strokeWidth={1.75} aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[10rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={6}\n align=\"end\"\n >\n {(['all', 'global', 'workspace', 'extra'] as const).map((key) => (\n <DropdownMenu.Item\n key={key}\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setSourceFilter(key)}\n >\n {key === 'all'\n ? sk.filterAll\n : key === 'global'\n ? sk.filterGlobal\n : key === 'workspace'\n ? sk.filterWorkspace\n : sk.filterExtra}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n {mainTab === 'marketplace' ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'inline-flex h-9 min-h-9 min-w-[9rem] shrink-0 items-center gap-1.5 rounded-lg border border-edge bg-surface-panel px-2.5 text-xs font-medium text-fg shadow-surface',\n interaction.transition,\n interaction.focusRingPanel,\n )}\n >\n <Funnel className=\"size-3.5 text-fg-muted\" strokeWidth={1.75} aria-hidden />\n <span>\n {marketSort === 'newest' ? sk.marketplaceSortNewest : sk.marketplaceSortDownloads}\n </span>\n <ChevronDown className=\"size-3.5 text-fg-subtle\" strokeWidth={1.75} aria-hidden />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[10rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={6}\n align=\"end\"\n >\n <DropdownMenu.Item\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setMarketSort('downloads')}\n >\n {sk.marketplaceSortDownloads}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n className={cn(\n 'cursor-pointer rounded-lg px-3 py-2 text-sm text-fg outline-none',\n 'hover:bg-surface-hover data-[highlighted]:bg-surface-hover',\n )}\n onSelect={() => setMarketSort('newest')}\n >\n {sk.marketplaceSortNewest}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n </div>\n </div>\n\n {mainTab === 'marketplace' ? (\n <>\n <p className=\"text-xs font-medium uppercase tracking-wide text-fg-subtle\">\n {sk.sectionMarketplace}\n </p>\n {mpLoading ? (\n <div\n className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: SKILL_LIST_SKELETON_COUNT }, (_, i) => (\n <SkillListRowSkeleton key={i} />\n ))}\n </div>\n ) : mpError ? (\n <div\n className=\"rounded-xl border border-edge bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-edge dark:bg-red-950/40 dark:text-red-300\"\n role=\"alert\"\n >\n {mpError}\n </div>\n ) : !mpPayload || mpPayload.items.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.marketplaceEmpty}\n </div>\n ) : (\n <>\n <div className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\">\n {mpPayload.items.map((row) => {\n const installed = isSkillInstalledByName(row.name);\n const busy = installingMarketName === row.name;\n return (\n <article\n key={row.id}\n className={cn(\n 'group relative flex flex-col gap-3 border-b border-edge-subtle px-4 py-3.5 last:border-b-0 sm:flex-row sm:items-center',\n 'transition-colors hover:bg-surface-hover/50 dark:hover:bg-surface-hover/25',\n )}\n >\n <button\n type=\"button\"\n className={cn(\n 'flex min-w-0 flex-1 cursor-pointer items-start gap-4 rounded-xl text-left outline-none',\n interaction.focusRingPanel,\n )}\n onClick={() => void openMarketplaceDetail(row.name)}\n >\n <SkillCardIcon name={row.name} />\n <div className=\"min-w-0 flex-1 pr-2\">\n <h3 className=\"text-[15px] font-semibold leading-snug tracking-tight text-fg\">\n {row.name}\n </h3>\n <p\n className=\"mt-0.5 line-clamp-2 text-sm leading-relaxed text-fg-muted\"\n title={row.description || undefined}\n >\n {row.description || '—'}\n </p>\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-fg-subtle\">\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceAuthor}: {row.author.username}\n </span>\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.marketplaceDownloads}: {row.downloads}\n </span>\n {row.latestVersion ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 font-mono text-[10px] dark:bg-surface-active/50\">\n {sk.marketplaceVersion}: {row.latestVersion}\n </span>\n ) : null}\n {installed ? (\n <span className=\"rounded-md bg-emerald-500/15 px-2 py-0.5 text-emerald-800 dark:text-emerald-200\">\n {sk.marketplaceInstalled}\n </span>\n ) : null}\n </div>\n </div>\n </button>\n <div className=\"flex shrink-0 justify-end sm:pl-2\">\n <Button\n type=\"button\"\n variant={installed ? 'secondary' : 'primary'}\n className=\"min-w-[6.5rem]\"\n disabled={busy || mpLoading}\n onClick={() => void onMarketInstall(row.name)}\n >\n {busy ? sk.uploading : installed ? sk.marketplaceReinstall : sk.marketplaceInstall}\n </Button>\n </div>\n </article>\n );\n })}\n </div>\n <div className=\"flex flex-col items-center justify-between gap-3 sm:flex-row\">\n <p className=\"text-center text-xs text-fg-muted sm:text-left\">\n {interpolate(sk.marketplacePageStatus, {\n page: mpPayload.meta.page,\n totalPages: mpPayload.meta.totalPages,\n total: mpPayload.meta.total,\n })}\n </p>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 gap-1 px-2\"\n disabled={mpLoading || marketPage <= 1}\n aria-label={sk.marketplacePagePrev}\n onClick={() => setMarketPage((p) => Math.max(1, p - 1))}\n >\n <ChevronLeft className=\"size-4\" strokeWidth={1.75} aria-hidden />\n <span className=\"sr-only sm:not-sr-only\">{sk.marketplacePagePrev}</span>\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-9 gap-1 px-2\"\n disabled={mpLoading || marketPage >= mpPayload.meta.totalPages}\n aria-label={sk.marketplacePageNext}\n onClick={() =>\n setMarketPage((p) => Math.min(mpPayload.meta.totalPages, p + 1))\n }\n >\n <span className=\"sr-only sm:not-sr-only\">{sk.marketplacePageNext}</span>\n <ChevronRight className=\"size-4\" strokeWidth={1.75} aria-hidden />\n </Button>\n </div>\n </div>\n </>\n )}\n </>\n ) : (\n <>\n <p className=\"text-xs font-medium uppercase tracking-wide text-fg-subtle\">\n {mainTab === 'builtin' ? sk.sectionBuiltinList : sk.sectionUser}\n </p>\n\n {loading ? (\n <div\n className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\"\n aria-busy=\"true\"\n aria-label={sk.loading}\n >\n {Array.from({ length: SKILL_LIST_SKELETON_COUNT }, (_, i) => (\n <SkillListRowSkeleton key={i} />\n ))}\n </div>\n ) : catalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.empty}\n </div>\n ) : filteredCatalog.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed border-edge py-16 text-center text-sm text-fg-muted\">\n {sk.noSearchResults}\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-2xl border border-edge-subtle bg-surface-base dark:border-edge-subtle\">\n {filteredCatalog.map((row) => (\n <article\n key={`${row.directoryId}-${row.path}`}\n className={cn(\n 'group relative flex items-center gap-4 border-b border-edge-subtle px-4 py-3.5 last:border-b-0',\n 'transition-colors hover:bg-surface-hover/50 dark:hover:bg-surface-hover/25',\n )}\n >\n <button\n type=\"button\"\n className={cn(\n 'flex min-w-0 flex-1 cursor-pointer items-center gap-4 rounded-lg text-left outline-none',\n interaction.focusRingPanel,\n )}\n onClick={() => void openSkillDetail(row)}\n >\n <SkillCardIcon name={row.name} />\n <div className=\"min-w-0 flex-1 pr-2\">\n <h3 className=\"text-[15px] font-semibold leading-snug tracking-tight text-fg\">\n {row.name}\n </h3>\n <p\n className=\"mt-0.5 truncate text-sm leading-relaxed text-fg-muted\"\n title={row.description ? row.description : undefined}\n >\n {row.description || '—'}\n </p>\n {mainTab !== 'builtin' || row.managed ? (\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-fg-subtle\">\n {mainTab !== 'builtin' ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sourceLabel(row.source)}\n </span>\n ) : null}\n {row.managed ? (\n <span className=\"rounded-md bg-surface-hover/60 px-2 py-0.5 dark:bg-surface-active/50\">\n {sk.col.managed}: {sk.yes}\n </span>\n ) : null}\n {row.hub ? (\n <span\n className=\"max-w-full truncate rounded-md bg-surface-hover/60 px-2 py-0.5 font-mono text-[10px] dark:bg-surface-active/50\"\n title={`${row.hub.source}${row.hub.ref ? `\\nref: ${row.hub.ref}` : ''}\\nupdated: ${row.hub.updatedAt}`}\n >\n {sk.hubRemote} ·{' '}\n {row.hub.kind === 'git' ? sk.hubKindGit : sk.hubKindArchive} ·{' '}\n {row.hub.source.length > 48\n ? `${row.hub.source.slice(0, 48)}…`\n : row.hub.source}\n </span>\n ) : null}\n </div>\n ) : null}\n </div>\n </button>\n <div\n className=\"flex shrink-0 items-center gap-1\"\n onClick={(e) => e.stopPropagation()}\n role=\"presentation\"\n >\n {row.managed ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.col.actions}\n >\n <MoreVertical className=\"size-4\" strokeWidth={1.75} />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[8rem] rounded-xl border border-edge bg-surface-panel p-1 shadow-popover dark:border-edge\"\n sideOffset={4}\n align=\"end\"\n >\n <DropdownMenu.Item\n className={cn(\n 'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 outline-none',\n 'hover:bg-red-50 data-[highlighted]:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/40',\n )}\n onSelect={() => {\n setConfirmId(row.directoryId);\n setConfirmOpen(true);\n }}\n >\n <Trash2 className=\"size-4\" strokeWidth={1.75} aria-hidden />\n {sk.delete}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n ) : null}\n <SkillEnableSwitch\n checked={enabledOverride[row.name] ?? row.enabled}\n onChange={(next) => void onSkillToggle(row.name, next)}\n />\n </div>\n </article>\n ))}\n </div>\n )}\n </>\n )}\n </section>\n </div>\n\n {/* SKILL.md preview */}\n <Dialog.Root\n open={detailOpen}\n onOpenChange={(open) => {\n setDetailOpen(open);\n if (!open) {\n setDetailSource('catalog');\n setDetailMarkdown('');\n setDetailError(null);\n setDetailTitle('');\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content\n className={cn(\n 'xopc-dialog-content fixed left-1/2 top-1/2 z-[60] flex max-h-[min(90vh,56rem)] w-[min(100%-2rem,min(92vw,56rem))] -translate-x-1/2 -translate-y-1/2 flex-col',\n 'rounded-2xl border border-edge bg-surface-panel shadow-float dark:border-edge',\n )}\n >\n <div className=\"group flex shrink-0 items-center gap-3 border-b border-edge px-4 py-3\">\n <SkillCardIcon name={detailTitle || '?'} />\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-base font-semibold text-fg\">\n {detailTitle || '—'}\n </Dialog.Title>\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className={cn(\n 'rounded-lg p-1.5 text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.detailCloseAria}\n >\n <X className=\"size-5\" strokeWidth={1.75} aria-hidden />\n </button>\n </Dialog.Close>\n </div>\n <div className=\"flex shrink-0 items-start gap-2 border-b border-blue-200/80 bg-blue-50/95 px-4 py-2.5 text-sm text-fg dark:border-blue-900/50 dark:bg-blue-950/45\">\n <Info className=\"mt-0.5 size-4 shrink-0 text-blue-600 dark:text-blue-400\" strokeWidth={1.75} aria-hidden />\n <p className=\"leading-relaxed\">\n {detailSource === 'store' ? sk.detailModalBannerStore : sk.detailModalBanner}\n </p>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto px-4 py-4\">\n {detailLoading ? (\n <div className=\"space-y-2\" aria-busy=\"true\">\n <div className=\"h-4 w-2/3 animate-pulse rounded bg-surface-hover\" />\n <div className=\"h-4 w-full animate-pulse rounded bg-surface-hover\" />\n <div className=\"h-4 w-5/6 animate-pulse rounded bg-surface-hover\" />\n </div>\n ) : detailError ? (\n <p className=\"text-sm text-red-600 dark:text-red-400\">{detailError}</p>\n ) : (\n <div className=\"markdown-content min-w-0\">\n <MarkdownView content={detailMarkdown} />\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 justify-end gap-2 border-t border-edge px-4 py-3\">\n {detailSource === 'store' ? (\n <>\n <Button type=\"button\" variant=\"ghost\" onClick={() => setDetailOpen(false)}>\n {sk.cancel}\n </Button>\n <Button\n type=\"button\"\n variant={isSkillInstalledByName(detailTitle) ? 'secondary' : 'primary'}\n disabled={!detailTitle || installingMarketName === detailTitle}\n onClick={() => {\n if (!detailTitle) return;\n void onMarketInstall(detailTitle);\n }}\n >\n {installingMarketName === detailTitle\n ? sk.uploading\n : isSkillInstalledByName(detailTitle)\n ? sk.marketplaceReinstall\n : sk.marketplaceInstall}\n </Button>\n </>\n ) : (\n <Button\n type=\"button\"\n variant=\"primary\"\n disabled={!detailTitle || togglingSkillName === detailTitle}\n onClick={async () => {\n if (!detailTitle) return;\n const ok = await onSkillToggle(detailTitle, !detailEnabled);\n if (ok) setDetailOpen(false);\n }}\n >\n {detailEnabled ? sk.detailModalDisable : sk.detailModalEnable}\n </Button>\n )}\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n\n {/* Install modal */}\n <Dialog.Root\n open={installOpen}\n onOpenChange={(open) => {\n setInstallOpen(open);\n if (!open) {\n setPendingFile(null);\n setDropActive(false);\n }\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content\n className={cn(\n 'xopc-dialog-content fixed left-1/2 top-1/2 z-[60] max-h-[min(100vh-2rem,44rem)] w-[min(100%-2rem,min(92vw,48rem))] -translate-x-1/2 -translate-y-1/2 overflow-y-auto',\n 'rounded-2xl border border-edge bg-surface-panel p-6 shadow-float dark:border-edge',\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <Dialog.Title className=\"text-base font-semibold text-fg\">{sk.installModalTitle}</Dialog.Title>\n <Dialog.Close asChild>\n <button\n type=\"button\"\n className={cn(\n 'rounded-lg p-1.5 text-fg-muted hover:bg-surface-hover hover:text-fg',\n interaction.focusRingPanel,\n )}\n aria-label={sk.installClose}\n >\n <X className=\"size-5\" strokeWidth={1.75} aria-hidden />\n <span className=\"sr-only\">{sk.installClose}</span>\n </button>\n </Dialog.Close>\n </div>\n\n <label\n className={cn(\n 'mt-4 flex min-h-[11rem] cursor-pointer flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed px-6 py-12 text-center transition-colors',\n dropActive\n ? 'border-accent bg-accent-soft/60 dark:bg-blue-950/40'\n : 'border-edge bg-surface-base dark:bg-surface-hover/30',\n )}\n onDragLeave={onModalDragLeave}\n onDragOver={onModalDragOver}\n onDrop={onModalDrop}\n >\n <input\n type=\"file\"\n accept=\".zip,.md,application/zip,text/markdown\"\n className=\"sr-only\"\n aria-label={sk.installModalDropHint}\n disabled={uploading}\n onChange={onFileInputChange}\n />\n <FileArchive className=\"size-12 text-fg-subtle\" strokeWidth={1.25} aria-hidden />\n <span className=\"text-sm text-fg-muted\">{sk.installModalDropHint}</span>\n {pendingFile ? (\n <span className=\"text-xs font-medium text-fg\">{pendingFile.name}</span>\n ) : null}\n </label>\n\n <div className=\"mt-5 space-y-2\">\n <p className=\"text-sm font-medium text-fg\">{sk.installModalReqTitle}</p>\n <ul className=\"list-inside list-disc space-y-1 text-sm text-fg-muted\">\n <li>{sk.installModalReq1}</li>\n <li>{sk.installModalReq2}</li>\n </ul>\n </div>\n\n <button\n type=\"button\"\n disabled={!pendingFile || uploading}\n className={cn(\n 'mt-6 flex w-full items-center justify-center rounded-xl py-3 text-sm font-semibold',\n 'transition-colors',\n !pendingFile || uploading\n ? 'cursor-not-allowed bg-surface-active text-fg-disabled'\n : 'bg-accent text-white hover:bg-accent-hover',\n interaction.focusRingPanel,\n )}\n onClick={() => void onInstallSubmit()}\n >\n {uploading ? sk.uploading : sk.installAction}\n </button>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n\n <Dialog.Root\n open={confirmOpen}\n onOpenChange={(open) => {\n setConfirmOpen(open);\n if (!open) setConfirmId(null);\n }}\n >\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[60] bg-scrim\" />\n <Dialog.Content className=\"xopc-dialog-content fixed left-1/2 top-1/2 z-[60] w-[min(100%-2rem,24rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-edge bg-surface-panel p-4 shadow-popover dark:border-edge\">\n <Dialog.Title className=\"text-base font-semibold text-fg\">{sk.deleteTitle}</Dialog.Title>\n <p className=\"mt-2 text-sm text-fg-muted\">\n {confirmId ? interpolate(sk.deleteMessage, { id: confirmId }) : ''}\n </p>\n <div className=\"mt-4 flex justify-end gap-2\">\n <Button type=\"button\" variant=\"secondary\" onClick={() => setConfirmOpen(false)}>\n {sk.cancel}\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"bg-red-600 hover:bg-red-700\"\n onClick={() => void runDelete()}\n >\n {sk.deleteConfirm}\n </Button>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n </div>\n );\n}\n"],"file":"skills-page-C59WQpM1.js"}
@@ -1,2 +1,2 @@
1
- import{c as e}from"./url-QmwQTJ-j.js";function t(e,t){let n;try{n=e()}catch{return}return{getItem:e=>{let r=e=>e===null?null:JSON.parse(e,t?.reviver),i=n.getItem(e)??null;return i instanceof Promise?i.then(r):r(i)},setItem:(e,r)=>n.setItem(e,JSON.stringify(r,t?.replacer)),removeItem:e=>n.removeItem(e)}}var n=e=>t=>{try{let r=e(t);return r instanceof Promise?r:{then(e){return n(e)(r)},catch(e){return this}}}catch(e){return{then(e){return this},catch(t){return n(t)(e)}}}},r=(e,r)=>(i,a,o)=>{let s={storage:t(()=>window.localStorage),partialize:e=>e,version:0,merge:(e,t)=>({...t,...e}),...r},c=!1,l=0,u=new Set,d=new Set,f=s.storage;if(!f)return e((...e)=>{console.warn(`[zustand persist middleware] Unable to update item '${s.name}', the given storage is currently unavailable.`),i(...e)},a,o);let p=()=>{let e=s.partialize({...a()});return f.setItem(s.name,{state:e,version:s.version})},m=o.setState;o.setState=(e,t)=>(m(e,t),p());let h=e((...e)=>(i(...e),p()),a,o);o.getInitialState=()=>h;let g,_=()=>{if(!f)return;let e=++l;c=!1,u.forEach(e=>e(a()??h));let t=s.onRehydrateStorage?.call(s,a()??h)||void 0;return n(f.getItem.bind(f))(s.name).then(e=>{if(e)if(typeof e.version==`number`&&e.version!==s.version){if(s.migrate){let t=s.migrate(e.state,e.version);return t instanceof Promise?t.then(e=>[!0,e]):[!0,t]}console.error(`State loaded from storage couldn't be migrated since no migrate function was provided`)}else return[!1,e.state];return[!1,void 0]}).then(t=>{if(e!==l)return;let[n,r]=t;if(g=s.merge(r,a()??h),i(g,!0),n)return p()}).then(()=>{e===l&&(t?.(a(),void 0),g=a(),c=!0,d.forEach(e=>e(g)))}).catch(n=>{e===l&&t?.(void 0,n)})};return o.persist={setOptions:e=>{s={...s,...e},e.storage&&(f=e.storage)},clearStorage:()=>{f?.removeItem(s.name)},getOptions:()=>s,rehydrate:()=>_(),hasHydrated:()=>c,onHydrate:e=>(u.add(e),()=>{u.delete(e)}),onFinishHydration:e=>(d.add(e),()=>{d.delete(e)})},s.skipHydration||_(),g||h},i=`default`,a={light:{default:`#f5f5f7`,emerald:`#f0fdf4`},dark:{default:`#1c1c1e`,emerald:`#000000`}};function o(e,t){let n=document.head;if(!n)return;let r=n.querySelector(`meta[name="theme-color"][data-xopc-theme-color="true"]`);r||(r=document.createElement(`meta`),r.setAttribute(`name`,`theme-color`),r.setAttribute(`data-xopc-theme-color`,`true`),n.appendChild(r)),r.setAttribute(`content`,a[e][t])}function s(){return globalThis.matchMedia?.(`(prefers-color-scheme: dark)`).matches??!1}function c(e){return e===`system`?s()?`dark`:`light`:e}function l(){return globalThis.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches??!1}function u(e){return e===`default`||e===`emerald`?e:i}function d(e,t,n){let r=document.documentElement,i=()=>{r.classList.toggle(`dark`,e===`dark`),r.dataset.theme=e,r.dataset.colorScheme=t,o(e,t)},a=document;n&&!l()&&typeof a.startViewTransition==`function`?a.startViewTransition(i):i()}function f(){try{let e=localStorage.getItem(`xopc-web-theme`),t=`system`,n=i;if(e){let r=JSON.parse(e);r.state?.preference&&(t=r.state.preference),r.state&&`colorScheme`in r.state&&(n=u(r.state.colorScheme))}d(c(t),n,!1)}catch{d(c(`system`),`default`,!1)}}var p=e(r((e,t)=>({preference:`system`,colorScheme:i,resolved:c(`system`),setPreference:n=>{let r=c(n),{resolved:i,colorScheme:a}=t();d(r,a,r!==i),e({preference:n,resolved:r})},setColorScheme:n=>{let{resolved:r}=t();d(r,n,!0),e({colorScheme:n})}}),{name:`xopc-web-theme`,merge:(e,t)=>{let n=e??{};return{...t,...n,colorScheme:u(n.colorScheme)}}}));function m(){let{preference:e,colorScheme:t}=p.getState(),n=c(e);d(n,t,!1),p.setState({resolved:n})}function h(){let e=globalThis.matchMedia?.(`(prefers-color-scheme: dark)`);if(!e)return()=>{};let t=()=>{let{preference:e,colorScheme:t}=p.getState();if(e!==`system`)return;let n=c(`system`),r=p.getState().resolved;d(n,t,n!==r),p.setState({resolved:n})};return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)}export{r as a,p as i,h as n,m as r,f as t};
2
- //# sourceMappingURL=theme-store-CPTH77BE.js.map
1
+ import{c as e}from"./url-D7yWllI8.js";function t(e,t){let n;try{n=e()}catch{return}return{getItem:e=>{let r=e=>e===null?null:JSON.parse(e,t?.reviver),i=n.getItem(e)??null;return i instanceof Promise?i.then(r):r(i)},setItem:(e,r)=>n.setItem(e,JSON.stringify(r,t?.replacer)),removeItem:e=>n.removeItem(e)}}var n=e=>t=>{try{let r=e(t);return r instanceof Promise?r:{then(e){return n(e)(r)},catch(e){return this}}}catch(e){return{then(e){return this},catch(t){return n(t)(e)}}}},r=(e,r)=>(i,a,o)=>{let s={storage:t(()=>window.localStorage),partialize:e=>e,version:0,merge:(e,t)=>({...t,...e}),...r},c=!1,l=0,u=new Set,d=new Set,f=s.storage;if(!f)return e((...e)=>{console.warn(`[zustand persist middleware] Unable to update item '${s.name}', the given storage is currently unavailable.`),i(...e)},a,o);let p=()=>{let e=s.partialize({...a()});return f.setItem(s.name,{state:e,version:s.version})},m=o.setState;o.setState=(e,t)=>(m(e,t),p());let h=e((...e)=>(i(...e),p()),a,o);o.getInitialState=()=>h;let g,_=()=>{if(!f)return;let e=++l;c=!1,u.forEach(e=>e(a()??h));let t=s.onRehydrateStorage?.call(s,a()??h)||void 0;return n(f.getItem.bind(f))(s.name).then(e=>{if(e)if(typeof e.version==`number`&&e.version!==s.version){if(s.migrate){let t=s.migrate(e.state,e.version);return t instanceof Promise?t.then(e=>[!0,e]):[!0,t]}console.error(`State loaded from storage couldn't be migrated since no migrate function was provided`)}else return[!1,e.state];return[!1,void 0]}).then(t=>{if(e!==l)return;let[n,r]=t;if(g=s.merge(r,a()??h),i(g,!0),n)return p()}).then(()=>{e===l&&(t?.(a(),void 0),g=a(),c=!0,d.forEach(e=>e(g)))}).catch(n=>{e===l&&t?.(void 0,n)})};return o.persist={setOptions:e=>{s={...s,...e},e.storage&&(f=e.storage)},clearStorage:()=>{f?.removeItem(s.name)},getOptions:()=>s,rehydrate:()=>_(),hasHydrated:()=>c,onHydrate:e=>(u.add(e),()=>{u.delete(e)}),onFinishHydration:e=>(d.add(e),()=>{d.delete(e)})},s.skipHydration||_(),g||h},i=`default`,a={light:{default:`#f5f5f7`,emerald:`#f0fdf4`},dark:{default:`#1c1c1e`,emerald:`#000000`}};function o(e,t){let n=document.head;if(!n)return;let r=n.querySelector(`meta[name="theme-color"][data-xopc-theme-color="true"]`);r||(r=document.createElement(`meta`),r.setAttribute(`name`,`theme-color`),r.setAttribute(`data-xopc-theme-color`,`true`),n.appendChild(r)),r.setAttribute(`content`,a[e][t])}function s(){return globalThis.matchMedia?.(`(prefers-color-scheme: dark)`).matches??!1}function c(e){return e===`system`?s()?`dark`:`light`:e}function l(){return globalThis.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches??!1}function u(e){return e===`default`||e===`emerald`?e:i}function d(e,t,n){let r=document.documentElement,i=()=>{r.classList.toggle(`dark`,e===`dark`),r.dataset.theme=e,r.dataset.colorScheme=t,o(e,t)},a=document;n&&!l()&&typeof a.startViewTransition==`function`?a.startViewTransition(i):i()}function f(){try{let e=localStorage.getItem(`xopc-web-theme`),t=`system`,n=i;if(e){let r=JSON.parse(e);r.state?.preference&&(t=r.state.preference),r.state&&`colorScheme`in r.state&&(n=u(r.state.colorScheme))}d(c(t),n,!1)}catch{d(c(`system`),`default`,!1)}}var p=e(r((e,t)=>({preference:`system`,colorScheme:i,resolved:c(`system`),setPreference:n=>{let r=c(n),{resolved:i,colorScheme:a}=t();d(r,a,r!==i),e({preference:n,resolved:r})},setColorScheme:n=>{let{resolved:r}=t();d(r,n,!0),e({colorScheme:n})}}),{name:`xopc-web-theme`,merge:(e,t)=>{let n=e??{};return{...t,...n,colorScheme:u(n.colorScheme)}}}));function m(){let{preference:e,colorScheme:t}=p.getState(),n=c(e);d(n,t,!1),p.setState({resolved:n})}function h(){let e=globalThis.matchMedia?.(`(prefers-color-scheme: dark)`);if(!e)return()=>{};let t=()=>{let{preference:e,colorScheme:t}=p.getState();if(e!==`system`)return;let n=c(`system`),r=p.getState().resolved;d(n,t,n!==r),p.setState({resolved:n})};return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)}export{r as a,p as i,h as n,m as r,f as t};
2
+ //# sourceMappingURL=theme-store-CywXkKml.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-store-CPTH77BE.js","names":[],"sources":["../../../../../node_modules/.pnpm/zustand@5.0.12_@types+react@19.2.14_react@19.2.5_use-sync-external-store@1.6.0_react@19.2.5_/node_modules/zustand/esm/middleware.mjs","../../../../../web/src/stores/theme-store.ts"],"sourcesContent":["const reduxImpl = (reducer, initial) => (set, _get, api) => {\n api.dispatch = (action) => {\n set((state) => reducer(state, action), false, action);\n return action;\n };\n api.dispatchFromDevtools = true;\n return { dispatch: (...args) => api.dispatch(...args), ...initial };\n};\nconst redux = reduxImpl;\n\nconst shouldDispatchFromDevtools = (api) => !!api.dispatchFromDevtools && typeof api.dispatch === \"function\";\nconst trackedConnections = /* @__PURE__ */ new Map();\nconst getTrackedConnectionState = (name) => {\n const api = trackedConnections.get(name);\n if (!api) return {};\n return Object.fromEntries(\n Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])\n );\n};\nconst extractConnectionInformation = (store, extensionConnector, options) => {\n if (store === void 0) {\n return {\n type: \"untracked\",\n connection: extensionConnector.connect(options)\n };\n }\n const existingConnection = trackedConnections.get(options.name);\n if (existingConnection) {\n return { type: \"tracked\", store, ...existingConnection };\n }\n const newConnection = {\n connection: extensionConnector.connect(options),\n stores: {}\n };\n trackedConnections.set(options.name, newConnection);\n return { type: \"tracked\", store, ...newConnection };\n};\nconst removeStoreFromTrackedConnections = (name, store) => {\n if (store === void 0) return;\n const connectionInfo = trackedConnections.get(name);\n if (!connectionInfo) return;\n delete connectionInfo.stores[store];\n if (Object.keys(connectionInfo.stores).length === 0) {\n trackedConnections.delete(name);\n }\n};\nconst findCallerName = (stack) => {\n var _a, _b;\n if (!stack) return void 0;\n const traceLines = stack.split(\"\\n\");\n const apiSetStateLineIndex = traceLines.findIndex(\n (traceLine) => traceLine.includes(\"api.setState\")\n );\n if (apiSetStateLineIndex < 0) return void 0;\n const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || \"\";\n return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];\n};\nconst devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {\n const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;\n let extensionConnector;\n try {\n extensionConnector = (enabled != null ? enabled : (import.meta.env ? import.meta.env.MODE : void 0) !== \"production\") && window.__REDUX_DEVTOOLS_EXTENSION__;\n } catch (e) {\n }\n if (!extensionConnector) {\n return fn(set, get, api);\n }\n const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);\n let isRecording = true;\n api.setState = ((state, replace, nameOrAction) => {\n const r = set(state, replace);\n if (!isRecording) return r;\n const action = nameOrAction === void 0 ? {\n type: anonymousActionType || findCallerName(new Error().stack) || \"anonymous\"\n } : typeof nameOrAction === \"string\" ? { type: nameOrAction } : nameOrAction;\n if (store === void 0) {\n connection == null ? void 0 : connection.send(action, get());\n return r;\n }\n connection == null ? void 0 : connection.send(\n {\n ...action,\n type: `${store}/${action.type}`\n },\n {\n ...getTrackedConnectionState(options.name),\n [store]: api.getState()\n }\n );\n return r;\n });\n api.devtools = {\n cleanup: () => {\n if (connection && typeof connection.unsubscribe === \"function\") {\n connection.unsubscribe();\n }\n removeStoreFromTrackedConnections(options.name, store);\n }\n };\n const setStateFromDevtools = (...a) => {\n const originalIsRecording = isRecording;\n isRecording = false;\n set(...a);\n isRecording = originalIsRecording;\n };\n const initialState = fn(api.setState, get, api);\n if (connectionInformation.type === \"untracked\") {\n connection == null ? void 0 : connection.init(initialState);\n } else {\n connectionInformation.stores[connectionInformation.store] = api;\n connection == null ? void 0 : connection.init(\n Object.fromEntries(\n Object.entries(connectionInformation.stores).map(([key, store2]) => [\n key,\n key === connectionInformation.store ? initialState : store2.getState()\n ])\n )\n );\n }\n if (shouldDispatchFromDevtools(api)) {\n let didWarnAboutReservedActionType = false;\n const originalDispatch = api.dispatch;\n api.dispatch = (...args) => {\n if ((import.meta.env ? import.meta.env.MODE : void 0) !== \"production\" && args[0].type === \"__setState\" && !didWarnAboutReservedActionType) {\n console.warn(\n '[zustand devtools middleware] \"__setState\" action type is reserved to set state from the devtools. Avoid using it.'\n );\n didWarnAboutReservedActionType = true;\n }\n originalDispatch(...args);\n };\n }\n connection.subscribe((message) => {\n var _a;\n switch (message.type) {\n case \"ACTION\":\n if (typeof message.payload !== \"string\") {\n console.error(\n \"[zustand devtools middleware] Unsupported action format\"\n );\n return;\n }\n return parseJsonThen(\n message.payload,\n (action) => {\n if (action.type === \"__setState\") {\n if (store === void 0) {\n setStateFromDevtools(action.state);\n return;\n }\n if (Object.keys(action.state).length !== 1) {\n console.error(\n `\n [zustand devtools middleware] Unsupported __setState action format.\n When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),\n and value of this only key should be a state object. Example: { \"type\": \"__setState\", \"state\": { \"abc123Store\": { \"foo\": \"bar\" } } }\n `\n );\n }\n const stateFromDevtools = action.state[store];\n if (stateFromDevtools === void 0 || stateFromDevtools === null) {\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {\n setStateFromDevtools(stateFromDevtools);\n }\n return;\n }\n if (shouldDispatchFromDevtools(api)) {\n api.dispatch(action);\n }\n }\n );\n case \"DISPATCH\":\n switch (message.payload.type) {\n case \"RESET\":\n setStateFromDevtools(initialState);\n if (store === void 0) {\n return connection == null ? void 0 : connection.init(api.getState());\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"COMMIT\":\n if (store === void 0) {\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"ROLLBACK\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n setStateFromDevtools(state[store]);\n connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n });\n case \"JUMP_TO_STATE\":\n case \"JUMP_TO_ACTION\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {\n setStateFromDevtools(state[store]);\n }\n });\n case \"IMPORT_STATE\": {\n const { nextLiftedState } = message.payload;\n const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;\n if (!lastComputedState) return;\n if (store === void 0) {\n setStateFromDevtools(lastComputedState);\n } else {\n setStateFromDevtools(lastComputedState[store]);\n }\n connection == null ? void 0 : connection.send(\n null,\n // FIXME no-any\n nextLiftedState\n );\n return;\n }\n case \"PAUSE_RECORDING\":\n return isRecording = !isRecording;\n }\n return;\n }\n });\n return initialState;\n};\nconst devtools = devtoolsImpl;\nconst parseJsonThen = (stringified, fn) => {\n let parsed;\n try {\n parsed = JSON.parse(stringified);\n } catch (e) {\n console.error(\n \"[zustand devtools middleware] Could not parse the received json\",\n e\n );\n }\n if (parsed !== void 0) fn(parsed);\n};\n\nconst subscribeWithSelectorImpl = (fn) => (set, get, api) => {\n const origSubscribe = api.subscribe;\n api.subscribe = ((selector, optListener, options) => {\n let listener = selector;\n if (optListener) {\n const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;\n let currentSlice = selector(api.getState());\n listener = (state) => {\n const nextSlice = selector(state);\n if (!equalityFn(currentSlice, nextSlice)) {\n const previousSlice = currentSlice;\n optListener(currentSlice = nextSlice, previousSlice);\n }\n };\n if (options == null ? void 0 : options.fireImmediately) {\n optListener(currentSlice, currentSlice);\n }\n }\n return origSubscribe(listener);\n });\n const initialState = fn(set, get, api);\n return initialState;\n};\nconst subscribeWithSelector = subscribeWithSelectorImpl;\n\nfunction combine(initialState, create) {\n return (...args) => Object.assign({}, initialState, create(...args));\n}\n\nfunction createJSONStorage(getStorage, options) {\n let storage;\n try {\n storage = getStorage();\n } catch (e) {\n return;\n }\n const persistStorage = {\n getItem: (name) => {\n var _a;\n const parse = (str2) => {\n if (str2 === null) {\n return null;\n }\n return JSON.parse(str2, options == null ? void 0 : options.reviver);\n };\n const str = (_a = storage.getItem(name)) != null ? _a : null;\n if (str instanceof Promise) {\n return str.then(parse);\n }\n return parse(str);\n },\n setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),\n removeItem: (name) => storage.removeItem(name)\n };\n return persistStorage;\n}\nconst toThenable = (fn) => (input) => {\n try {\n const result = fn(input);\n if (result instanceof Promise) {\n return result;\n }\n return {\n then(onFulfilled) {\n return toThenable(onFulfilled)(result);\n },\n catch(_onRejected) {\n return this;\n }\n };\n } catch (e) {\n return {\n then(_onFulfilled) {\n return this;\n },\n catch(onRejected) {\n return toThenable(onRejected)(e);\n }\n };\n }\n};\nconst persistImpl = (config, baseOptions) => (set, get, api) => {\n let options = {\n storage: createJSONStorage(() => window.localStorage),\n partialize: (state) => state,\n version: 0,\n merge: (persistedState, currentState) => ({\n ...currentState,\n ...persistedState\n }),\n ...baseOptions\n };\n let hasHydrated = false;\n let hydrationVersion = 0;\n const hydrationListeners = /* @__PURE__ */ new Set();\n const finishHydrationListeners = /* @__PURE__ */ new Set();\n let storage = options.storage;\n if (!storage) {\n return config(\n (...args) => {\n console.warn(\n `[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`\n );\n set(...args);\n },\n get,\n api\n );\n }\n const setItem = () => {\n const state = options.partialize({ ...get() });\n return storage.setItem(options.name, {\n state,\n version: options.version\n });\n };\n const savedSetState = api.setState;\n api.setState = (state, replace) => {\n savedSetState(state, replace);\n return setItem();\n };\n const configResult = config(\n (...args) => {\n set(...args);\n return setItem();\n },\n get,\n api\n );\n api.getInitialState = () => configResult;\n let stateFromStorage;\n const hydrate = () => {\n var _a, _b;\n if (!storage) return;\n const currentVersion = ++hydrationVersion;\n hasHydrated = false;\n hydrationListeners.forEach((cb) => {\n var _a2;\n return cb((_a2 = get()) != null ? _a2 : configResult);\n });\n const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;\n return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {\n if (deserializedStorageValue) {\n if (typeof deserializedStorageValue.version === \"number\" && deserializedStorageValue.version !== options.version) {\n if (options.migrate) {\n const migration = options.migrate(\n deserializedStorageValue.state,\n deserializedStorageValue.version\n );\n if (migration instanceof Promise) {\n return migration.then((result) => [true, result]);\n }\n return [true, migration];\n }\n console.error(\n `State loaded from storage couldn't be migrated since no migrate function was provided`\n );\n } else {\n return [false, deserializedStorageValue.state];\n }\n }\n return [false, void 0];\n }).then((migrationResult) => {\n var _a2;\n if (currentVersion !== hydrationVersion) {\n return;\n }\n const [migrated, migratedState] = migrationResult;\n stateFromStorage = options.merge(\n migratedState,\n (_a2 = get()) != null ? _a2 : configResult\n );\n set(stateFromStorage, true);\n if (migrated) {\n return setItem();\n }\n }).then(() => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(get(), void 0);\n stateFromStorage = get();\n hasHydrated = true;\n finishHydrationListeners.forEach((cb) => cb(stateFromStorage));\n }).catch((e) => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);\n });\n };\n api.persist = {\n setOptions: (newOptions) => {\n options = {\n ...options,\n ...newOptions\n };\n if (newOptions.storage) {\n storage = newOptions.storage;\n }\n },\n clearStorage: () => {\n storage == null ? void 0 : storage.removeItem(options.name);\n },\n getOptions: () => options,\n rehydrate: () => hydrate(),\n hasHydrated: () => hasHydrated,\n onHydrate: (cb) => {\n hydrationListeners.add(cb);\n return () => {\n hydrationListeners.delete(cb);\n };\n },\n onFinishHydration: (cb) => {\n finishHydrationListeners.add(cb);\n return () => {\n finishHydrationListeners.delete(cb);\n };\n }\n };\n if (!options.skipHydration) {\n hydrate();\n }\n return stateFromStorage || configResult;\n};\nconst persist = persistImpl;\n\nfunction ssrSafe(config, isSSR = typeof window === \"undefined\") {\n return (set, get, api) => {\n if (!isSSR) {\n return config(set, get, api);\n }\n const ssrSet = () => {\n throw new Error(\"Cannot set state of Zustand store in SSR\");\n };\n api.setState = ssrSet;\n return config(ssrSet, get, api);\n };\n}\n\nexport { combine, createJSONStorage, devtools, persist, redux, subscribeWithSelector, ssrSafe as unstable_ssrSafe };\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\nexport type ThemePreference = 'light' | 'dark' | 'system';\n\n/** Visual color scheme — orthogonal to light/dark mode. */\nexport type ColorScheme = 'default' | 'emerald';\n\nexport const COLOR_SCHEMES: { value: ColorScheme; labelEn: string; labelZh: string }[] = [\n { value: 'default', labelEn: 'Default', labelZh: '默认' },\n { value: 'emerald', labelEn: 'Light green', labelZh: '浅绿' },\n];\n\nconst DEFAULT_COLOR_SCHEME: ColorScheme = 'default';\n\nconst THEME_META_COLOR: Record<'light' | 'dark', Record<ColorScheme, string>> = {\n light: {\n default: '#f5f5f7',\n emerald: '#f0fdf4',\n },\n dark: {\n default: '#1c1c1e',\n emerald: '#000000',\n },\n};\n\nfunction syncThemeColorMeta(mode: 'light' | 'dark', scheme: ColorScheme) {\n const head = document.head;\n if (!head) return;\n const selector = 'meta[name=\"theme-color\"][data-xopc-theme-color=\"true\"]';\n let meta = head.querySelector<HTMLMetaElement>(selector);\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n meta.setAttribute('data-xopc-theme-color', 'true');\n head.appendChild(meta);\n }\n meta.setAttribute('content', THEME_META_COLOR[mode][scheme]);\n}\n\nfunction getSystemDark(): boolean {\n return globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;\n}\n\nfunction resolveTheme(pref: ThemePreference): 'light' | 'dark' {\n if (pref === 'system') {\n return getSystemDark() ? 'dark' : 'light';\n }\n return pref;\n}\n\nfunction prefersReducedMotion(): boolean {\n return globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;\n}\n\nfunction normalizeColorScheme(value: unknown): ColorScheme {\n return value === 'default' || value === 'emerald' ? value : DEFAULT_COLOR_SCHEME;\n}\n\n/** Apply light/dark + color scheme on `<html>`. Uses View Transitions when available for a softer cross-fade. */\nfunction applyDomTheme(mode: 'light' | 'dark', scheme: ColorScheme, useViewTransition: boolean) {\n const root = document.documentElement;\n const run = () => {\n root.classList.toggle('dark', mode === 'dark');\n root.dataset.theme = mode;\n root.dataset.colorScheme = scheme;\n syncThemeColorMeta(mode, scheme);\n };\n\n const doc = document as Document & {\n startViewTransition?: (cb: () => void) => { finished: Promise<void> };\n };\n\n if (\n useViewTransition &&\n !prefersReducedMotion() &&\n typeof doc.startViewTransition === 'function'\n ) {\n doc.startViewTransition(run);\n } else {\n run();\n }\n}\n\n/** Sync DOM from localStorage before React paint (zustand persist hydrates async). */\nexport function bootstrapTheme() {\n try {\n const raw = localStorage.getItem('xopc-web-theme');\n let pref: ThemePreference = 'system';\n let scheme: ColorScheme = DEFAULT_COLOR_SCHEME;\n if (raw) {\n const parsed = JSON.parse(raw) as {\n state?: { preference?: ThemePreference; colorScheme?: ColorScheme };\n };\n if (parsed.state?.preference) pref = parsed.state.preference;\n if (parsed.state && 'colorScheme' in parsed.state) {\n scheme = normalizeColorScheme(parsed.state.colorScheme);\n }\n }\n applyDomTheme(resolveTheme(pref), scheme, false);\n } catch {\n applyDomTheme(resolveTheme('system'), 'default', false);\n }\n}\n\ntype ThemeState = {\n preference: ThemePreference;\n colorScheme: ColorScheme;\n resolved: 'light' | 'dark';\n setPreference: (p: ThemePreference) => void;\n setColorScheme: (scheme: ColorScheme) => void;\n};\n\nexport const useThemeStore = create(\n persist<ThemeState>(\n (set, get) => ({\n preference: 'system',\n colorScheme: DEFAULT_COLOR_SCHEME,\n resolved: resolveTheme('system'),\n\n setPreference: (preference) => {\n const resolved = resolveTheme(preference);\n const { resolved: prevResolved, colorScheme } = get();\n applyDomTheme(resolved, colorScheme, resolved !== prevResolved);\n set({ preference, resolved });\n },\n\n setColorScheme: (scheme) => {\n const { resolved } = get();\n applyDomTheme(resolved, scheme, true);\n set({ colorScheme: scheme });\n },\n }),\n {\n name: 'xopc-web-theme',\n merge: (persisted, current) => {\n const p = (persisted ?? {}) as Partial<ThemeState>;\n return {\n ...current,\n ...p,\n colorScheme: normalizeColorScheme(p.colorScheme),\n };\n },\n },\n ),\n);\n\nexport function syncThemeAfterHydration() {\n const { preference, colorScheme } = useThemeStore.getState();\n const resolved = resolveTheme(preference);\n applyDomTheme(resolved, colorScheme, false);\n useThemeStore.setState({ resolved });\n}\n\nexport function subscribeSystemTheme() {\n const mq = globalThis.matchMedia?.('(prefers-color-scheme: dark)');\n if (!mq) return () => {};\n\n const handler = () => {\n const { preference, colorScheme } = useThemeStore.getState();\n if (preference !== 'system') return;\n const resolved = resolveTheme('system');\n const prevResolved = useThemeStore.getState().resolved;\n applyDomTheme(resolved, colorScheme, resolved !== prevResolved);\n useThemeStore.setState({ resolved });\n };\n\n mq.addEventListener('change', handler);\n return () => mq.removeEventListener('change', handler);\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
1
+ {"version":3,"file":"theme-store-CywXkKml.js","names":[],"sources":["../../../../../node_modules/.pnpm/zustand@5.0.12_@types+react@19.2.14_react@19.2.5_use-sync-external-store@1.6.0_react@19.2.5_/node_modules/zustand/esm/middleware.mjs","../../../../../web/src/stores/theme-store.ts"],"sourcesContent":["const reduxImpl = (reducer, initial) => (set, _get, api) => {\n api.dispatch = (action) => {\n set((state) => reducer(state, action), false, action);\n return action;\n };\n api.dispatchFromDevtools = true;\n return { dispatch: (...args) => api.dispatch(...args), ...initial };\n};\nconst redux = reduxImpl;\n\nconst shouldDispatchFromDevtools = (api) => !!api.dispatchFromDevtools && typeof api.dispatch === \"function\";\nconst trackedConnections = /* @__PURE__ */ new Map();\nconst getTrackedConnectionState = (name) => {\n const api = trackedConnections.get(name);\n if (!api) return {};\n return Object.fromEntries(\n Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])\n );\n};\nconst extractConnectionInformation = (store, extensionConnector, options) => {\n if (store === void 0) {\n return {\n type: \"untracked\",\n connection: extensionConnector.connect(options)\n };\n }\n const existingConnection = trackedConnections.get(options.name);\n if (existingConnection) {\n return { type: \"tracked\", store, ...existingConnection };\n }\n const newConnection = {\n connection: extensionConnector.connect(options),\n stores: {}\n };\n trackedConnections.set(options.name, newConnection);\n return { type: \"tracked\", store, ...newConnection };\n};\nconst removeStoreFromTrackedConnections = (name, store) => {\n if (store === void 0) return;\n const connectionInfo = trackedConnections.get(name);\n if (!connectionInfo) return;\n delete connectionInfo.stores[store];\n if (Object.keys(connectionInfo.stores).length === 0) {\n trackedConnections.delete(name);\n }\n};\nconst findCallerName = (stack) => {\n var _a, _b;\n if (!stack) return void 0;\n const traceLines = stack.split(\"\\n\");\n const apiSetStateLineIndex = traceLines.findIndex(\n (traceLine) => traceLine.includes(\"api.setState\")\n );\n if (apiSetStateLineIndex < 0) return void 0;\n const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || \"\";\n return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];\n};\nconst devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {\n const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;\n let extensionConnector;\n try {\n extensionConnector = (enabled != null ? enabled : (import.meta.env ? import.meta.env.MODE : void 0) !== \"production\") && window.__REDUX_DEVTOOLS_EXTENSION__;\n } catch (e) {\n }\n if (!extensionConnector) {\n return fn(set, get, api);\n }\n const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);\n let isRecording = true;\n api.setState = ((state, replace, nameOrAction) => {\n const r = set(state, replace);\n if (!isRecording) return r;\n const action = nameOrAction === void 0 ? {\n type: anonymousActionType || findCallerName(new Error().stack) || \"anonymous\"\n } : typeof nameOrAction === \"string\" ? { type: nameOrAction } : nameOrAction;\n if (store === void 0) {\n connection == null ? void 0 : connection.send(action, get());\n return r;\n }\n connection == null ? void 0 : connection.send(\n {\n ...action,\n type: `${store}/${action.type}`\n },\n {\n ...getTrackedConnectionState(options.name),\n [store]: api.getState()\n }\n );\n return r;\n });\n api.devtools = {\n cleanup: () => {\n if (connection && typeof connection.unsubscribe === \"function\") {\n connection.unsubscribe();\n }\n removeStoreFromTrackedConnections(options.name, store);\n }\n };\n const setStateFromDevtools = (...a) => {\n const originalIsRecording = isRecording;\n isRecording = false;\n set(...a);\n isRecording = originalIsRecording;\n };\n const initialState = fn(api.setState, get, api);\n if (connectionInformation.type === \"untracked\") {\n connection == null ? void 0 : connection.init(initialState);\n } else {\n connectionInformation.stores[connectionInformation.store] = api;\n connection == null ? void 0 : connection.init(\n Object.fromEntries(\n Object.entries(connectionInformation.stores).map(([key, store2]) => [\n key,\n key === connectionInformation.store ? initialState : store2.getState()\n ])\n )\n );\n }\n if (shouldDispatchFromDevtools(api)) {\n let didWarnAboutReservedActionType = false;\n const originalDispatch = api.dispatch;\n api.dispatch = (...args) => {\n if ((import.meta.env ? import.meta.env.MODE : void 0) !== \"production\" && args[0].type === \"__setState\" && !didWarnAboutReservedActionType) {\n console.warn(\n '[zustand devtools middleware] \"__setState\" action type is reserved to set state from the devtools. Avoid using it.'\n );\n didWarnAboutReservedActionType = true;\n }\n originalDispatch(...args);\n };\n }\n connection.subscribe((message) => {\n var _a;\n switch (message.type) {\n case \"ACTION\":\n if (typeof message.payload !== \"string\") {\n console.error(\n \"[zustand devtools middleware] Unsupported action format\"\n );\n return;\n }\n return parseJsonThen(\n message.payload,\n (action) => {\n if (action.type === \"__setState\") {\n if (store === void 0) {\n setStateFromDevtools(action.state);\n return;\n }\n if (Object.keys(action.state).length !== 1) {\n console.error(\n `\n [zustand devtools middleware] Unsupported __setState action format.\n When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),\n and value of this only key should be a state object. Example: { \"type\": \"__setState\", \"state\": { \"abc123Store\": { \"foo\": \"bar\" } } }\n `\n );\n }\n const stateFromDevtools = action.state[store];\n if (stateFromDevtools === void 0 || stateFromDevtools === null) {\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {\n setStateFromDevtools(stateFromDevtools);\n }\n return;\n }\n if (shouldDispatchFromDevtools(api)) {\n api.dispatch(action);\n }\n }\n );\n case \"DISPATCH\":\n switch (message.payload.type) {\n case \"RESET\":\n setStateFromDevtools(initialState);\n if (store === void 0) {\n return connection == null ? void 0 : connection.init(api.getState());\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"COMMIT\":\n if (store === void 0) {\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"ROLLBACK\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n setStateFromDevtools(state[store]);\n connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n });\n case \"JUMP_TO_STATE\":\n case \"JUMP_TO_ACTION\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {\n setStateFromDevtools(state[store]);\n }\n });\n case \"IMPORT_STATE\": {\n const { nextLiftedState } = message.payload;\n const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;\n if (!lastComputedState) return;\n if (store === void 0) {\n setStateFromDevtools(lastComputedState);\n } else {\n setStateFromDevtools(lastComputedState[store]);\n }\n connection == null ? void 0 : connection.send(\n null,\n // FIXME no-any\n nextLiftedState\n );\n return;\n }\n case \"PAUSE_RECORDING\":\n return isRecording = !isRecording;\n }\n return;\n }\n });\n return initialState;\n};\nconst devtools = devtoolsImpl;\nconst parseJsonThen = (stringified, fn) => {\n let parsed;\n try {\n parsed = JSON.parse(stringified);\n } catch (e) {\n console.error(\n \"[zustand devtools middleware] Could not parse the received json\",\n e\n );\n }\n if (parsed !== void 0) fn(parsed);\n};\n\nconst subscribeWithSelectorImpl = (fn) => (set, get, api) => {\n const origSubscribe = api.subscribe;\n api.subscribe = ((selector, optListener, options) => {\n let listener = selector;\n if (optListener) {\n const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;\n let currentSlice = selector(api.getState());\n listener = (state) => {\n const nextSlice = selector(state);\n if (!equalityFn(currentSlice, nextSlice)) {\n const previousSlice = currentSlice;\n optListener(currentSlice = nextSlice, previousSlice);\n }\n };\n if (options == null ? void 0 : options.fireImmediately) {\n optListener(currentSlice, currentSlice);\n }\n }\n return origSubscribe(listener);\n });\n const initialState = fn(set, get, api);\n return initialState;\n};\nconst subscribeWithSelector = subscribeWithSelectorImpl;\n\nfunction combine(initialState, create) {\n return (...args) => Object.assign({}, initialState, create(...args));\n}\n\nfunction createJSONStorage(getStorage, options) {\n let storage;\n try {\n storage = getStorage();\n } catch (e) {\n return;\n }\n const persistStorage = {\n getItem: (name) => {\n var _a;\n const parse = (str2) => {\n if (str2 === null) {\n return null;\n }\n return JSON.parse(str2, options == null ? void 0 : options.reviver);\n };\n const str = (_a = storage.getItem(name)) != null ? _a : null;\n if (str instanceof Promise) {\n return str.then(parse);\n }\n return parse(str);\n },\n setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),\n removeItem: (name) => storage.removeItem(name)\n };\n return persistStorage;\n}\nconst toThenable = (fn) => (input) => {\n try {\n const result = fn(input);\n if (result instanceof Promise) {\n return result;\n }\n return {\n then(onFulfilled) {\n return toThenable(onFulfilled)(result);\n },\n catch(_onRejected) {\n return this;\n }\n };\n } catch (e) {\n return {\n then(_onFulfilled) {\n return this;\n },\n catch(onRejected) {\n return toThenable(onRejected)(e);\n }\n };\n }\n};\nconst persistImpl = (config, baseOptions) => (set, get, api) => {\n let options = {\n storage: createJSONStorage(() => window.localStorage),\n partialize: (state) => state,\n version: 0,\n merge: (persistedState, currentState) => ({\n ...currentState,\n ...persistedState\n }),\n ...baseOptions\n };\n let hasHydrated = false;\n let hydrationVersion = 0;\n const hydrationListeners = /* @__PURE__ */ new Set();\n const finishHydrationListeners = /* @__PURE__ */ new Set();\n let storage = options.storage;\n if (!storage) {\n return config(\n (...args) => {\n console.warn(\n `[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`\n );\n set(...args);\n },\n get,\n api\n );\n }\n const setItem = () => {\n const state = options.partialize({ ...get() });\n return storage.setItem(options.name, {\n state,\n version: options.version\n });\n };\n const savedSetState = api.setState;\n api.setState = (state, replace) => {\n savedSetState(state, replace);\n return setItem();\n };\n const configResult = config(\n (...args) => {\n set(...args);\n return setItem();\n },\n get,\n api\n );\n api.getInitialState = () => configResult;\n let stateFromStorage;\n const hydrate = () => {\n var _a, _b;\n if (!storage) return;\n const currentVersion = ++hydrationVersion;\n hasHydrated = false;\n hydrationListeners.forEach((cb) => {\n var _a2;\n return cb((_a2 = get()) != null ? _a2 : configResult);\n });\n const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;\n return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {\n if (deserializedStorageValue) {\n if (typeof deserializedStorageValue.version === \"number\" && deserializedStorageValue.version !== options.version) {\n if (options.migrate) {\n const migration = options.migrate(\n deserializedStorageValue.state,\n deserializedStorageValue.version\n );\n if (migration instanceof Promise) {\n return migration.then((result) => [true, result]);\n }\n return [true, migration];\n }\n console.error(\n `State loaded from storage couldn't be migrated since no migrate function was provided`\n );\n } else {\n return [false, deserializedStorageValue.state];\n }\n }\n return [false, void 0];\n }).then((migrationResult) => {\n var _a2;\n if (currentVersion !== hydrationVersion) {\n return;\n }\n const [migrated, migratedState] = migrationResult;\n stateFromStorage = options.merge(\n migratedState,\n (_a2 = get()) != null ? _a2 : configResult\n );\n set(stateFromStorage, true);\n if (migrated) {\n return setItem();\n }\n }).then(() => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(get(), void 0);\n stateFromStorage = get();\n hasHydrated = true;\n finishHydrationListeners.forEach((cb) => cb(stateFromStorage));\n }).catch((e) => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);\n });\n };\n api.persist = {\n setOptions: (newOptions) => {\n options = {\n ...options,\n ...newOptions\n };\n if (newOptions.storage) {\n storage = newOptions.storage;\n }\n },\n clearStorage: () => {\n storage == null ? void 0 : storage.removeItem(options.name);\n },\n getOptions: () => options,\n rehydrate: () => hydrate(),\n hasHydrated: () => hasHydrated,\n onHydrate: (cb) => {\n hydrationListeners.add(cb);\n return () => {\n hydrationListeners.delete(cb);\n };\n },\n onFinishHydration: (cb) => {\n finishHydrationListeners.add(cb);\n return () => {\n finishHydrationListeners.delete(cb);\n };\n }\n };\n if (!options.skipHydration) {\n hydrate();\n }\n return stateFromStorage || configResult;\n};\nconst persist = persistImpl;\n\nfunction ssrSafe(config, isSSR = typeof window === \"undefined\") {\n return (set, get, api) => {\n if (!isSSR) {\n return config(set, get, api);\n }\n const ssrSet = () => {\n throw new Error(\"Cannot set state of Zustand store in SSR\");\n };\n api.setState = ssrSet;\n return config(ssrSet, get, api);\n };\n}\n\nexport { combine, createJSONStorage, devtools, persist, redux, subscribeWithSelector, ssrSafe as unstable_ssrSafe };\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\nexport type ThemePreference = 'light' | 'dark' | 'system';\n\n/** Visual color scheme — orthogonal to light/dark mode. */\nexport type ColorScheme = 'default' | 'emerald';\n\nexport const COLOR_SCHEMES: { value: ColorScheme; labelEn: string; labelZh: string }[] = [\n { value: 'default', labelEn: 'Default', labelZh: '默认' },\n { value: 'emerald', labelEn: 'Light green', labelZh: '浅绿' },\n];\n\nconst DEFAULT_COLOR_SCHEME: ColorScheme = 'default';\n\nconst THEME_META_COLOR: Record<'light' | 'dark', Record<ColorScheme, string>> = {\n light: {\n default: '#f5f5f7',\n emerald: '#f0fdf4',\n },\n dark: {\n default: '#1c1c1e',\n emerald: '#000000',\n },\n};\n\nfunction syncThemeColorMeta(mode: 'light' | 'dark', scheme: ColorScheme) {\n const head = document.head;\n if (!head) return;\n const selector = 'meta[name=\"theme-color\"][data-xopc-theme-color=\"true\"]';\n let meta = head.querySelector<HTMLMetaElement>(selector);\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n meta.setAttribute('data-xopc-theme-color', 'true');\n head.appendChild(meta);\n }\n meta.setAttribute('content', THEME_META_COLOR[mode][scheme]);\n}\n\nfunction getSystemDark(): boolean {\n return globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;\n}\n\nfunction resolveTheme(pref: ThemePreference): 'light' | 'dark' {\n if (pref === 'system') {\n return getSystemDark() ? 'dark' : 'light';\n }\n return pref;\n}\n\nfunction prefersReducedMotion(): boolean {\n return globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;\n}\n\nfunction normalizeColorScheme(value: unknown): ColorScheme {\n return value === 'default' || value === 'emerald' ? value : DEFAULT_COLOR_SCHEME;\n}\n\n/** Apply light/dark + color scheme on `<html>`. Uses View Transitions when available for a softer cross-fade. */\nfunction applyDomTheme(mode: 'light' | 'dark', scheme: ColorScheme, useViewTransition: boolean) {\n const root = document.documentElement;\n const run = () => {\n root.classList.toggle('dark', mode === 'dark');\n root.dataset.theme = mode;\n root.dataset.colorScheme = scheme;\n syncThemeColorMeta(mode, scheme);\n };\n\n const doc = document as Document & {\n startViewTransition?: (cb: () => void) => { finished: Promise<void> };\n };\n\n if (\n useViewTransition &&\n !prefersReducedMotion() &&\n typeof doc.startViewTransition === 'function'\n ) {\n doc.startViewTransition(run);\n } else {\n run();\n }\n}\n\n/** Sync DOM from localStorage before React paint (zustand persist hydrates async). */\nexport function bootstrapTheme() {\n try {\n const raw = localStorage.getItem('xopc-web-theme');\n let pref: ThemePreference = 'system';\n let scheme: ColorScheme = DEFAULT_COLOR_SCHEME;\n if (raw) {\n const parsed = JSON.parse(raw) as {\n state?: { preference?: ThemePreference; colorScheme?: ColorScheme };\n };\n if (parsed.state?.preference) pref = parsed.state.preference;\n if (parsed.state && 'colorScheme' in parsed.state) {\n scheme = normalizeColorScheme(parsed.state.colorScheme);\n }\n }\n applyDomTheme(resolveTheme(pref), scheme, false);\n } catch {\n applyDomTheme(resolveTheme('system'), 'default', false);\n }\n}\n\ntype ThemeState = {\n preference: ThemePreference;\n colorScheme: ColorScheme;\n resolved: 'light' | 'dark';\n setPreference: (p: ThemePreference) => void;\n setColorScheme: (scheme: ColorScheme) => void;\n};\n\nexport const useThemeStore = create(\n persist<ThemeState>(\n (set, get) => ({\n preference: 'system',\n colorScheme: DEFAULT_COLOR_SCHEME,\n resolved: resolveTheme('system'),\n\n setPreference: (preference) => {\n const resolved = resolveTheme(preference);\n const { resolved: prevResolved, colorScheme } = get();\n applyDomTheme(resolved, colorScheme, resolved !== prevResolved);\n set({ preference, resolved });\n },\n\n setColorScheme: (scheme) => {\n const { resolved } = get();\n applyDomTheme(resolved, scheme, true);\n set({ colorScheme: scheme });\n },\n }),\n {\n name: 'xopc-web-theme',\n merge: (persisted, current) => {\n const p = (persisted ?? {}) as Partial<ThemeState>;\n return {\n ...current,\n ...p,\n colorScheme: normalizeColorScheme(p.colorScheme),\n };\n },\n },\n ),\n);\n\nexport function syncThemeAfterHydration() {\n const { preference, colorScheme } = useThemeStore.getState();\n const resolved = resolveTheme(preference);\n applyDomTheme(resolved, colorScheme, false);\n useThemeStore.setState({ resolved });\n}\n\nexport function subscribeSystemTheme() {\n const mq = globalThis.matchMedia?.('(prefers-color-scheme: dark)');\n if (!mq) return () => {};\n\n const handler = () => {\n const { preference, colorScheme } = useThemeStore.getState();\n if (preference !== 'system') return;\n const resolved = resolveTheme('system');\n const prevResolved = useThemeStore.getState().resolved;\n applyDomTheme(resolved, colorScheme, resolved !== prevResolved);\n useThemeStore.setState({ resolved });\n };\n\n mq.addEventListener('change', handler);\n return () => mq.removeEventListener('change', handler);\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}