@lobehub/lobehub 2.0.0-next.337 → 2.0.0-next.339

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 (270) hide show
  1. package/.gitattributes +35 -0
  2. package/CHANGELOG.md +69 -0
  3. package/changelog/v1.json +24 -0
  4. package/locales/ar/plugin.json +12 -2
  5. package/locales/ar/providers.json +1 -0
  6. package/locales/ar/setting.json +77 -1
  7. package/locales/bg-BG/models.json +5 -10
  8. package/locales/bg-BG/plugin.json +12 -2
  9. package/locales/bg-BG/providers.json +1 -0
  10. package/locales/bg-BG/setting.json +78 -2
  11. package/locales/de-DE/models.json +51 -9
  12. package/locales/de-DE/plugin.json +12 -2
  13. package/locales/de-DE/providers.json +1 -0
  14. package/locales/de-DE/setting.json +78 -2
  15. package/locales/en-US/models.json +11 -10
  16. package/locales/en-US/plugin.json +14 -4
  17. package/locales/en-US/providers.json +1 -0
  18. package/locales/en-US/setting.json +97 -2
  19. package/locales/es-ES/plugin.json +12 -2
  20. package/locales/es-ES/providers.json +1 -0
  21. package/locales/es-ES/setting.json +78 -2
  22. package/locales/fa-IR/plugin.json +12 -2
  23. package/locales/fa-IR/providers.json +1 -0
  24. package/locales/fa-IR/setting.json +78 -2
  25. package/locales/fr-FR/plugin.json +12 -2
  26. package/locales/fr-FR/providers.json +1 -0
  27. package/locales/fr-FR/setting.json +78 -2
  28. package/locales/it-IT/plugin.json +12 -2
  29. package/locales/it-IT/providers.json +1 -0
  30. package/locales/it-IT/setting.json +78 -2
  31. package/locales/ja-JP/plugin.json +12 -2
  32. package/locales/ja-JP/providers.json +1 -0
  33. package/locales/ja-JP/setting.json +78 -2
  34. package/locales/ko-KR/plugin.json +12 -2
  35. package/locales/ko-KR/providers.json +1 -0
  36. package/locales/ko-KR/setting.json +78 -2
  37. package/locales/nl-NL/models.json +4 -9
  38. package/locales/nl-NL/plugin.json +12 -2
  39. package/locales/nl-NL/providers.json +1 -0
  40. package/locales/nl-NL/setting.json +78 -2
  41. package/locales/pl-PL/plugin.json +12 -2
  42. package/locales/pl-PL/providers.json +1 -0
  43. package/locales/pl-PL/setting.json +78 -2
  44. package/locales/pt-BR/plugin.json +12 -2
  45. package/locales/pt-BR/providers.json +1 -0
  46. package/locales/pt-BR/setting.json +78 -2
  47. package/locales/ru-RU/plugin.json +12 -2
  48. package/locales/ru-RU/providers.json +1 -0
  49. package/locales/ru-RU/setting.json +78 -2
  50. package/locales/tr-TR/plugin.json +12 -2
  51. package/locales/tr-TR/providers.json +1 -0
  52. package/locales/tr-TR/setting.json +78 -2
  53. package/locales/vi-VN/plugin.json +12 -2
  54. package/locales/vi-VN/providers.json +1 -0
  55. package/locales/vi-VN/setting.json +77 -1
  56. package/locales/zh-CN/auth.json +1 -0
  57. package/locales/zh-CN/plugin.json +12 -2
  58. package/locales/zh-CN/providers.json +1 -0
  59. package/locales/zh-CN/setting.json +97 -2
  60. package/locales/zh-TW/plugin.json +12 -2
  61. package/locales/zh-TW/providers.json +1 -0
  62. package/locales/zh-TW/setting.json +78 -2
  63. package/package.json +1 -1
  64. package/packages/agent-runtime/src/groupOrchestration/GroupOrchestrationSupervisor.ts +2 -0
  65. package/packages/agent-runtime/src/groupOrchestration/__tests__/GroupOrchestrationSupervisor.test.ts +3 -1
  66. package/packages/agent-runtime/src/groupOrchestration/types.ts +5 -0
  67. package/packages/const/src/index.ts +1 -0
  68. package/packages/const/src/klavis.ts +144 -0
  69. package/packages/const/src/lobehubSkill.ts +34 -0
  70. package/packages/const/src/recommendedSkill.ts +17 -0
  71. package/packages/model-runtime/src/core/contextBuilders/anthropic.test.ts +38 -0
  72. package/packages/model-runtime/src/core/contextBuilders/anthropic.ts +20 -1
  73. package/packages/model-runtime/src/core/contextBuilders/google.test.ts +42 -0
  74. package/packages/model-runtime/src/core/contextBuilders/google.ts +17 -0
  75. package/packages/model-runtime/src/providers/google/index.ts +14 -14
  76. package/packages/model-runtime/src/providers/moonshot/index.ts +1 -1
  77. package/packages/model-runtime/src/providers/openai/index.ts +3 -3
  78. package/packages/types/src/discover/index.ts +1 -1
  79. package/scripts/electronWorkflow/modifiers/dynamicToStatic.mts +273 -0
  80. package/scripts/electronWorkflow/modifiers/index.mts +10 -0
  81. package/scripts/electronWorkflow/modifiers/nextConfig.mts +1 -0
  82. package/scripts/electronWorkflow/modifiers/nextDynamicToStatic.mts +233 -0
  83. package/scripts/electronWorkflow/modifiers/removeSuspense.mts +124 -0
  84. package/scripts/electronWorkflow/modifiers/routes.mts +14 -2
  85. package/scripts/electronWorkflow/modifiers/settingsContentToStatic.mts +148 -0
  86. package/scripts/electronWorkflow/modifiers/wrapChildrenWithClientOnly.mts +73 -0
  87. package/src/app/[variants]/(main)/agent/cron/[cronId]/CronConfig.ts +16 -16
  88. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobSaveButton.tsx +1 -1
  89. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobScheduleConfig.tsx +5 -2
  90. package/src/app/[variants]/(main)/community/features/Search.tsx +1 -1
  91. package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +131 -0
  92. package/src/app/[variants]/(main)/home/features/InputArea/index.tsx +34 -27
  93. package/src/app/[variants]/(main)/settings/features/SettingHeader.tsx +8 -4
  94. package/src/app/[variants]/(main)/settings/features/SettingsContent.tsx +3 -0
  95. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +6 -0
  96. package/src/{features/PluginStore/InstalledList/List/Item/Action.tsx → app/[variants]/(main)/settings/skill/features/Actions.tsx} +45 -40
  97. package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +353 -0
  98. package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +344 -0
  99. package/src/app/[variants]/(main)/settings/skill/features/McpSkillItem.tsx +116 -0
  100. package/src/app/[variants]/(main)/settings/skill/features/SkillList.tsx +244 -0
  101. package/src/app/[variants]/(main)/settings/skill/index.tsx +35 -0
  102. package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +27 -0
  103. package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +8 -17
  104. package/src/app/[variants]/(mobile)/settings/_layout/index.tsx +6 -1
  105. package/src/app/[variants]/(mobile)/settings/provider/_layout/index.tsx +22 -0
  106. package/src/components/Plugins/PluginTag.tsx +23 -35
  107. package/src/components/client/ClientOnly.tsx +6 -2
  108. package/src/features/AgentSetting/AgentPlugin/index.tsx +2 -2
  109. package/src/features/ChatInput/ActionBar/Tools/KlavisServerItem.tsx +8 -32
  110. package/src/features/ChatInput/ActionBar/Tools/LobehubSkillServerItem.tsx +8 -30
  111. package/src/features/ChatInput/ActionBar/Tools/PopoverContent.tsx +48 -59
  112. package/src/features/ChatInput/ActionBar/Tools/index.tsx +5 -23
  113. package/src/features/ChatInput/ActionBar/Tools/useControls.tsx +158 -56
  114. package/src/features/IntegrationDetailModal/index.tsx +293 -0
  115. package/src/features/{PluginStore/McpList/Detail → MCP/MCPDetail}/index.tsx +15 -6
  116. package/src/features/MCP/MCPSettings/McpSettingsModal.tsx +58 -0
  117. package/src/features/{PluginStore/McpList/Detail/Settings → MCP/MCPSettings}/index.tsx +39 -27
  118. package/src/features/PluginDetailModal/index.tsx +2 -2
  119. package/src/features/PluginDevModal/index.tsx +16 -40
  120. package/src/features/ProfileEditor/AgentTool.tsx +2 -2
  121. package/src/features/ProtocolUrlHandler/InstallPlugin/OfficialPluginInstallModal/index.tsx +1 -1
  122. package/src/features/{PluginStore/AddPluginButton.tsx → SkillStore/AddSkillButton.tsx} +3 -3
  123. package/src/features/SkillStore/CommunityList/Item.tsx +158 -0
  124. package/src/features/SkillStore/CommunityList/index.tsx +101 -0
  125. package/src/features/SkillStore/Content.tsx +59 -0
  126. package/src/features/{PluginStore/PluginEmpty.tsx → SkillStore/Empty.tsx} +8 -8
  127. package/src/features/SkillStore/LobeHubList/Item.tsx +118 -0
  128. package/src/features/SkillStore/LobeHubList/index.tsx +187 -0
  129. package/src/features/SkillStore/LobeHubList/useSkillConnect.ts +239 -0
  130. package/src/features/SkillStore/Search/index.tsx +43 -0
  131. package/src/features/{PluginStore → SkillStore}/index.tsx +14 -10
  132. package/src/features/SkillStore/style.ts +27 -0
  133. package/src/locales/default/plugin.ts +15 -4
  134. package/src/locales/default/setting.ts +204 -2
  135. package/src/services/chat/mecha/agentConfigResolver.test.ts +197 -0
  136. package/src/services/chat/mecha/agentConfigResolver.ts +44 -17
  137. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +40 -37
  138. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +78 -0
  139. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +50 -16
  140. package/src/store/global/initialState.ts +1 -0
  141. package/src/store/tool/slices/lobehubSkillStore/action.test.ts +914 -0
  142. package/src/store/tool/slices/lobehubSkillStore/selectors.test.ts +548 -0
  143. package/.cursor/skills/vercel-react-best-practices/AGENTS.md +0 -2410
  144. package/.cursor/skills/vercel-react-best-practices/SKILL.md +0 -125
  145. package/.cursor/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  146. package/.cursor/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -49
  147. package/.cursor/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  148. package/.cursor/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
  149. package/.cursor/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -36
  150. package/.cursor/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
  151. package/.cursor/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  152. package/.cursor/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
  153. package/.cursor/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  154. package/.cursor/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  155. package/.cursor/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  156. package/.cursor/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  157. package/.cursor/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  158. package/.cursor/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  159. package/.cursor/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  160. package/.cursor/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  161. package/.cursor/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -57
  162. package/.cursor/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  163. package/.cursor/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  164. package/.cursor/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  165. package/.cursor/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  166. package/.cursor/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  167. package/.cursor/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  168. package/.cursor/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  169. package/.cursor/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
  170. package/.cursor/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  171. package/.cursor/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  172. package/.cursor/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  173. package/.cursor/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  174. package/.cursor/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  175. package/.cursor/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  176. package/.cursor/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  177. package/.cursor/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  178. package/.cursor/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  179. package/.cursor/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  180. package/.cursor/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  181. package/.cursor/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  182. package/.cursor/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  183. package/.cursor/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  184. package/.cursor/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  185. package/.cursor/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  186. package/.cursor/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  187. package/.cursor/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  188. package/.cursor/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  189. package/.cursor/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  190. package/.cursor/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  191. package/.cursor/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
  192. package/src/features/PluginStore/Content.tsx +0 -54
  193. package/src/features/PluginStore/InstalledList/Detail/CustomPluginEmptyState.tsx +0 -79
  194. package/src/features/PluginStore/InstalledList/Detail/index.tsx +0 -21
  195. package/src/features/PluginStore/InstalledList/List/Item/index.tsx +0 -61
  196. package/src/features/PluginStore/InstalledList/List/index.tsx +0 -72
  197. package/src/features/PluginStore/InstalledList/index.tsx +0 -90
  198. package/src/features/PluginStore/McpList/List/Action.tsx +0 -119
  199. package/src/features/PluginStore/McpList/List/Item.tsx +0 -83
  200. package/src/features/PluginStore/McpList/List/index.tsx +0 -93
  201. package/src/features/PluginStore/McpList/index.tsx +0 -58
  202. package/src/features/PluginStore/PluginList/Detail/DetailProvider.tsx +0 -19
  203. package/src/features/PluginStore/PluginList/Detail/EmptyState.tsx +0 -56
  204. package/src/features/PluginStore/PluginList/Detail/Header.tsx +0 -130
  205. package/src/features/PluginStore/PluginList/Detail/InstallDetail/Nav.tsx +0 -73
  206. package/src/features/PluginStore/PluginList/Detail/InstallDetail/Settings.tsx +0 -19
  207. package/src/features/PluginStore/PluginList/Detail/InstallDetail/Tools.tsx +0 -111
  208. package/src/features/PluginStore/PluginList/Detail/InstallDetail/index.tsx +0 -24
  209. package/src/features/PluginStore/PluginList/Detail/Loading.tsx +0 -42
  210. package/src/features/PluginStore/PluginList/Detail/TagList.tsx +0 -35
  211. package/src/features/PluginStore/PluginList/Detail/index.tsx +0 -39
  212. package/src/features/PluginStore/PluginList/Detail/useCategory.tsx +0 -76
  213. package/src/features/PluginStore/PluginList/List/Action.tsx +0 -78
  214. package/src/features/PluginStore/PluginList/List/Item.tsx +0 -92
  215. package/src/features/PluginStore/PluginList/List/index.tsx +0 -94
  216. package/src/features/PluginStore/PluginList/index.tsx +0 -46
  217. package/src/features/PluginStore/Search/index.tsx +0 -40
  218. /package/{.codex/skills → .agents}/vercel-react-best-practices/AGENTS.md +0 -0
  219. /package/{.codex/skills → .agents}/vercel-react-best-practices/SKILL.md +0 -0
  220. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -0
  221. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/advanced-use-latest.md +0 -0
  222. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-api-routes.md +0 -0
  223. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-defer-await.md +0 -0
  224. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-dependencies.md +0 -0
  225. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-parallel.md +0 -0
  226. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -0
  227. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -0
  228. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-conditional.md +0 -0
  229. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -0
  230. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -0
  231. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-preload.md +0 -0
  232. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/client-event-listeners.md +0 -0
  233. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -0
  234. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -0
  235. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/client-swr-dedup.md +0 -0
  236. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -0
  237. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-cache-function-results.md +0 -0
  238. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-cache-property-access.md +0 -0
  239. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-cache-storage.md +0 -0
  240. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-combine-iterations.md +0 -0
  241. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-early-exit.md +0 -0
  242. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -0
  243. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-index-maps.md +0 -0
  244. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-length-check-first.md +0 -0
  245. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-min-max-loop.md +0 -0
  246. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -0
  247. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -0
  248. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-activity.md +0 -0
  249. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -0
  250. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -0
  251. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -0
  252. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -0
  253. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -0
  254. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -0
  255. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -0
  256. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-dependencies.md +0 -0
  257. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-derived-state.md +0 -0
  258. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -0
  259. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -0
  260. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-memo.md +0 -0
  261. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-transitions.md +0 -0
  262. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -0
  263. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-cache-lru.md +0 -0
  264. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-cache-react.md +0 -0
  265. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -0
  266. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-serialization.md +0 -0
  267. /package/src/{features/PluginStore/InstalledList → app/[variants]/(main)/settings/skill/features}/EditCustomPlugin.tsx +0 -0
  268. /package/src/features/{PluginStore/McpList/Detail → MCP/MCPDetail}/Loading.tsx +0 -0
  269. /package/src/features/{PluginStore → SkillStore}/Loading.tsx +0 -0
  270. /package/src/features/{PluginStore → SkillStore}/VirtuosoLoading.tsx +0 -0
@@ -0,0 +1,548 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { initialState } from '../../initialState';
4
+ import { type ToolStore } from '../../store';
5
+ import { lobehubSkillStoreSelectors } from './selectors';
6
+ import { type LobehubSkillServer, LobehubSkillStatus } from './types';
7
+
8
+ describe('lobehubSkillStoreSelectors', () => {
9
+ describe('getServers', () => {
10
+ it('should return empty array when no servers exist', () => {
11
+ const state = { ...initialState } as ToolStore;
12
+ const result = lobehubSkillStoreSelectors.getServers(state);
13
+ expect(result).toEqual([]);
14
+ });
15
+
16
+ it('should return all servers', () => {
17
+ const servers: LobehubSkillServer[] = [
18
+ {
19
+ identifier: 'linear',
20
+ name: 'Linear',
21
+ isConnected: true,
22
+ status: LobehubSkillStatus.CONNECTED,
23
+ },
24
+ {
25
+ identifier: 'github',
26
+ name: 'GitHub',
27
+ isConnected: false,
28
+ status: LobehubSkillStatus.NOT_CONNECTED,
29
+ },
30
+ ];
31
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
32
+ const result = lobehubSkillStoreSelectors.getServers(state);
33
+ expect(result).toEqual(servers);
34
+ });
35
+
36
+ it('should handle undefined lobehubSkillServers', () => {
37
+ const state = { ...initialState, lobehubSkillServers: undefined } as unknown as ToolStore;
38
+ const result = lobehubSkillStoreSelectors.getServers(state);
39
+ expect(result).toEqual([]);
40
+ });
41
+ });
42
+
43
+ describe('getConnectedServers', () => {
44
+ it('should return only connected servers', () => {
45
+ const servers: LobehubSkillServer[] = [
46
+ {
47
+ identifier: 'linear',
48
+ name: 'Linear',
49
+ isConnected: true,
50
+ status: LobehubSkillStatus.CONNECTED,
51
+ },
52
+ {
53
+ identifier: 'github',
54
+ name: 'GitHub',
55
+ isConnected: false,
56
+ status: LobehubSkillStatus.NOT_CONNECTED,
57
+ },
58
+ {
59
+ identifier: 'slack',
60
+ name: 'Slack',
61
+ isConnected: false,
62
+ status: LobehubSkillStatus.ERROR,
63
+ },
64
+ ];
65
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
66
+ const result = lobehubSkillStoreSelectors.getConnectedServers(state);
67
+ expect(result).toHaveLength(1);
68
+ expect(result[0].name).toBe('Linear');
69
+ });
70
+
71
+ it('should return empty array when no servers are connected', () => {
72
+ const servers: LobehubSkillServer[] = [
73
+ {
74
+ identifier: 'github',
75
+ name: 'GitHub',
76
+ isConnected: false,
77
+ status: LobehubSkillStatus.NOT_CONNECTED,
78
+ },
79
+ ];
80
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
81
+ const result = lobehubSkillStoreSelectors.getConnectedServers(state);
82
+ expect(result).toEqual([]);
83
+ });
84
+
85
+ it('should return empty array when no servers exist', () => {
86
+ const state = { ...initialState } as ToolStore;
87
+ const result = lobehubSkillStoreSelectors.getConnectedServers(state);
88
+ expect(result).toEqual([]);
89
+ });
90
+ });
91
+
92
+ describe('getAllServerIdentifiers', () => {
93
+ it('should return set of all server identifiers', () => {
94
+ const servers: LobehubSkillServer[] = [
95
+ {
96
+ identifier: 'linear',
97
+ name: 'Linear',
98
+ isConnected: true,
99
+ status: LobehubSkillStatus.CONNECTED,
100
+ },
101
+ {
102
+ identifier: 'github',
103
+ name: 'GitHub',
104
+ isConnected: false,
105
+ status: LobehubSkillStatus.NOT_CONNECTED,
106
+ },
107
+ ];
108
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
109
+ const result = lobehubSkillStoreSelectors.getAllServerIdentifiers(state);
110
+ expect(result).toEqual(new Set(['linear', 'github']));
111
+ });
112
+
113
+ it('should return empty set when no servers exist', () => {
114
+ const state = { ...initialState } as ToolStore;
115
+ const result = lobehubSkillStoreSelectors.getAllServerIdentifiers(state);
116
+ expect(result).toEqual(new Set());
117
+ });
118
+ });
119
+
120
+ describe('getServerByIdentifier', () => {
121
+ it('should return server by identifier', () => {
122
+ const servers: LobehubSkillServer[] = [
123
+ {
124
+ identifier: 'linear',
125
+ name: 'Linear',
126
+ isConnected: true,
127
+ status: LobehubSkillStatus.CONNECTED,
128
+ },
129
+ ];
130
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
131
+ const result = lobehubSkillStoreSelectors.getServerByIdentifier('linear')(state);
132
+ expect(result?.identifier).toBe('linear');
133
+ expect(result?.name).toBe('Linear');
134
+ });
135
+
136
+ it('should return undefined when server not found', () => {
137
+ const state = { ...initialState } as ToolStore;
138
+ const result = lobehubSkillStoreSelectors.getServerByIdentifier('non-existent')(state);
139
+ expect(result).toBeUndefined();
140
+ });
141
+
142
+ it('should return undefined when lobehubSkillServers is undefined', () => {
143
+ const state = { ...initialState, lobehubSkillServers: undefined } as unknown as ToolStore;
144
+ const result = lobehubSkillStoreSelectors.getServerByIdentifier('linear')(state);
145
+ expect(result).toBeUndefined();
146
+ });
147
+ });
148
+
149
+ describe('isLobehubSkillServer', () => {
150
+ it('should return true for existing server', () => {
151
+ const servers: LobehubSkillServer[] = [
152
+ {
153
+ identifier: 'linear',
154
+ name: 'Linear',
155
+ isConnected: true,
156
+ status: LobehubSkillStatus.CONNECTED,
157
+ },
158
+ ];
159
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
160
+ const result = lobehubSkillStoreSelectors.isLobehubSkillServer('linear')(state);
161
+ expect(result).toBe(true);
162
+ });
163
+
164
+ it('should return false for non-existing server', () => {
165
+ const state = { ...initialState } as ToolStore;
166
+ const result = lobehubSkillStoreSelectors.isLobehubSkillServer('non-existent')(state);
167
+ expect(result).toBe(false);
168
+ });
169
+
170
+ it('should return false when lobehubSkillServers is undefined', () => {
171
+ const state = { ...initialState, lobehubSkillServers: undefined } as unknown as ToolStore;
172
+ const result = lobehubSkillStoreSelectors.isLobehubSkillServer('linear')(state);
173
+ expect(result).toBe(false);
174
+ });
175
+ });
176
+
177
+ describe('isServerLoading', () => {
178
+ it('should return true when server is loading', () => {
179
+ const state = {
180
+ ...initialState,
181
+ lobehubSkillLoadingIds: new Set(['linear']),
182
+ } as ToolStore;
183
+ const result = lobehubSkillStoreSelectors.isServerLoading('linear')(state);
184
+ expect(result).toBe(true);
185
+ });
186
+
187
+ it('should return false when server is not loading', () => {
188
+ const state = {
189
+ ...initialState,
190
+ lobehubSkillLoadingIds: new Set(),
191
+ } as ToolStore;
192
+ const result = lobehubSkillStoreSelectors.isServerLoading('linear')(state);
193
+ expect(result).toBe(false);
194
+ });
195
+
196
+ it('should return false when lobehubSkillLoadingIds is undefined', () => {
197
+ const state = {
198
+ ...initialState,
199
+ lobehubSkillLoadingIds: undefined,
200
+ } as unknown as ToolStore;
201
+ const result = lobehubSkillStoreSelectors.isServerLoading('linear')(state);
202
+ expect(result).toBe(false);
203
+ });
204
+ });
205
+
206
+ describe('isToolExecuting', () => {
207
+ it('should return true when tool is executing', () => {
208
+ const state = {
209
+ ...initialState,
210
+ lobehubSkillExecutingToolIds: new Set(['linear:createIssue']),
211
+ } as ToolStore;
212
+ const result = lobehubSkillStoreSelectors.isToolExecuting('linear', 'createIssue')(state);
213
+ expect(result).toBe(true);
214
+ });
215
+
216
+ it('should return false when tool is not executing', () => {
217
+ const state = {
218
+ ...initialState,
219
+ lobehubSkillExecutingToolIds: new Set(),
220
+ } as ToolStore;
221
+ const result = lobehubSkillStoreSelectors.isToolExecuting('linear', 'createIssue')(state);
222
+ expect(result).toBe(false);
223
+ });
224
+
225
+ it('should return false for different tool', () => {
226
+ const state = {
227
+ ...initialState,
228
+ lobehubSkillExecutingToolIds: new Set(['linear:createIssue']),
229
+ } as ToolStore;
230
+ const result = lobehubSkillStoreSelectors.isToolExecuting('linear', 'listIssues')(state);
231
+ expect(result).toBe(false);
232
+ });
233
+
234
+ it('should return false when lobehubSkillExecutingToolIds is undefined', () => {
235
+ const state = {
236
+ ...initialState,
237
+ lobehubSkillExecutingToolIds: undefined,
238
+ } as unknown as ToolStore;
239
+ const result = lobehubSkillStoreSelectors.isToolExecuting('linear', 'createIssue')(state);
240
+ expect(result).toBe(false);
241
+ });
242
+ });
243
+
244
+ describe('getAllTools', () => {
245
+ it('should return all tools from connected servers', () => {
246
+ const servers: LobehubSkillServer[] = [
247
+ {
248
+ identifier: 'linear',
249
+ name: 'Linear',
250
+ isConnected: true,
251
+ status: LobehubSkillStatus.CONNECTED,
252
+ tools: [
253
+ { name: 'createIssue', description: 'Create issue', inputSchema: { type: 'object' } },
254
+ { name: 'listIssues', description: 'List issues', inputSchema: { type: 'object' } },
255
+ ],
256
+ },
257
+ {
258
+ identifier: 'github',
259
+ name: 'GitHub',
260
+ isConnected: false,
261
+ status: LobehubSkillStatus.NOT_CONNECTED,
262
+ tools: [{ name: 'createPR', description: 'Create PR', inputSchema: { type: 'object' } }],
263
+ },
264
+ ];
265
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
266
+ const result = lobehubSkillStoreSelectors.getAllTools(state);
267
+
268
+ // Only tools from connected server (Linear) should be returned
269
+ expect(result).toHaveLength(2);
270
+ expect(result[0].name).toBe('createIssue');
271
+ expect(result[0].provider).toBe('linear');
272
+ expect(result[1].name).toBe('listIssues');
273
+ expect(result[1].provider).toBe('linear');
274
+ });
275
+
276
+ it('should return empty array when no connected servers have tools', () => {
277
+ const servers: LobehubSkillServer[] = [
278
+ {
279
+ identifier: 'linear',
280
+ name: 'Linear',
281
+ isConnected: true,
282
+ status: LobehubSkillStatus.CONNECTED,
283
+ },
284
+ ];
285
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
286
+ const result = lobehubSkillStoreSelectors.getAllTools(state);
287
+ expect(result).toEqual([]);
288
+ });
289
+
290
+ it('should return empty array when no servers exist', () => {
291
+ const state = { ...initialState } as ToolStore;
292
+ const result = lobehubSkillStoreSelectors.getAllTools(state);
293
+ expect(result).toEqual([]);
294
+ });
295
+
296
+ it('should combine tools from multiple connected servers', () => {
297
+ const servers: LobehubSkillServer[] = [
298
+ {
299
+ identifier: 'linear',
300
+ name: 'Linear',
301
+ isConnected: true,
302
+ status: LobehubSkillStatus.CONNECTED,
303
+ tools: [
304
+ { name: 'createIssue', description: 'Create issue', inputSchema: { type: 'object' } },
305
+ ],
306
+ },
307
+ {
308
+ identifier: 'github',
309
+ name: 'GitHub',
310
+ isConnected: true,
311
+ status: LobehubSkillStatus.CONNECTED,
312
+ tools: [{ name: 'createPR', description: 'Create PR', inputSchema: { type: 'object' } }],
313
+ },
314
+ ];
315
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
316
+ const result = lobehubSkillStoreSelectors.getAllTools(state);
317
+
318
+ expect(result).toHaveLength(2);
319
+ expect(result[0].provider).toBe('linear');
320
+ expect(result[1].provider).toBe('github');
321
+ });
322
+ });
323
+
324
+ describe('lobehubSkillAsLobeTools', () => {
325
+ it('should convert connected servers with tools to LobeTool format', () => {
326
+ const servers: LobehubSkillServer[] = [
327
+ {
328
+ identifier: 'linear',
329
+ name: 'Linear',
330
+ icon: 'linear-icon',
331
+ isConnected: true,
332
+ status: LobehubSkillStatus.CONNECTED,
333
+ tools: [
334
+ { name: 'createIssue', description: 'Create issue', inputSchema: { type: 'object' } },
335
+ ],
336
+ },
337
+ ];
338
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
339
+ const result = lobehubSkillStoreSelectors.lobehubSkillAsLobeTools(state);
340
+
341
+ expect(result).toHaveLength(1);
342
+ expect(result[0].identifier).toBe('linear');
343
+ expect(result[0].type).toBe('plugin');
344
+ expect(result[0].manifest.api).toHaveLength(1);
345
+ expect(result[0].manifest.api[0].name).toBe('createIssue');
346
+ expect(result[0].manifest.meta.title).toBe('Linear');
347
+ expect(result[0].manifest.meta.avatar).toBe('linear-icon');
348
+ });
349
+
350
+ it('should not include disconnected servers', () => {
351
+ const servers: LobehubSkillServer[] = [
352
+ {
353
+ identifier: 'linear',
354
+ name: 'Linear',
355
+ isConnected: false,
356
+ status: LobehubSkillStatus.NOT_CONNECTED,
357
+ tools: [
358
+ { name: 'createIssue', description: 'Create issue', inputSchema: { type: 'object' } },
359
+ ],
360
+ },
361
+ ];
362
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
363
+ const result = lobehubSkillStoreSelectors.lobehubSkillAsLobeTools(state);
364
+ expect(result).toEqual([]);
365
+ });
366
+
367
+ it('should not include servers without tools', () => {
368
+ const servers: LobehubSkillServer[] = [
369
+ {
370
+ identifier: 'linear',
371
+ name: 'Linear',
372
+ isConnected: true,
373
+ status: LobehubSkillStatus.CONNECTED,
374
+ },
375
+ ];
376
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
377
+ const result = lobehubSkillStoreSelectors.lobehubSkillAsLobeTools(state);
378
+ expect(result).toEqual([]);
379
+ });
380
+
381
+ it('should not include servers with empty tools array', () => {
382
+ const servers: LobehubSkillServer[] = [
383
+ {
384
+ identifier: 'linear',
385
+ name: 'Linear',
386
+ isConnected: true,
387
+ status: LobehubSkillStatus.CONNECTED,
388
+ tools: [],
389
+ },
390
+ ];
391
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
392
+ const result = lobehubSkillStoreSelectors.lobehubSkillAsLobeTools(state);
393
+ expect(result).toEqual([]);
394
+ });
395
+
396
+ it('should use default avatar when icon is not provided', () => {
397
+ const servers: LobehubSkillServer[] = [
398
+ {
399
+ identifier: 'linear',
400
+ name: 'Linear',
401
+ isConnected: true,
402
+ status: LobehubSkillStatus.CONNECTED,
403
+ tools: [
404
+ { name: 'createIssue', description: 'Create issue', inputSchema: { type: 'object' } },
405
+ ],
406
+ },
407
+ ];
408
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
409
+ const result = lobehubSkillStoreSelectors.lobehubSkillAsLobeTools(state);
410
+
411
+ expect(result[0].manifest.meta.avatar).toBe('🔗');
412
+ });
413
+
414
+ it('should include all apis from server', () => {
415
+ const servers: LobehubSkillServer[] = [
416
+ {
417
+ identifier: 'linear',
418
+ name: 'Linear',
419
+ isConnected: true,
420
+ status: LobehubSkillStatus.CONNECTED,
421
+ tools: [
422
+ { name: 'createIssue', description: 'Create issue', inputSchema: { type: 'object' } },
423
+ { name: 'listIssues', description: 'List issues', inputSchema: { type: 'object' } },
424
+ { name: 'updateIssue', description: 'Update issue', inputSchema: { type: 'object' } },
425
+ ],
426
+ },
427
+ ];
428
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
429
+ const result = lobehubSkillStoreSelectors.lobehubSkillAsLobeTools(state);
430
+
431
+ expect(result[0].manifest.api).toHaveLength(3);
432
+ expect(result[0].manifest.api[0].name).toBe('createIssue');
433
+ expect(result[0].manifest.api[1].name).toBe('listIssues');
434
+ expect(result[0].manifest.api[2].name).toBe('updateIssue');
435
+ });
436
+
437
+ it('should handle undefined description in tools', () => {
438
+ const servers: LobehubSkillServer[] = [
439
+ {
440
+ identifier: 'linear',
441
+ name: 'Linear',
442
+ isConnected: true,
443
+ status: LobehubSkillStatus.CONNECTED,
444
+ tools: [{ name: 'createIssue', inputSchema: { type: 'object' } }],
445
+ },
446
+ ];
447
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
448
+ const result = lobehubSkillStoreSelectors.lobehubSkillAsLobeTools(state);
449
+
450
+ expect(result[0].manifest.api[0].description).toBe('');
451
+ });
452
+ });
453
+
454
+ describe('metaList', () => {
455
+ it('should return metadata for connected servers', () => {
456
+ const servers: LobehubSkillServer[] = [
457
+ {
458
+ identifier: 'linear',
459
+ name: 'Linear',
460
+ icon: 'linear-icon',
461
+ isConnected: true,
462
+ status: LobehubSkillStatus.CONNECTED,
463
+ },
464
+ {
465
+ identifier: 'github',
466
+ name: 'GitHub',
467
+ icon: 'github-icon',
468
+ isConnected: false,
469
+ status: LobehubSkillStatus.NOT_CONNECTED,
470
+ },
471
+ ];
472
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
473
+ const result = lobehubSkillStoreSelectors.metaList(state);
474
+
475
+ expect(result).toHaveLength(1);
476
+ expect(result[0].identifier).toBe('linear');
477
+ expect(result[0].meta.title).toBe('Linear');
478
+ expect(result[0].meta.avatar).toBe('linear-icon');
479
+ expect(result[0].meta.description).toBe('LobeHub Skill: Linear');
480
+ });
481
+
482
+ it('should return empty array when no connected servers', () => {
483
+ const servers: LobehubSkillServer[] = [
484
+ {
485
+ identifier: 'linear',
486
+ name: 'Linear',
487
+ isConnected: false,
488
+ status: LobehubSkillStatus.NOT_CONNECTED,
489
+ },
490
+ ];
491
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
492
+ const result = lobehubSkillStoreSelectors.metaList(state);
493
+ expect(result).toEqual([]);
494
+ });
495
+
496
+ it('should return empty array when no servers exist', () => {
497
+ const state = { ...initialState } as ToolStore;
498
+ const result = lobehubSkillStoreSelectors.metaList(state);
499
+ expect(result).toEqual([]);
500
+ });
501
+
502
+ it('should use default avatar when icon is not provided', () => {
503
+ const servers: LobehubSkillServer[] = [
504
+ {
505
+ identifier: 'linear',
506
+ name: 'Linear',
507
+ isConnected: true,
508
+ status: LobehubSkillStatus.CONNECTED,
509
+ },
510
+ ];
511
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
512
+ const result = lobehubSkillStoreSelectors.metaList(state);
513
+
514
+ expect(result[0].meta.avatar).toBe('🔗');
515
+ });
516
+
517
+ it('should return metadata for multiple connected servers', () => {
518
+ const servers: LobehubSkillServer[] = [
519
+ {
520
+ identifier: 'linear',
521
+ name: 'Linear',
522
+ icon: 'linear-icon',
523
+ isConnected: true,
524
+ status: LobehubSkillStatus.CONNECTED,
525
+ },
526
+ {
527
+ identifier: 'github',
528
+ name: 'GitHub',
529
+ icon: 'github-icon',
530
+ isConnected: true,
531
+ status: LobehubSkillStatus.CONNECTED,
532
+ },
533
+ {
534
+ identifier: 'slack',
535
+ name: 'Slack',
536
+ icon: 'slack-icon',
537
+ isConnected: true,
538
+ status: LobehubSkillStatus.CONNECTED,
539
+ },
540
+ ];
541
+ const state = { ...initialState, lobehubSkillServers: servers } as ToolStore;
542
+ const result = lobehubSkillStoreSelectors.metaList(state);
543
+
544
+ expect(result).toHaveLength(3);
545
+ expect(result.map((r) => r.identifier)).toEqual(['linear', 'github', 'slack']);
546
+ });
547
+ });
548
+ });