@geminilight/mindos 0.6.40 → 0.6.42

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 (422) hide show
  1. package/_standalone/.mindos-build-version +1 -1
  2. package/_standalone/.next/BUILD_ID +1 -1
  3. package/_standalone/.next/app-path-routes-manifest.json +17 -16
  4. package/_standalone/.next/build-manifest.json +3 -3
  5. package/_standalone/.next/cache/.previewinfo +1 -1
  6. package/_standalone/.next/cache/.rscinfo +1 -1
  7. package/_standalone/.next/cache/config.json +3 -3
  8. package/_standalone/.next/prerender-manifest.json +3 -3
  9. package/_standalone/.next/react-loadable-manifest.json +5 -1
  10. package/_standalone/.next/routes-manifest.json +6 -0
  11. package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
  12. package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  13. package/_standalone/.next/server/app/_global-error.html +2 -2
  14. package/_standalone/.next/server/app/_global-error.rsc +1 -1
  15. package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  16. package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  17. package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  18. package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  19. package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  20. package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  21. package/_standalone/.next/server/app/_not-found/page.js +1 -1
  22. package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  23. package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  24. package/_standalone/.next/server/app/agents/[agentKey]/page.js +1 -1
  25. package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
  26. package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
  27. package/_standalone/.next/server/app/agents/page.js +2 -2
  28. package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
  29. package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  30. package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
  31. package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
  32. package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
  33. package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
  34. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  35. package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
  37. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  38. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  39. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  40. package/_standalone/.next/server/app/api/ask/route.js +1 -1
  41. package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
  42. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  43. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  44. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  45. package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
  46. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  47. package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
  48. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  49. package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
  50. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  51. package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
  52. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  54. package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
  55. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  56. package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
  57. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  59. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  60. package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  61. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  62. package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
  63. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  65. package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -1
  66. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
  68. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  69. package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
  70. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/mcp/install/route.js +1 -1
  72. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  73. package/_standalone/.next/server/app/api/mcp/install-skill/route.js.nft.json +1 -1
  74. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  75. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  76. package/_standalone/.next/server/app/api/mcp/status/route.js +1 -1
  77. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  78. package/_standalone/.next/server/app/api/mcp/uninstall/route.js +1 -0
  79. package/_standalone/.next/server/app/api/mcp/uninstall/route.js.nft.json +1 -0
  80. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -0
  81. package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
  82. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  83. package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
  84. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  86. package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  87. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  88. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  89. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  90. package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  91. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  92. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  93. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  94. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  95. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  96. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  97. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  98. package/_standalone/.next/server/app/api/skills/route.js +4 -4
  99. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  100. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  101. package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
  102. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  103. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  104. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  105. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  106. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  107. package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
  108. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  109. package/_standalone/.next/server/app/changes/page.js +1 -1
  110. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  111. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  112. package/_standalone/.next/server/app/echo/[segment]/page.js +1 -1
  113. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  114. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  115. package/_standalone/.next/server/app/echo/page.js +1 -1
  116. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  117. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  118. package/_standalone/.next/server/app/explore/page.js +1 -1
  119. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  120. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  121. package/_standalone/.next/server/app/help/page.js +2 -2
  122. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  123. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  124. package/_standalone/.next/server/app/login/page.js +1 -1
  125. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  126. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  127. package/_standalone/.next/server/app/page.js +2 -2
  128. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  129. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  130. package/_standalone/.next/server/app/setup/page.js +2 -2
  131. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  132. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  133. package/_standalone/.next/server/app/trash/page.js +3 -3
  134. package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
  135. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  136. package/_standalone/.next/server/app/view/[...path]/page.js +3 -3
  137. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  138. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  139. package/_standalone/.next/server/app-paths-manifest.json +17 -16
  140. package/_standalone/.next/server/chunks/1550.js +1 -1
  141. package/_standalone/.next/server/chunks/2190.js +11 -0
  142. package/_standalone/.next/server/chunks/{6365.js → 3262.js} +2 -2
  143. package/_standalone/.next/server/chunks/5648.js +2 -0
  144. package/_standalone/.next/server/chunks/6539.js +1 -1
  145. package/_standalone/.next/server/chunks/8388.js +1 -1
  146. package/_standalone/.next/server/chunks/953.js +1 -1
  147. package/_standalone/.next/server/chunks/9539.js +219 -0
  148. package/_standalone/.next/server/middleware-build-manifest.js +1 -1
  149. package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  150. package/_standalone/.next/server/next-font-manifest.js +1 -1
  151. package/_standalone/.next/server/next-font-manifest.json +1 -1
  152. package/_standalone/.next/server/pages/500.html +2 -2
  153. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  154. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  155. package/_standalone/.next/static/GB-YReQ58tsvCuwlzrkMZ/_buildManifest.js +1 -0
  156. package/_standalone/.next/static/chunks/1053-67f0ce444d1227e2.js +29 -0
  157. package/_standalone/.next/static/chunks/{8663-de911d2d395622be.js → 1880-c2a9e76201841c86.js} +1 -1
  158. package/_standalone/.next/static/chunks/3637.0541ac2d0ea7de1f.js +1 -0
  159. package/_standalone/.next/static/chunks/4563-b2a2ce80aff845af.js +6 -0
  160. package/_standalone/.next/static/chunks/6981-3d7dcac2d12a5670.js +1 -0
  161. package/_standalone/.next/static/chunks/7144-5febf62f1a79fe64.js +1 -0
  162. package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/route-84943536516b00b2.js +1 -0
  163. package/_standalone/.next/static/chunks/app/_global-error/page-84943536516b00b2.js +1 -0
  164. package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-773071a99c4daac2.js +1 -0
  165. package/_standalone/.next/static/chunks/app/agents/page-eac6c5f6650dbf62.js +5 -0
  166. package/_standalone/.next/static/chunks/app/api/a2a/agents/route-84943536516b00b2.js +1 -0
  167. package/_standalone/.next/static/chunks/app/api/a2a/delegations/route-84943536516b00b2.js +1 -0
  168. package/_standalone/.next/static/chunks/app/api/a2a/discover/route-84943536516b00b2.js +1 -0
  169. package/_standalone/.next/static/chunks/app/api/a2a/route-84943536516b00b2.js +1 -0
  170. package/_standalone/.next/static/chunks/app/api/acp/config/route-84943536516b00b2.js +1 -0
  171. package/_standalone/.next/static/chunks/app/api/acp/detect/route-84943536516b00b2.js +1 -0
  172. package/_standalone/.next/static/chunks/app/api/acp/install/route-84943536516b00b2.js +1 -0
  173. package/_standalone/.next/static/chunks/app/api/acp/registry/route-84943536516b00b2.js +1 -0
  174. package/_standalone/.next/static/chunks/app/api/acp/session/route-84943536516b00b2.js +1 -0
  175. package/_standalone/.next/static/chunks/app/api/agent-activity/route-84943536516b00b2.js +1 -0
  176. package/_standalone/.next/static/chunks/app/api/ask/route-84943536516b00b2.js +1 -0
  177. package/_standalone/.next/static/chunks/app/api/ask-sessions/route-84943536516b00b2.js +1 -0
  178. package/_standalone/.next/static/chunks/app/api/auth/route-84943536516b00b2.js +1 -0
  179. package/_standalone/.next/static/chunks/app/api/backlinks/route-84943536516b00b2.js +1 -0
  180. package/_standalone/.next/static/chunks/app/api/bootstrap/route-84943536516b00b2.js +1 -0
  181. package/_standalone/.next/static/chunks/app/api/changes/route-84943536516b00b2.js +1 -0
  182. package/_standalone/.next/static/chunks/app/api/export/route-84943536516b00b2.js +1 -0
  183. package/_standalone/.next/static/chunks/app/api/extract-pdf/route-84943536516b00b2.js +1 -0
  184. package/_standalone/.next/static/chunks/app/api/file/import/route-84943536516b00b2.js +1 -0
  185. package/_standalone/.next/static/chunks/app/api/file/route-84943536516b00b2.js +1 -0
  186. package/_standalone/.next/static/chunks/app/api/files/route-84943536516b00b2.js +1 -0
  187. package/_standalone/.next/static/chunks/app/api/git/route-84943536516b00b2.js +1 -0
  188. package/_standalone/.next/static/chunks/app/api/graph/route-84943536516b00b2.js +1 -0
  189. package/_standalone/.next/static/chunks/app/api/health/route-84943536516b00b2.js +1 -0
  190. package/_standalone/.next/static/chunks/app/api/inbox/route-84943536516b00b2.js +1 -0
  191. package/_standalone/.next/static/chunks/app/api/init/route-84943536516b00b2.js +1 -0
  192. package/_standalone/.next/static/chunks/app/api/mcp/agents/route-84943536516b00b2.js +1 -0
  193. package/_standalone/.next/static/chunks/app/api/mcp/install/route-84943536516b00b2.js +1 -0
  194. package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-84943536516b00b2.js +1 -0
  195. package/_standalone/.next/static/chunks/app/api/mcp/restart/route-84943536516b00b2.js +1 -0
  196. package/_standalone/.next/static/chunks/app/api/mcp/status/route-84943536516b00b2.js +1 -0
  197. package/_standalone/.next/static/chunks/app/api/mcp/uninstall/route-84943536516b00b2.js +1 -0
  198. package/_standalone/.next/static/chunks/app/api/monitoring/route-84943536516b00b2.js +1 -0
  199. package/_standalone/.next/static/chunks/app/api/recent-files/route-84943536516b00b2.js +1 -0
  200. package/_standalone/.next/static/chunks/app/api/restart/route-84943536516b00b2.js +1 -0
  201. package/_standalone/.next/static/chunks/app/api/search/route-84943536516b00b2.js +1 -0
  202. package/_standalone/.next/static/chunks/app/api/settings/list-models/route-84943536516b00b2.js +1 -0
  203. package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-84943536516b00b2.js +1 -0
  204. package/_standalone/.next/static/chunks/app/api/settings/route-84943536516b00b2.js +1 -0
  205. package/_standalone/.next/static/chunks/app/api/settings/test-key/route-84943536516b00b2.js +1 -0
  206. package/_standalone/.next/static/chunks/app/api/setup/check-path/route-84943536516b00b2.js +1 -0
  207. package/_standalone/.next/static/chunks/app/api/setup/check-port/route-84943536516b00b2.js +1 -0
  208. package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-84943536516b00b2.js +1 -0
  209. package/_standalone/.next/static/chunks/app/api/setup/ls/route-84943536516b00b2.js +1 -0
  210. package/_standalone/.next/static/chunks/app/api/setup/route-84943536516b00b2.js +1 -0
  211. package/_standalone/.next/static/chunks/app/api/skills/route-84943536516b00b2.js +1 -0
  212. package/_standalone/.next/static/chunks/app/api/sync/route-84943536516b00b2.js +1 -0
  213. package/_standalone/.next/static/chunks/app/api/tree-version/route-84943536516b00b2.js +1 -0
  214. package/_standalone/.next/static/chunks/app/api/uninstall/route-84943536516b00b2.js +1 -0
  215. package/_standalone/.next/static/chunks/app/api/update/route-84943536516b00b2.js +1 -0
  216. package/_standalone/.next/static/chunks/app/api/update-check/route-84943536516b00b2.js +1 -0
  217. package/_standalone/.next/static/chunks/app/api/update-status/route-84943536516b00b2.js +1 -0
  218. package/_standalone/.next/static/chunks/app/api/workflows/route-84943536516b00b2.js +1 -0
  219. package/_standalone/.next/static/chunks/app/echo/page-84943536516b00b2.js +1 -0
  220. package/_standalone/.next/static/chunks/app/help/page-2325d25b6846ca07.js +1 -0
  221. package/_standalone/.next/static/chunks/app/{layout-9378c1c8d3e5761b.js → layout-7cb442df92212140.js} +55 -55
  222. package/_standalone/.next/static/chunks/app/{page-9bae420fbbdc5fff.js → page-aaee2d9bd3d3eabb.js} +1 -1
  223. package/_standalone/.next/static/chunks/app/setup/page-6132ea7632e08a9b.js +1 -0
  224. package/_standalone/.next/static/chunks/app/trash/{page-b61ef2d5cd4f8d73.js → page-7b5cbf541c315db2.js} +1 -1
  225. package/_standalone/.next/static/chunks/app/view/[...path]/loading-84943536516b00b2.js +1 -0
  226. package/_standalone/.next/static/chunks/app/view/[...path]/page-b72e4f88c8c48181.js +12 -0
  227. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-84943536516b00b2.js +1 -0
  228. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-84943536516b00b2.js +1 -0
  229. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-84943536516b00b2.js +1 -0
  230. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-84943536516b00b2.js +1 -0
  231. package/_standalone/.next/static/chunks/{webpack-c28c55d0a6021a6b.js → webpack-7b276daaa930d480.js} +1 -1
  232. package/_standalone/.next/static/css/bc9179074eaf65ae.css +1 -0
  233. package/_standalone/.next/trace +63 -63
  234. package/_standalone/.next/types/routes.d.ts +2 -1
  235. package/_standalone/.next/types/validator.ts +9 -0
  236. package/_standalone/__tests__/api/mcp-install.test.ts +23 -0
  237. package/_standalone/__tests__/cli/agent-routing.test.ts +232 -0
  238. package/_standalone/__tests__/cli/file-subcommands.test.ts +379 -0
  239. package/_standalone/__tests__/core/tools.test.ts +3 -6
  240. package/_standalone/components/FileTree.tsx +3 -2
  241. package/_standalone/components/MarkdownView.tsx +30 -15
  242. package/_standalone/components/RightAskPanel.tsx +36 -6
  243. package/_standalone/components/Sidebar.tsx +3 -3
  244. package/_standalone/components/agents/AgentsMcpSection.tsx +27 -5
  245. package/_standalone/components/settings/McpAgentInstall.tsx +94 -27
  246. package/_standalone/components/settings/McpSkillsSection.tsx +1 -1
  247. package/_standalone/components/settings/McpTab.tsx +484 -340
  248. package/_standalone/components/settings/SettingsContent.tsx +12 -6
  249. package/_standalone/components/settings/types.ts +3 -0
  250. package/_standalone/components/setup/StepAgents.tsx +113 -47
  251. package/_standalone/components/setup/StepReview.tsx +14 -27
  252. package/_standalone/components/setup/types.ts +7 -0
  253. package/_standalone/data/skills/mindos/SKILL.md +92 -92
  254. package/_standalone/data/skills/mindos/references/write-supplement.md +119 -0
  255. package/_standalone/data/skills/mindos-zh/SKILL.md +100 -104
  256. package/_standalone/data/skills/mindos-zh/references/write-supplement.md +119 -0
  257. package/_standalone/lib/i18n/modules/features.ts +4 -4
  258. package/_standalone/lib/i18n/modules/knowledge.ts +4 -0
  259. package/_standalone/lib/i18n/modules/onboarding.ts +40 -30
  260. package/_standalone/lib/i18n/modules/panels.ts +6 -2
  261. package/_standalone/lib/i18n/modules/settings.ts +78 -6
  262. package/_standalone/lib/mcp-snippets.ts +5 -1
  263. package/_standalone/tsconfig.tsbuildinfo +1 -1
  264. package/app/app/api/ask/route.ts +3 -2
  265. package/app/app/api/mcp/install/route.ts +15 -3
  266. package/app/app/api/mcp/status/route.ts +14 -6
  267. package/app/app/api/mcp/uninstall/route.ts +130 -0
  268. package/app/app/api/skills/route.ts +14 -1
  269. package/app/app/view/[...path]/ViewPageClient.tsx +12 -27
  270. package/app/components/FileTree.tsx +3 -2
  271. package/app/components/MarkdownView.tsx +30 -15
  272. package/app/components/RightAskPanel.tsx +36 -6
  273. package/app/components/Sidebar.tsx +3 -3
  274. package/app/components/agents/AgentsMcpSection.tsx +27 -5
  275. package/app/components/help/HelpContent.tsx +1 -0
  276. package/app/components/settings/McpAgentInstall.tsx +94 -27
  277. package/app/components/settings/McpSkillsSection.tsx +1 -1
  278. package/app/components/settings/McpTab.tsx +484 -340
  279. package/app/components/settings/SettingsContent.tsx +12 -6
  280. package/app/components/settings/types.ts +3 -0
  281. package/app/components/setup/StepAgents.tsx +113 -47
  282. package/app/components/setup/StepReview.tsx +14 -27
  283. package/app/components/setup/index.tsx +16 -14
  284. package/app/components/setup/types.ts +7 -0
  285. package/app/data/skills/mindos/SKILL.md +92 -92
  286. package/app/data/skills/mindos/references/write-supplement.md +119 -0
  287. package/app/data/skills/mindos-zh/SKILL.md +100 -104
  288. package/app/data/skills/mindos-zh/references/write-supplement.md +119 -0
  289. package/app/lib/fs.ts +0 -6
  290. package/app/lib/i18n/modules/features.ts +4 -4
  291. package/app/lib/i18n/modules/knowledge.ts +4 -0
  292. package/app/lib/i18n/modules/onboarding.ts +40 -30
  293. package/app/lib/i18n/modules/panels.ts +6 -2
  294. package/app/lib/i18n/modules/settings.ts +78 -6
  295. package/app/lib/mcp-agents.ts +1 -2
  296. package/app/lib/mcp-snippets.ts +5 -1
  297. package/app/lib/renderers/index.ts +2 -1
  298. package/app/lib/settings.ts +32 -0
  299. package/bin/cli.js +168 -1404
  300. package/bin/commands/agent.js +156 -20
  301. package/bin/commands/api.js +14 -11
  302. package/bin/commands/ask.js +79 -68
  303. package/bin/commands/build.js +26 -0
  304. package/bin/commands/config.js +170 -0
  305. package/bin/commands/dev.js +58 -0
  306. package/bin/commands/doctor.js +205 -0
  307. package/bin/commands/file.js +551 -36
  308. package/bin/commands/gateway.js +42 -0
  309. package/bin/commands/init-skills.js +56 -0
  310. package/bin/commands/logs.js +32 -0
  311. package/bin/commands/mcp-cmd.js +57 -0
  312. package/bin/commands/onboard.js +25 -0
  313. package/bin/commands/open.js +41 -0
  314. package/bin/commands/restart.js +48 -0
  315. package/bin/commands/search.js +16 -14
  316. package/bin/commands/space.js +96 -25
  317. package/bin/commands/start.js +272 -0
  318. package/bin/commands/status.js +2 -2
  319. package/bin/commands/stop.js +14 -0
  320. package/bin/commands/sync-cmd.js +134 -0
  321. package/bin/commands/token.js +98 -0
  322. package/bin/commands/uninstall.js +154 -0
  323. package/bin/commands/update.js +286 -0
  324. package/bin/lib/build.js +1 -1
  325. package/bin/lib/colors.js +8 -7
  326. package/bin/lib/command.js +37 -96
  327. package/bin/lib/config.js +5 -0
  328. package/bin/lib/csv.js +19 -0
  329. package/bin/lib/jsonc.js +12 -0
  330. package/bin/lib/markdown.js +69 -0
  331. package/bin/lib/mcp-agents.js +1 -6
  332. package/bin/lib/mcp-build.js +1 -1
  333. package/bin/lib/mcp-install.js +2 -1
  334. package/bin/lib/one-shot.js +88 -0
  335. package/bin/lib/path-expand.js +9 -0
  336. package/bin/lib/remote.js +65 -0
  337. package/bin/lib/repl.js +167 -0
  338. package/bin/lib/{utils.js → shell.js} +10 -26
  339. package/bin/lib/skill-check.js +116 -21
  340. package/bin/lib/sse-stream.js +167 -0
  341. package/package.json +2 -2
  342. package/scripts/setup.js +210 -120
  343. package/skills/mindos/SKILL.md +94 -95
  344. package/skills/mindos-zh/SKILL.md +103 -106
  345. package/_standalone/.next/server/chunks/1955.js +0 -11
  346. package/_standalone/.next/server/chunks/3680.js +0 -1
  347. package/_standalone/.next/server/chunks/4497.js +0 -219
  348. package/_standalone/.next/server/chunks/5560.js +0 -2
  349. package/_standalone/.next/static/chunks/1053-0adaccc98a752a58.js +0 -29
  350. package/_standalone/.next/static/chunks/3637.f9a42cca59fd5bb5.js +0 -1
  351. package/_standalone/.next/static/chunks/4563-c2afaeacb241d1d0.js +0 -6
  352. package/_standalone/.next/static/chunks/6090-c98268ca726a68d3.js +0 -1
  353. package/_standalone/.next/static/chunks/9371-575600301da5d6bb.js +0 -1
  354. package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/route-400c3c09b1540c14.js +0 -1
  355. package/_standalone/.next/static/chunks/app/_global-error/page-400c3c09b1540c14.js +0 -1
  356. package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-3e08abb495ecd5fd.js +0 -1
  357. package/_standalone/.next/static/chunks/app/agents/page-e7e0f87ad3d765ac.js +0 -5
  358. package/_standalone/.next/static/chunks/app/api/a2a/agents/route-400c3c09b1540c14.js +0 -1
  359. package/_standalone/.next/static/chunks/app/api/a2a/delegations/route-400c3c09b1540c14.js +0 -1
  360. package/_standalone/.next/static/chunks/app/api/a2a/discover/route-400c3c09b1540c14.js +0 -1
  361. package/_standalone/.next/static/chunks/app/api/a2a/route-400c3c09b1540c14.js +0 -1
  362. package/_standalone/.next/static/chunks/app/api/acp/config/route-400c3c09b1540c14.js +0 -1
  363. package/_standalone/.next/static/chunks/app/api/acp/detect/route-400c3c09b1540c14.js +0 -1
  364. package/_standalone/.next/static/chunks/app/api/acp/install/route-400c3c09b1540c14.js +0 -1
  365. package/_standalone/.next/static/chunks/app/api/acp/registry/route-400c3c09b1540c14.js +0 -1
  366. package/_standalone/.next/static/chunks/app/api/acp/session/route-400c3c09b1540c14.js +0 -1
  367. package/_standalone/.next/static/chunks/app/api/agent-activity/route-400c3c09b1540c14.js +0 -1
  368. package/_standalone/.next/static/chunks/app/api/ask/route-400c3c09b1540c14.js +0 -1
  369. package/_standalone/.next/static/chunks/app/api/ask-sessions/route-400c3c09b1540c14.js +0 -1
  370. package/_standalone/.next/static/chunks/app/api/auth/route-400c3c09b1540c14.js +0 -1
  371. package/_standalone/.next/static/chunks/app/api/backlinks/route-400c3c09b1540c14.js +0 -1
  372. package/_standalone/.next/static/chunks/app/api/bootstrap/route-400c3c09b1540c14.js +0 -1
  373. package/_standalone/.next/static/chunks/app/api/changes/route-400c3c09b1540c14.js +0 -1
  374. package/_standalone/.next/static/chunks/app/api/export/route-400c3c09b1540c14.js +0 -1
  375. package/_standalone/.next/static/chunks/app/api/extract-pdf/route-400c3c09b1540c14.js +0 -1
  376. package/_standalone/.next/static/chunks/app/api/file/import/route-400c3c09b1540c14.js +0 -1
  377. package/_standalone/.next/static/chunks/app/api/file/route-400c3c09b1540c14.js +0 -1
  378. package/_standalone/.next/static/chunks/app/api/files/route-400c3c09b1540c14.js +0 -1
  379. package/_standalone/.next/static/chunks/app/api/git/route-400c3c09b1540c14.js +0 -1
  380. package/_standalone/.next/static/chunks/app/api/graph/route-400c3c09b1540c14.js +0 -1
  381. package/_standalone/.next/static/chunks/app/api/health/route-400c3c09b1540c14.js +0 -1
  382. package/_standalone/.next/static/chunks/app/api/inbox/route-400c3c09b1540c14.js +0 -1
  383. package/_standalone/.next/static/chunks/app/api/init/route-400c3c09b1540c14.js +0 -1
  384. package/_standalone/.next/static/chunks/app/api/mcp/agents/route-400c3c09b1540c14.js +0 -1
  385. package/_standalone/.next/static/chunks/app/api/mcp/install/route-400c3c09b1540c14.js +0 -1
  386. package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-400c3c09b1540c14.js +0 -1
  387. package/_standalone/.next/static/chunks/app/api/mcp/restart/route-400c3c09b1540c14.js +0 -1
  388. package/_standalone/.next/static/chunks/app/api/mcp/status/route-400c3c09b1540c14.js +0 -1
  389. package/_standalone/.next/static/chunks/app/api/monitoring/route-400c3c09b1540c14.js +0 -1
  390. package/_standalone/.next/static/chunks/app/api/recent-files/route-400c3c09b1540c14.js +0 -1
  391. package/_standalone/.next/static/chunks/app/api/restart/route-400c3c09b1540c14.js +0 -1
  392. package/_standalone/.next/static/chunks/app/api/search/route-400c3c09b1540c14.js +0 -1
  393. package/_standalone/.next/static/chunks/app/api/settings/list-models/route-400c3c09b1540c14.js +0 -1
  394. package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-400c3c09b1540c14.js +0 -1
  395. package/_standalone/.next/static/chunks/app/api/settings/route-400c3c09b1540c14.js +0 -1
  396. package/_standalone/.next/static/chunks/app/api/settings/test-key/route-400c3c09b1540c14.js +0 -1
  397. package/_standalone/.next/static/chunks/app/api/setup/check-path/route-400c3c09b1540c14.js +0 -1
  398. package/_standalone/.next/static/chunks/app/api/setup/check-port/route-400c3c09b1540c14.js +0 -1
  399. package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-400c3c09b1540c14.js +0 -1
  400. package/_standalone/.next/static/chunks/app/api/setup/ls/route-400c3c09b1540c14.js +0 -1
  401. package/_standalone/.next/static/chunks/app/api/setup/route-400c3c09b1540c14.js +0 -1
  402. package/_standalone/.next/static/chunks/app/api/skills/route-400c3c09b1540c14.js +0 -1
  403. package/_standalone/.next/static/chunks/app/api/sync/route-400c3c09b1540c14.js +0 -1
  404. package/_standalone/.next/static/chunks/app/api/tree-version/route-400c3c09b1540c14.js +0 -1
  405. package/_standalone/.next/static/chunks/app/api/uninstall/route-400c3c09b1540c14.js +0 -1
  406. package/_standalone/.next/static/chunks/app/api/update/route-400c3c09b1540c14.js +0 -1
  407. package/_standalone/.next/static/chunks/app/api/update-check/route-400c3c09b1540c14.js +0 -1
  408. package/_standalone/.next/static/chunks/app/api/update-status/route-400c3c09b1540c14.js +0 -1
  409. package/_standalone/.next/static/chunks/app/api/workflows/route-400c3c09b1540c14.js +0 -1
  410. package/_standalone/.next/static/chunks/app/echo/page-400c3c09b1540c14.js +0 -1
  411. package/_standalone/.next/static/chunks/app/help/page-3d0e1ceaa4abc243.js +0 -1
  412. package/_standalone/.next/static/chunks/app/setup/page-99ed3d1bb6b8f4ef.js +0 -1
  413. package/_standalone/.next/static/chunks/app/view/[...path]/loading-400c3c09b1540c14.js +0 -1
  414. package/_standalone/.next/static/chunks/app/view/[...path]/page-44fa78cbea613a78.js +0 -12
  415. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-400c3c09b1540c14.js +0 -1
  416. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-400c3c09b1540c14.js +0 -1
  417. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-400c3c09b1540c14.js +0 -1
  418. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-400c3c09b1540c14.js +0 -1
  419. package/_standalone/.next/static/css/d300701f384db50d.css +0 -1
  420. package/_standalone/.next/static/rZLs1krFuduixvcVNe6q3/_buildManifest.js +0 -1
  421. package/_standalone/components/renderers/agent-inspector/manifest.ts +0 -16
  422. /package/_standalone/.next/static/{rZLs1krFuduixvcVNe6q3 → GB-YReQ58tsvCuwlzrkMZ}/_ssgManifest.js +0 -0
@@ -1,5 +1,5 @@
1
1
  import { useState, useMemo, useRef, useEffect, useCallback } from 'react';
2
- import { Loader2, Copy, Check, Monitor, Globe, AlertCircle, RotateCcw, RefreshCw, Eye, EyeOff, ChevronDown, ChevronRight, Link2, Shield } from 'lucide-react';
2
+ import { Loader2, Copy, Check, Monitor, Globe, AlertCircle, RotateCcw, RefreshCw, Eye, EyeOff, ChevronDown, ChevronRight, Link2, Shield, Terminal, Plug, CheckCircle2, Sparkles, Users } from 'lucide-react';
3
3
  import { toast } from '@/lib/toast';
4
4
  import { useMcpDataOptional } from '@/lib/stores/mcp-store';
5
5
  import { generateSnippet } from '@/lib/mcp-snippets';
@@ -11,18 +11,17 @@ import type { McpTabProps, McpStatus, AgentInfo } from './types';
11
11
  import AgentInstall from './McpAgentInstall';
12
12
  import SkillsSection from './McpSkillsSection';
13
13
 
14
- /* ── Main McpTab ───────────────────────────────────────────────── */
14
+ /* ── Main Connections Tab ────────────────────────────────────────── */
15
15
 
16
16
  export function McpTab({ t }: McpTabProps) {
17
17
  const mcp = useMcpDataOptional();
18
18
  const m = t.settings?.mcp;
19
19
 
20
+ const [mode, setMode] = useState<'cli' | 'mcp'>('cli');
20
21
  const [restarting, setRestarting] = useState(false);
21
22
  const [selectedAgent, setSelectedAgent] = useState('');
22
- const [transport, setTransport] = useState<'stdio' | 'http'>('stdio');
23
23
  const restartPollRef = useRef<ReturnType<typeof setInterval>>(undefined);
24
24
 
25
- // Cleanup restart poll on unmount
26
25
  useEffect(() => () => clearInterval(restartPollRef.current), []);
27
26
 
28
27
  if (!mcp || mcp.loading) {
@@ -36,408 +35,553 @@ export function McpTab({ t }: McpTabProps) {
36
35
  const connectedAgents = mcp.agents.filter(a => a.present && a.installed);
37
36
  const detectedAgents = mcp.agents.filter(a => a.present && !a.installed);
38
37
  const notFoundAgents = mcp.agents.filter(a => !a.present);
39
-
40
- // Auto-select first agent if none selected
41
38
  const effectiveSelected = selectedAgent || (mcp.agents[0]?.key ?? '');
42
39
  const currentAgent = mcp.agents.find(a => a.key === effectiveSelected);
43
40
 
41
+ // Determine active skill name based on which mindos skill is enabled
42
+ const mindosEnabled = mcp.skills?.find(s => s.name === 'mindos')?.enabled ?? true;
43
+ const activeSkillName = mindosEnabled ? 'mindos' : 'mindos-zh';
44
+
45
+ const handleRestart = async () => {
46
+ setRestarting(true);
47
+ try {
48
+ await apiFetch('/api/mcp/restart', { method: 'POST' });
49
+ } catch (err) {
50
+ console.error('[McpTab] Restart request failed:', err);
51
+ setRestarting(false);
52
+ return;
53
+ }
54
+ const deadline = Date.now() + 60_000;
55
+ clearInterval(restartPollRef.current);
56
+ restartPollRef.current = setInterval(async () => {
57
+ if (Date.now() > deadline) {
58
+ clearInterval(restartPollRef.current);
59
+ setRestarting(false);
60
+ return;
61
+ }
62
+ try {
63
+ const s = await apiFetch<McpStatus>('/api/mcp/status', { timeout: 3000 });
64
+ if (s.running) {
65
+ clearInterval(restartPollRef.current);
66
+ setRestarting(false);
67
+ mcp.refresh();
68
+ }
69
+ } catch { /* continue polling */ }
70
+ }, 3000);
71
+ };
72
+
44
73
  return (
45
74
  <div className="space-y-6">
46
- {/* Server status with restart */}
47
- <McpStatusCard
75
+ {/* 1. Auth Token */}
76
+ <AuthTokenCard status={mcp.status} m={m} />
77
+
78
+ {/* 2. Connect Agents (CLI/MCP guides + detected agents) */}
79
+ <ConnectCard
80
+ mode={mode}
81
+ onModeChange={setMode}
48
82
  status={mcp.status}
83
+ agents={mcp.agents}
84
+ connectedAgents={connectedAgents}
85
+ detectedAgents={detectedAgents}
86
+ notFoundAgents={notFoundAgents}
87
+ currentAgent={currentAgent ?? null}
88
+ selectedAgent={effectiveSelected}
89
+ onSelectAgent={setSelectedAgent}
49
90
  restarting={restarting}
50
- onRestart={async () => {
51
- setRestarting(true);
52
- try {
53
- await apiFetch('/api/mcp/restart', { method: 'POST' });
54
- } catch (err) {
55
- console.error('[McpTab] Restart request failed:', err);
56
- setRestarting(false);
57
- return; // Exit early, don't start polling if restart request fails
58
- }
59
- const deadline = Date.now() + 60_000;
60
- clearInterval(restartPollRef.current);
61
- restartPollRef.current = setInterval(async () => {
62
- if (Date.now() > deadline) {
63
- clearInterval(restartPollRef.current);
64
- setRestarting(false);
65
- console.warn('[McpTab] MCP restart timed out after 60s');
66
- return;
67
- }
68
- try {
69
- const s = await apiFetch<McpStatus>('/api/mcp/status', { timeout: 3000 });
70
- if (s.running) {
71
- clearInterval(restartPollRef.current);
72
- setRestarting(false);
73
- mcp.refresh();
74
- }
75
- } catch (err) {
76
- console.warn('[McpTab] Status poll attempt failed:', err);
77
- // Continue polling on individual failures
78
- }
79
- }, 3000);
80
- }}
91
+ onRestart={handleRestart}
81
92
  onRefresh={mcp.refresh}
93
+ activeSkillName={activeSkillName}
82
94
  m={m}
95
+ t={t}
83
96
  />
84
97
 
85
- {/* Connection Info — token + URL */}
86
- <McpConnectionCard status={mcp.status} m={m} />
87
-
88
- {/* MCP Config Viewer */}
89
- {mcp.agents.length > 0 && (
90
- <div>
91
- <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3">MCP</p>
92
- <AgentConfigViewer
93
- connectedAgents={connectedAgents}
94
- detectedAgents={detectedAgents}
95
- notFoundAgents={notFoundAgents}
96
- currentAgent={currentAgent ?? null}
97
- mcpStatus={mcp.status}
98
- selectedAgent={effectiveSelected}
99
- onSelectAgent={(key) => setSelectedAgent(key)}
100
- transport={transport}
101
- onTransportChange={setTransport}
102
- onCopy={async (snippet) => {
103
- const ok = await copyToClipboard(snippet);
104
- if (ok) toast.copy();
105
- }}
106
- m={m}
107
- />
98
+ {/* 3. Skills */}
99
+ <div className="rounded-xl border border-border bg-card overflow-hidden">
100
+ <div className="flex items-center gap-2.5 px-4 pt-4 pb-3">
101
+ <div className="w-7 h-7 rounded-lg bg-muted flex items-center justify-center shrink-0">
102
+ <Sparkles size={14} className="text-muted-foreground" />
103
+ </div>
104
+ <div className="flex-1 min-w-0">
105
+ <h3 className="text-sm font-semibold text-foreground">{m?.skillsTitle ?? 'Skills'}</h3>
106
+ <p className="text-2xs text-muted-foreground">{m?.skillsDesc ?? 'Teach agents how to operate your knowledge base.'}</p>
107
+ </div>
108
+ </div>
109
+ <div className="px-4 pb-4">
110
+ <SkillsSection t={t} />
108
111
  </div>
109
- )}
110
-
111
- {/* Skills */}
112
- <div>
113
- <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3">{m?.skillsTitle ?? 'Skills'}</p>
114
- <SkillsSection t={t} />
115
- </div>
116
-
117
- {/* Batch Agent Install */}
118
- <div>
119
- <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3">{m?.agentsTitle ?? 'Agent Configuration'}</p>
120
- <AgentInstall agents={mcp.agents} t={t} onRefresh={mcp.refresh} />
121
112
  </div>
122
113
  </div>
123
114
  );
124
115
  }
125
116
 
126
- /* ── MCP Status Card ── */
117
+ /* ── Auth Token Card ── */
127
118
 
128
- function McpStatusCard({ status, restarting, onRestart, onRefresh, m }: {
119
+ function AuthTokenCard({ status, m }: {
129
120
  status: McpStatus | null;
130
- restarting: boolean;
131
- onRestart: () => void;
132
- onRefresh: () => void;
133
121
  m: Record<string, any> | undefined;
134
122
  }) {
123
+ const [copiedField, setCopiedField] = useState<string | null>(null);
124
+ const [revealed, setRevealed] = useState(false);
125
+
126
+ useEffect(() => () => setRevealed(false), []);
127
+ useEffect(() => {
128
+ if (!copiedField) return;
129
+ const t = setTimeout(() => setCopiedField(null), 2000);
130
+ return () => clearTimeout(t);
131
+ }, [copiedField]);
132
+
133
+ const handleCopy = useCallback(async (text: string, field: string) => {
134
+ if (!text) return;
135
+ const ok = await copyToClipboard(text);
136
+ if (ok) { setCopiedField(field); toast.copy(); }
137
+ }, []);
138
+
135
139
  if (!status) return null;
140
+
141
+ const hasToken = status.authConfigured && !!status.authToken;
142
+ const displayToken = revealed ? (status.authToken ?? '') : (status.maskedToken ?? '');
143
+
136
144
  return (
137
- <div className="rounded-xl border border-border bg-card p-4 flex items-center justify-between">
138
- <div className="flex items-center gap-2.5 text-sm">
139
- {restarting ? (
140
- <>
141
- <Loader2 size={12} className="animate-spin text-[var(--amber)]" />
142
- <span className="text-[var(--amber)]">{m?.restarting ?? 'Restarting...'}</span>
143
- </>
144
- ) : (
145
- <>
146
- <span className={`inline-block w-1.5 h-1.5 rounded-full shrink-0 ${status.running ? 'bg-success' : 'bg-muted-foreground'}`} />
147
- <span className="text-foreground font-medium">
148
- {status.running ? (m?.running ?? 'Running') : (m?.stopped ?? 'Stopped')}
149
- </span>
150
- {status.running && (
151
- <>
152
- <span className="text-muted-foreground">·</span>
153
- <span className="font-mono text-muted-foreground">{status.endpoint}</span>
154
- <span className="text-muted-foreground">·</span>
155
- <span className="text-muted-foreground">{status.toolCount} {m?.tools ?? 'tools'}</span>
156
- </>
157
- )}
158
- </>
159
- )}
145
+ <div className="rounded-xl border border-border bg-card overflow-hidden">
146
+ <div className="flex items-center gap-2.5 px-4 pt-4 pb-3">
147
+ <div className="w-7 h-7 rounded-lg bg-muted flex items-center justify-center shrink-0">
148
+ <Shield size={14} className="text-muted-foreground" />
149
+ </div>
150
+ <div className="flex-1 min-w-0">
151
+ <h3 className="text-sm font-semibold text-foreground">{m?.tokenCardTitle ?? 'Auth Token'}</h3>
152
+ <p className="text-2xs text-muted-foreground">{m?.tokenCardDesc ?? 'Used by CLI remote mode and MCP connections.'}</p>
153
+ </div>
160
154
  </div>
161
- <div className="flex items-center gap-2">
162
- {!status.running && !restarting && (
163
- <button onClick={onRestart}
164
- className="flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-lg font-medium text-[var(--amber-foreground)] bg-[var(--amber)] transition-colors">
165
- <RotateCcw size={14} /> {m?.restart ?? 'Restart'}
166
- </button>
155
+ <div className="px-4 pb-4">
156
+ {hasToken ? (
157
+ <div className="flex items-center gap-2">
158
+ <div className="flex-1 flex items-center gap-2 px-2.5 py-1.5 bg-muted/50 border border-border rounded-lg min-h-[34px]">
159
+ <code className="flex-1 text-xs font-mono text-foreground break-all select-all leading-relaxed">{displayToken}</code>
160
+ </div>
161
+ <button type="button" onClick={() => setRevealed(v => !v)}
162
+ className="shrink-0 p-1.5 rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors focus-visible:ring-2 focus-visible:ring-ring"
163
+ title={revealed ? (m?.tokenHide ?? 'Hide') : (m?.tokenShow ?? 'Show')}>
164
+ {revealed ? <EyeOff size={13} /> : <Eye size={13} />}
165
+ </button>
166
+ <CopyButton onCopy={() => handleCopy(status.authToken ?? '', 'token-card')} copied={copiedField === 'token-card'} title={m?.tokenCopy ?? 'Copy'} size="sm" />
167
+ </div>
168
+ ) : (
169
+ <div className="px-2.5 py-2 bg-[var(--amber-subtle)] border border-[var(--amber)]/20 rounded-lg">
170
+ <p className="text-xs text-[var(--amber-text)]">{m?.tokenNone ?? 'No token set.'}</p>
171
+ <p className="text-2xs text-muted-foreground mt-0.5">{m?.tokenNoneAction ?? 'Generate one in Settings → General → Security.'}</p>
172
+ </div>
167
173
  )}
168
- <button onClick={onRefresh}
169
- className="p-1.5 rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors">
170
- <RefreshCw size={14} />
171
- </button>
172
174
  </div>
173
175
  </div>
174
176
  );
175
177
  }
176
178
 
177
- /* ── Agent Config Viewer (dropdown + snippet) ── */
179
+ /* ── Shared copy-state hook for guide sub-components ── */
180
+
181
+ function useCopyField() {
182
+ const [copiedField, setCopiedField] = useState<string | null>(null);
183
+ useEffect(() => {
184
+ if (!copiedField) return;
185
+ const timer = setTimeout(() => setCopiedField(null), 2000);
186
+ return () => clearTimeout(timer);
187
+ }, [copiedField]);
188
+ const handleCopy = useCallback(async (text: string, field: string) => {
189
+ if (!text) return;
190
+ const ok = await copyToClipboard(text);
191
+ if (ok) { setCopiedField(field); toast.copy(); }
192
+ }, []);
193
+ return { copiedField, handleCopy };
194
+ }
195
+
196
+ /* ── Connect Card — header + CLI/MCP tabs + detected agents ── */
178
197
 
179
- function AgentConfigViewer({ connectedAgents, detectedAgents, notFoundAgents, currentAgent, mcpStatus, selectedAgent, onSelectAgent, transport, onTransportChange, onCopy, m }: {
198
+ function ConnectCard({ mode, onModeChange, status, agents, connectedAgents, detectedAgents, notFoundAgents, currentAgent, selectedAgent, onSelectAgent, restarting, onRestart, onRefresh, activeSkillName, m, t }: {
199
+ mode: 'cli' | 'mcp';
200
+ onModeChange: (m: 'cli' | 'mcp') => void;
201
+ status: McpStatus | null;
202
+ agents: AgentInfo[];
180
203
  connectedAgents: AgentInfo[];
181
204
  detectedAgents: AgentInfo[];
182
205
  notFoundAgents: AgentInfo[];
183
206
  currentAgent: AgentInfo | null;
184
- mcpStatus: McpStatus | null;
185
207
  selectedAgent: string;
186
208
  onSelectAgent: (key: string) => void;
187
- transport: 'stdio' | 'http';
188
- onTransportChange: (t: 'stdio' | 'http') => void;
189
- onCopy: (snippet: string) => void;
209
+ restarting: boolean;
210
+ onRestart: () => void;
211
+ onRefresh: () => void;
212
+ activeSkillName: string;
190
213
  m: Record<string, any> | undefined;
214
+ t: McpTabProps['t'];
191
215
  }) {
192
- const snippet = useMemo(
193
- () => currentAgent ? generateSnippet(currentAgent, mcpStatus, transport) : null,
194
- [currentAgent, mcpStatus, transport]
195
- );
216
+ if (!status) return null;
196
217
 
197
218
  return (
198
- <div className="rounded-xl border border-border bg-card p-4 space-y-3">
199
- {/* Agent selector */}
200
- <CustomSelect
201
- value={selectedAgent}
202
- onChange={onSelectAgent}
203
- options={[
204
- ...(connectedAgents.length > 0 ? [{
205
- label: m?.connectedGroup ?? 'Connected',
206
- options: connectedAgents.map(a => ({
207
- value: a.key,
208
- label: `${a.name} — ${a.transport ?? 'stdio'} · ${a.scope ?? 'global'}`,
209
- })),
210
- }] : []),
211
- ...(detectedAgents.length > 0 ? [{
212
- label: m?.detectedGroup ?? 'Detected (not configured)',
213
- options: detectedAgents.map(a => ({
214
- value: a.key,
215
- label: `${a.name} — ${m?.notConfigured ?? 'not configured'}`,
216
- })),
217
- }] : []),
218
- ...(notFoundAgents.length > 0 ? [{
219
- label: m?.notFoundGroup ?? 'Not Installed',
220
- options: notFoundAgents.map(a => ({
221
- value: a.key,
222
- label: a.name,
223
- })),
224
- }] : []),
225
- ] as SelectItem[]}
226
- />
227
-
228
- {currentAgent && (
229
- <>
230
- {/* Agent status badge */}
231
- <div className="flex items-center gap-2">
232
- {currentAgent.present && currentAgent.installed ? (
233
- <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-2xs font-medium bg-success/10 text-success">
234
- <span className="w-1.5 h-1.5 rounded-full bg-success inline-block" />
235
- {m?.tagConnected ?? 'Connected'}
236
- </span>
237
- ) : currentAgent.present && !currentAgent.installed ? (
238
- <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-2xs font-medium bg-[var(--amber-subtle)] text-[var(--amber-text)]">
239
- <span className="w-1.5 h-1.5 rounded-full bg-[var(--amber)] inline-block" />
240
- {m?.tagDetected ?? 'Detected — not configured'}
241
- </span>
242
- ) : (
243
- <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-2xs font-medium bg-muted text-muted-foreground">
244
- <span className="w-1.5 h-1.5 rounded-full bg-muted-foreground inline-block" />
245
- {m?.tagNotInstalled ?? 'Not installed'}
246
- </span>
247
- )}
248
- {currentAgent.transport && (
249
- <span className="px-1.5 py-0.5 rounded text-2xs bg-muted text-muted-foreground">{currentAgent.transport}</span>
250
- )}
251
- {currentAgent.scope && (
252
- <span className="px-1.5 py-0.5 rounded text-2xs bg-muted text-muted-foreground">{currentAgent.scope}</span>
253
- )}
254
- </div>
219
+ <div className="rounded-xl border border-border bg-card overflow-hidden">
220
+ {/* Header */}
221
+ <div className="flex items-center gap-2.5 px-4 pt-4 pb-3">
222
+ <div className="w-7 h-7 rounded-lg bg-[var(--amber-subtle)] flex items-center justify-center shrink-0">
223
+ <Link2 size={14} className="text-[var(--amber)]" />
224
+ </div>
225
+ <h3 className="text-sm font-semibold text-foreground">{m?.connectionTitle ?? 'Connect Agents'}</h3>
226
+ </div>
255
227
 
256
- {/* Transport toggle */}
257
- <div className="flex items-center rounded-lg border border-border overflow-hidden w-fit">
258
- <button
259
- onClick={() => onTransportChange('stdio')}
260
- className={`flex items-center gap-1.5 px-3 py-1.5 text-sm transition-colors ${
261
- transport === 'stdio' ? 'bg-muted text-foreground font-medium' : 'text-muted-foreground hover:text-foreground'
262
- }`}
263
- >
264
- <Monitor size={14} /> {m?.transportLocal ?? 'Local (stdio)'}
265
- </button>
266
- <button
267
- onClick={() => onTransportChange('http')}
268
- className={`flex items-center gap-1.5 px-3 py-1.5 text-sm transition-colors ${
269
- transport === 'http' ? 'bg-muted text-foreground font-medium' : 'text-muted-foreground hover:text-foreground'
270
- }`}
271
- >
272
- <Globe size={14} /> {m?.transportRemote ?? 'Remote (HTTP)'}
273
- </button>
274
- </div>
228
+ {/* Tab switcher */}
229
+ <div className="grid grid-cols-2 mx-4 mb-3 rounded-lg border border-border overflow-hidden">
230
+ <button
231
+ onClick={() => onModeChange('cli')}
232
+ className={`flex flex-col items-start px-3 py-2.5 text-left transition-colors ${
233
+ mode === 'cli' ? 'bg-muted' : 'hover:bg-muted/50'
234
+ }`}
235
+ >
236
+ <span className="flex items-center gap-1.5">
237
+ <Terminal size={12} className={mode === 'cli' ? 'text-[var(--amber)]' : 'text-muted-foreground'} />
238
+ <span className={`text-xs font-semibold ${mode === 'cli' ? 'text-foreground' : 'text-muted-foreground'}`}>CLI</span>
239
+ <span className="text-2xs px-1 py-0.5 rounded bg-[var(--amber-subtle)] text-[var(--amber-text)] font-medium leading-none">{m?.recommended ?? 'Recommended'}</span>
240
+ </span>
241
+ <span className="text-2xs text-muted-foreground mt-0.5">{m?.cliAgents ?? 'Claude Code · Gemini CLI · Codex'}</span>
242
+ </button>
243
+ <button
244
+ onClick={() => onModeChange('mcp')}
245
+ className={`flex flex-col items-start px-3 py-2.5 text-left transition-colors border-l border-border ${
246
+ mode === 'mcp' ? 'bg-muted' : 'hover:bg-muted/50'
247
+ }`}
248
+ >
249
+ <span className="flex items-center gap-1.5">
250
+ <Plug size={12} className={mode === 'mcp' ? 'text-foreground' : 'text-muted-foreground'} />
251
+ <span className={`text-xs font-semibold ${mode === 'mcp' ? 'text-foreground' : 'text-muted-foreground'}`}>MCP</span>
252
+ </span>
253
+ <span className="text-2xs text-muted-foreground mt-0.5">{m?.mcpAgents ?? 'Claude Desktop · Cursor'}</span>
254
+ </button>
255
+ </div>
275
256
 
276
- {/* Auth warning */}
277
- {transport === 'http' && mcpStatus && !mcpStatus.authConfigured && (
278
- <p className="flex items-center gap-1.5 text-xs text-[var(--amber-text)]">
279
- <AlertCircle size={12} />
280
- {m?.noAuthWarning ?? 'Auth not configured. Run `mindos token` to set up.'}
281
- </p>
282
- )}
283
-
284
- {/* Snippet */}
285
- {snippet && (
286
- <>
287
- <pre className="text-[11px] font-mono bg-muted/50 border border-border rounded-lg p-3 overflow-x-auto whitespace-pre select-all max-h-[240px] overflow-y-auto">
288
- {snippet.displaySnippet}
289
- </pre>
290
- <div className="flex items-center gap-3 text-sm">
291
- <button onClick={() => onCopy(snippet.snippet)}
292
- className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0">
293
- <Copy size={14} />
294
- {m?.copyConfig ?? 'Copy config'}
295
- </button>
296
- <span className="text-muted-foreground">→</span>
297
- <span className="font-mono text-muted-foreground truncate text-2xs">{snippet.path}</span>
298
- </div>
299
- </>
300
- )}
301
- </>
302
- )}
257
+ {/* Tab content */}
258
+ <div className="px-4 pb-4 space-y-4">
259
+ {mode === 'cli' ? (
260
+ <CliGuide status={status} activeSkillName={activeSkillName} agents={agents} connectedAgents={connectedAgents} detectedAgents={detectedAgents} notFoundAgents={notFoundAgents} onRefresh={onRefresh} m={m} t={t} />
261
+ ) : (
262
+ <McpGuide
263
+ status={status} agents={agents} activeSkillName={activeSkillName}
264
+ connectedAgents={connectedAgents} detectedAgents={detectedAgents} notFoundAgents={notFoundAgents}
265
+ currentAgent={currentAgent} selectedAgent={selectedAgent} onSelectAgent={onSelectAgent}
266
+ restarting={restarting} onRestart={onRestart} onRefresh={onRefresh} m={m} t={t}
267
+ />
268
+ )}
269
+ </div>
303
270
  </div>
304
271
  );
305
272
  }
306
273
 
307
- /* ── MCP Connection Card (Token + URL + How-to) ── */
274
+ /* ── CLI Guide (local + remote setup) ── */
308
275
 
309
- function McpConnectionCard({ status, m }: {
310
- status: McpStatus | null;
311
- m: Record<string, any> | undefined;
276
+ function CliGuide({ status, activeSkillName, agents, connectedAgents, detectedAgents, notFoundAgents, onRefresh, m, t }: {
277
+ status: McpStatus; activeSkillName: string; agents: AgentInfo[]; connectedAgents: AgentInfo[]; detectedAgents: AgentInfo[]; notFoundAgents: AgentInfo[];
278
+ onRefresh: () => void; m: Record<string, any> | undefined; t: McpTabProps['t'];
312
279
  }) {
313
- const [revealed, setRevealed] = useState(false);
314
- const [howToOpen, setHowToOpen] = useState(false);
315
- const [copiedField, setCopiedField] = useState<'token' | 'url' | null>(null);
280
+ const { copiedField, handleCopy } = useCopyField();
316
281
 
317
- // Auto-hide token when component unmounts (tab switch)
318
- useEffect(() => () => setRevealed(false), []);
282
+ const hasToken = status.authConfigured && !!status.authToken;
283
+ const remoteHost = status.localIP || 'localhost';
284
+ const webPort = typeof window !== 'undefined' ? window.location.port || '3456' : '3456';
285
+ const remoteUrl = `http://${remoteHost}:${webPort}`;
286
+ const maskedAuthToken = status.maskedToken ?? '';
319
287
 
320
- // Clear "copied" feedback after 2s
321
- useEffect(() => {
322
- if (!copiedField) return;
323
- const t = setTimeout(() => setCopiedField(null), 2000);
324
- return () => clearTimeout(t);
325
- }, [copiedField]);
288
+ return (
289
+ <>
290
+ {/* Local */}
291
+ <div className="space-y-2.5">
292
+ <div className="flex items-center gap-2">
293
+ <Monitor size={12} className="text-success" />
294
+ <span className="text-xs font-semibold text-foreground">{m?.localTitle ?? 'Local'}</span>
295
+ <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-2xs font-medium bg-success/10 text-success">
296
+ <CheckCircle2 size={10} />
297
+ {m?.localReady ?? 'Ready to use'}
298
+ </span>
299
+ </div>
300
+ <p className="text-xs text-muted-foreground">
301
+ {m?.cliLocalDesc ?? 'MindOS Skill is built-in. Install the CLI and you\'re good to go.'}
302
+ </p>
303
+ <CodeBlock code="mindos file list" label={m?.cliSkillVerify ?? 'Verify'} onCopy={handleCopy} copiedField={copiedField} fieldId="cli-verify" />
304
+
305
+ {/* Detected Agents — install Skill locally */}
306
+ {agents.length > 0 && (
307
+ <InlineCollapsible
308
+ icon={<Users size={12} className="text-muted-foreground" />}
309
+ title={m?.detectedAgentsTitle ?? 'Detected Agents'}
310
+ badge={`${connectedAgents.length + detectedAgents.length}/${agents.length}`}
311
+ >
312
+ <AgentInstall agents={agents} t={t} onRefresh={onRefresh} mode="cli" activeSkillName={activeSkillName} />
313
+ </InlineCollapsible>
314
+ )}
315
+ </div>
326
316
 
327
- const handleCopy = useCallback(async (text: string, field: 'token' | 'url') => {
328
- if (!text) return;
329
- const ok = await copyToClipboard(text);
330
- if (ok) {
331
- setCopiedField(field);
332
- toast.copy();
333
- }
334
- }, []);
317
+ {/* Remote */}
318
+ <div className="border-t border-border pt-3 space-y-3">
319
+ <div className="flex items-center gap-2">
320
+ <Globe size={12} className="text-muted-foreground" />
321
+ <span className="text-xs font-semibold text-foreground">{m?.remoteTitle ?? 'Remote Access'}</span>
322
+ </div>
323
+ <p className="text-xs text-muted-foreground">
324
+ {m?.cliRemoteDesc ?? 'Install the CLI on another machine and connect to this MindOS server.'}
325
+ </p>
326
+ <StepBlock step="1" label={m?.cliSkillInstall ?? 'Install'}>
327
+ <CodeBlock code="npm install -g @geminilight/mindos" onCopy={handleCopy} copiedField={copiedField} fieldId="cli-install" compact />
328
+ </StepBlock>
329
+ <StepBlock step="2" label={m?.cliRemoteConfigure ?? 'Configure'}>
330
+ <div className="space-y-1">
331
+ <CodeBlock code={`mindos config set url ${remoteUrl}`} onCopy={handleCopy} copiedField={copiedField} fieldId="cli-url" compact />
332
+ <CodeBlock
333
+ code={`mindos config set authToken ${hasToken ? maskedAuthToken : '<token>'}`}
334
+ onCopy={(_, field) => {
335
+ handleCopy(`mindos config set authToken ${status.authToken ?? '<token>'}`, field);
336
+ }}
337
+ copiedField={copiedField} fieldId="cli-token" compact
338
+ hint={hasToken ? (m?.tokenCopyFullHint ?? 'Copies full token') : undefined}
339
+ />
340
+ </div>
341
+ </StepBlock>
342
+ <StepBlock step="3" label={m?.cliInstallSkill ?? 'Install Skill'}>
343
+ <CodeBlock code={`npx skills add GeminiLight/MindOS --skill ${activeSkillName} -g -y`} onCopy={handleCopy} copiedField={copiedField} fieldId="cli-skill" compact />
344
+ </StepBlock>
345
+ <StepBlock step="4" label={m?.cliSkillVerify ?? 'Verify'}>
346
+ <CodeBlock code="mindos file list" onCopy={handleCopy} copiedField={copiedField} fieldId="cli-remote-verify" compact />
347
+ </StepBlock>
348
+ </div>
349
+ </>
350
+ );
351
+ }
335
352
 
336
- if (!status) return null;
353
+ /* ── MCP Guide (status + snippets + remote) ── */
354
+
355
+ function McpGuide({ status, agents, activeSkillName, connectedAgents, detectedAgents, notFoundAgents, currentAgent, selectedAgent, onSelectAgent, restarting, onRestart, onRefresh, m, t }: {
356
+ status: McpStatus;
357
+ agents: AgentInfo[];
358
+ activeSkillName: string;
359
+ connectedAgents: AgentInfo[];
360
+ detectedAgents: AgentInfo[];
361
+ notFoundAgents: AgentInfo[];
362
+ currentAgent: AgentInfo | null;
363
+ selectedAgent: string;
364
+ onSelectAgent: (key: string) => void;
365
+ restarting: boolean;
366
+ onRestart: () => void;
367
+ onRefresh: () => void;
368
+ m: Record<string, any> | undefined;
369
+ t: McpTabProps['t'];
370
+ }) {
371
+ const { copiedField, handleCopy } = useCopyField();
337
372
 
338
373
  const hasToken = status.authConfigured && !!status.authToken;
339
- const displayToken = revealed ? (status.authToken ?? '') : (status.maskedToken ?? '');
340
- const serverUrl = status.endpoint || `http://127.0.0.1:${status.port}/mcp`;
374
+ const remoteHost = status.localIP || 'localhost';
375
+ const mcpUrl = `http://${remoteHost}:${status.port}/mcp`;
376
+
377
+ const localSnippet = useMemo(
378
+ () => currentAgent ? generateSnippet(currentAgent, status, 'stdio') : null,
379
+ [currentAgent, status]
380
+ );
381
+ const remoteSnippet = useMemo(
382
+ () => currentAgent ? generateSnippet(currentAgent, status, 'http') : null,
383
+ [currentAgent, status]
384
+ );
341
385
 
342
386
  return (
343
- <div className="rounded-xl border border-border bg-card overflow-hidden">
344
- {/* Header */}
345
- <div className="flex items-center gap-2.5 px-4 pt-4 pb-1">
346
- <div className="w-7 h-7 rounded-lg bg-[var(--amber-subtle)] flex items-center justify-center shrink-0">
347
- <Link2 size={14} className="text-[var(--amber)]" />
348
- </div>
349
- <div className="flex-1 min-w-0">
350
- <h3 className="text-sm font-semibold text-foreground">{m?.connectionTitle ?? 'Connection'}</h3>
351
- <p className="text-xs text-muted-foreground">{m?.connectionHint ?? 'Use these credentials to connect AI agents.'}</p>
387
+ <>
388
+ {/* MCP Status */}
389
+ <McpStatusInline status={status} restarting={restarting} onRestart={onRestart} onRefresh={onRefresh} m={m} />
390
+
391
+ {/* Local (stdio) */}
392
+ <div className="space-y-2.5">
393
+ <div className="flex items-center gap-2">
394
+ <Monitor size={12} className={status.running ? 'text-success' : 'text-muted-foreground'} />
395
+ <span className="text-xs font-semibold text-foreground">{m?.localTitle ?? 'Local'}</span>
352
396
  </div>
397
+ <p className="text-xs text-muted-foreground">
398
+ {m?.mcpLocalDesc ?? 'Copy the config snippet and paste into your agent\'s MCP settings.'}
399
+ </p>
400
+ {agents.length > 0 && (
401
+ <div className="space-y-3">
402
+ <CustomSelect
403
+ value={selectedAgent}
404
+ onChange={onSelectAgent}
405
+ options={[
406
+ ...(connectedAgents.length > 0 ? [{ label: m?.connectedGroup ?? 'Connected', options: connectedAgents.map(a => ({ value: a.key, label: a.name })) }] : []),
407
+ ...(detectedAgents.length > 0 ? [{ label: m?.detectedGroup ?? 'Detected', options: detectedAgents.map(a => ({ value: a.key, label: a.name })) }] : []),
408
+ ...(notFoundAgents.length > 0 ? [{ label: m?.notFoundGroup ?? 'Not Installed', options: notFoundAgents.map(a => ({ value: a.key, label: a.name })) }] : []),
409
+ ] as SelectItem[]}
410
+ />
411
+ {currentAgent && localSnippet && (
412
+ <>
413
+ {currentAgent.present && currentAgent.installed && (
414
+ <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-2xs font-medium bg-success/10 text-success">
415
+ <CheckCircle2 size={10} /> {m?.tagConnected ?? 'Connected'}
416
+ </span>
417
+ )}
418
+ <pre className="text-[11px] font-mono bg-muted/50 border border-border rounded-lg p-3 overflow-x-auto whitespace-pre select-all max-h-[200px] overflow-y-auto">
419
+ {localSnippet.displaySnippet}
420
+ </pre>
421
+ <div className="flex items-center gap-3 text-sm">
422
+ <button onClick={async () => { const ok = await copyToClipboard(localSnippet.snippet); if (ok) toast.copy(); }}
423
+ className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0">
424
+ <Copy size={14} /> {m?.copyConfig ?? 'Copy'}
425
+ </button>
426
+ <span className="text-muted-foreground">→</span>
427
+ <span className="font-mono text-muted-foreground truncate text-2xs">{localSnippet.path}</span>
428
+ </div>
429
+ </>
430
+ )}
431
+ </div>
432
+ )}
353
433
  </div>
354
434
 
355
- <div className="p-4 space-y-3">
356
- {/* Auth Token */}
357
- <div className="space-y-1.5">
358
- <label className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground uppercase tracking-wider">
359
- <Shield size={11} />
360
- {m?.tokenLabel ?? 'Auth Token'}
361
- </label>
362
- {hasToken ? (
363
- <div className="flex items-center gap-2">
364
- <div className="flex-1 flex items-center gap-2 px-3 py-2 bg-muted/50 border border-border rounded-lg min-h-[38px]">
365
- <code className="flex-1 text-xs font-mono text-foreground break-all select-all leading-relaxed">
366
- {displayToken}
367
- </code>
368
- </div>
369
- <button
370
- type="button"
371
- onClick={() => setRevealed(v => !v)}
372
- className="shrink-0 p-2 rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1"
373
- title={revealed ? (m?.tokenHide ?? 'Hide') : (m?.tokenShow ?? 'Show')}
374
- >
375
- {revealed ? <EyeOff size={14} /> : <Eye size={14} />}
376
- </button>
377
- <button
378
- type="button"
379
- onClick={() => handleCopy(status.authToken ?? '', 'token')}
380
- className={`shrink-0 p-2 rounded-lg border transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 ${
381
- copiedField === 'token'
382
- ? 'border-success/50 bg-success/10 text-success'
383
- : 'border-border text-muted-foreground hover:text-foreground hover:bg-muted'
384
- }`}
385
- title={m?.tokenCopy ?? 'Copy'}
386
- >
387
- {copiedField === 'token' ? <Check size={14} /> : <Copy size={14} />}
388
- </button>
389
- </div>
390
- ) : (
391
- <div className="px-3 py-2.5 bg-[var(--amber-subtle)] border border-[var(--amber)]/20 rounded-lg">
392
- <p className="text-xs text-[var(--amber-text)]">{m?.tokenNone ?? 'No token set.'}</p>
393
- <p className="text-xs text-muted-foreground mt-1">{m?.tokenNoneAction ?? 'Generate one in Settings \u2192 General \u2192 Security.'}</p>
394
- </div>
395
- )}
396
- </div>
435
+ {/* Detected Agents — install MCP config + Skill locally */}
436
+ {agents.length > 0 && (
437
+ <InlineCollapsible
438
+ icon={<Users size={12} className="text-muted-foreground" />}
439
+ title={m?.detectedAgentsTitle ?? 'Detected Agents'}
440
+ badge={`${connectedAgents.length + detectedAgents.length}/${agents.length}`}
441
+ >
442
+ <AgentInstall agents={agents} t={t} onRefresh={onRefresh} mode="mcp" activeSkillName={activeSkillName} />
443
+ </InlineCollapsible>
444
+ )}
397
445
 
398
- {/* Server URL */}
399
- <div className="space-y-1.5">
400
- <label className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground uppercase tracking-wider">
401
- <Globe size={11} />
402
- {m?.serverUrl ?? 'MCP Server URL'}
403
- </label>
404
- <div className="flex items-center gap-2">
405
- <div className="flex-1 flex items-center px-3 py-2 bg-muted/50 border border-border rounded-lg min-h-[38px]">
406
- <code className="flex-1 text-xs font-mono text-foreground select-all">{serverUrl}</code>
407
- </div>
408
- <button
409
- type="button"
410
- onClick={() => handleCopy(serverUrl, 'url')}
411
- className={`shrink-0 p-2 rounded-lg border transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 ${
412
- copiedField === 'url'
413
- ? 'border-success/50 bg-success/10 text-success'
414
- : 'border-border text-muted-foreground hover:text-foreground hover:bg-muted'
415
- }`}
416
- title={m?.serverUrlCopy ?? 'Copy URL'}
417
- >
418
- {copiedField === 'url' ? <Check size={14} /> : <Copy size={14} />}
419
- </button>
446
+ {/* Remote */}
447
+ <div className="border-t border-border pt-3 space-y-3">
448
+ <div className="flex items-center gap-2">
449
+ <Globe size={12} className="text-muted-foreground" />
450
+ <span className="text-xs font-semibold text-foreground">{m?.remoteTitle ?? 'Remote Access'}</span>
451
+ </div>
452
+ {!hasToken && (
453
+ <p className="flex items-center gap-1.5 text-xs text-[var(--amber-text)]">
454
+ <AlertCircle size={12} /> {m?.noAuthWarning ?? 'Set an Auth Token in Settings → General before enabling remote access.'}
455
+ </p>
456
+ )}
457
+ <div className="space-y-1">
458
+ <span className="text-2xs font-medium text-muted-foreground uppercase tracking-wider">{m?.serverUrl ?? 'MCP Server URL'}</span>
459
+ <div className="flex items-center gap-2 px-2.5 py-1.5 bg-muted/50 border border-border rounded-lg">
460
+ <code className="flex-1 text-xs font-mono text-foreground select-all truncate">{mcpUrl}</code>
461
+ <CopyButton onCopy={() => handleCopy(mcpUrl, 'mcp-url')} copied={copiedField === 'mcp-url'} size="sm" />
420
462
  </div>
421
463
  </div>
464
+ {agents.length > 0 && currentAgent && remoteSnippet && (
465
+ <>
466
+ <pre className="text-[11px] font-mono bg-muted/50 border border-border rounded-lg p-3 overflow-x-auto whitespace-pre select-all max-h-[200px] overflow-y-auto">
467
+ {remoteSnippet.displaySnippet}
468
+ </pre>
469
+ <div className="flex items-center gap-3 text-sm">
470
+ <button onClick={async () => { const ok = await copyToClipboard(remoteSnippet.snippet); if (ok) toast.copy(); }}
471
+ className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0">
472
+ <Copy size={14} /> {m?.copyConfig ?? 'Copy'}
473
+ </button>
474
+ <span className="text-muted-foreground">→</span>
475
+ <span className="font-mono text-muted-foreground truncate text-2xs">{remoteSnippet.path}</span>
476
+ </div>
477
+ </>
478
+ )}
479
+ </div>
480
+ </>
481
+ );
482
+ }
422
483
 
423
- {/* How to connect (collapsible) */}
424
- <button
425
- type="button"
426
- onClick={() => setHowToOpen(v => !v)}
427
- className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors py-1 focus-visible:ring-2 focus-visible:ring-ring rounded"
428
- >
429
- {howToOpen ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
430
- {m?.howToConnect ?? 'How to connect an AI agent'}
431
- </button>
432
- {howToOpen && (
433
- <ol className="ml-1 pl-3 border-l-2 border-border space-y-1.5 text-xs text-muted-foreground list-decimal list-inside">
434
- <li>{m?.howToStep1 ?? 'Open your agent\'s MCP settings'}</li>
435
- <li>{m?.howToStep2 ?? 'Add MCP server with the URL above'}</li>
436
- <li>{m?.howToStep3 ?? 'Set Auth Token as bearer token'}</li>
437
- <li>{m?.howToStep4 ?? 'Save and verify the connection'}</li>
438
- </ol>
484
+ /* ── Inline Collapsible (inside a card) ── */
485
+
486
+ function InlineCollapsible({ icon, title, badge, defaultOpen = false, children }: {
487
+ icon?: React.ReactNode;
488
+ title: string;
489
+ badge?: string;
490
+ defaultOpen?: boolean;
491
+ children: React.ReactNode;
492
+ }) {
493
+ const [open, setOpen] = useState(defaultOpen);
494
+ return (
495
+ <div className="rounded-lg border border-border overflow-hidden">
496
+ <button
497
+ type="button"
498
+ onClick={() => setOpen(v => !v)}
499
+ className="flex items-center gap-2 w-full px-3 py-2 text-left bg-muted/30 hover:bg-muted/60 transition-colors"
500
+ >
501
+ {open ? <ChevronDown size={11} className="text-muted-foreground" /> : <ChevronRight size={11} className="text-muted-foreground" />}
502
+ {icon}
503
+ <span className="text-xs font-medium text-muted-foreground">{title}</span>
504
+ {badge && <span className="text-2xs text-muted-foreground/70 ml-auto">{badge}</span>}
505
+ </button>
506
+ {open && <div className="px-3 py-2.5 border-t border-border">{children}</div>}
507
+ </div>
508
+ );
509
+ }
510
+
511
+ /* ── Step Block ── */
512
+
513
+ function StepBlock({ step, label, children }: { step: string; label: string; children: React.ReactNode }) {
514
+ return (
515
+ <div className="space-y-1.5">
516
+ <div className="flex items-center gap-2">
517
+ <span className="w-4 h-4 rounded-full bg-muted flex items-center justify-center text-2xs font-semibold text-muted-foreground shrink-0">{step}</span>
518
+ <span className="text-2xs font-medium text-muted-foreground uppercase tracking-wider">{label}</span>
519
+ </div>
520
+ <div className="pl-6">{children}</div>
521
+ </div>
522
+ );
523
+ }
524
+
525
+ /* ── MCP Status (compact inline) ── */
526
+
527
+ function McpStatusInline({ status, restarting, onRestart, onRefresh, m }: {
528
+ status: McpStatus; restarting: boolean; onRestart: () => void; onRefresh: () => void; m: Record<string, any> | undefined;
529
+ }) {
530
+ return (
531
+ <div className="flex items-center justify-between px-3 py-2 rounded-lg border border-border bg-muted/30">
532
+ <div className="flex items-center gap-2 text-xs">
533
+ {restarting ? (
534
+ <><Loader2 size={11} className="animate-spin text-[var(--amber)]" /><span className="text-[var(--amber)]">{m?.restarting ?? 'Restarting...'}</span></>
535
+ ) : (
536
+ <>
537
+ <span className={`inline-block w-1.5 h-1.5 rounded-full shrink-0 ${status.running ? 'bg-success' : 'bg-muted-foreground'}`} />
538
+ <span className="font-medium text-foreground">MCP {status.running ? (m?.running ?? 'Running') : (m?.stopped ?? 'Stopped')}</span>
539
+ {status.running && <><span className="text-muted-foreground">·</span><span className="text-muted-foreground">:{status.port}</span><span className="text-muted-foreground">·</span><span className="text-muted-foreground">{status.toolCount} {m?.tools ?? 'tools'}</span></>}
540
+ </>
439
541
  )}
440
542
  </div>
543
+ <div className="flex items-center gap-1.5">
544
+ {!status.running && !restarting && (
545
+ <button onClick={onRestart} className="flex items-center gap-1 px-2 py-1 text-2xs rounded-md font-medium text-[var(--amber-foreground)] bg-[var(--amber)] transition-colors">
546
+ <RotateCcw size={11} /> {m?.restart ?? 'Restart'}
547
+ </button>
548
+ )}
549
+ <button onClick={onRefresh} className="p-1 rounded-md border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors">
550
+ <RefreshCw size={11} />
551
+ </button>
552
+ </div>
441
553
  </div>
442
554
  );
443
555
  }
556
+
557
+ /* ── Code Block ── */
558
+
559
+ function CodeBlock({ label, code, onCopy, copiedField, fieldId, compact, hint }: {
560
+ label?: string; code: string; onCopy: (text: string, field: string) => void; copiedField: string | null; fieldId: string; compact?: boolean; hint?: string;
561
+ }) {
562
+ return (
563
+ <div className={compact ? '' : 'space-y-1'}>
564
+ {label && <span className="text-2xs font-medium text-muted-foreground uppercase tracking-wider">{label}</span>}
565
+ <div className={`flex items-center gap-2 ${compact ? 'px-2.5 py-1.5' : 'px-3 py-2'} bg-muted/50 border border-border rounded-lg`}>
566
+ <code className="flex-1 text-xs font-mono text-foreground select-all truncate">{code}</code>
567
+ {hint && <span className="text-2xs text-muted-foreground/60 shrink-0 hidden sm:inline">{hint}</span>}
568
+ <CopyButton onCopy={() => onCopy(code, fieldId)} copied={copiedField === fieldId} size="sm" />
569
+ </div>
570
+ </div>
571
+ );
572
+ }
573
+
574
+ /* ── Copy Button ── */
575
+
576
+ function CopyButton({ onCopy, copied, title, size }: { onCopy: () => void; copied: boolean; title?: string; size?: 'sm' | 'md' }) {
577
+ const sz = size === 'sm' ? 11 : 14;
578
+ const pad = size === 'sm' ? 'p-1' : 'p-2';
579
+ return (
580
+ <button type="button" onClick={onCopy} title={title ?? 'Copy'}
581
+ className={`shrink-0 ${pad} rounded-lg border transition-colors focus-visible:ring-2 focus-visible:ring-ring ${
582
+ copied ? 'border-success/50 bg-success/10 text-success' : 'border-border text-muted-foreground hover:text-foreground hover:bg-muted'
583
+ }`}>
584
+ {copied ? <Check size={sz} /> : <Copy size={sz} />}
585
+ </button>
586
+ );
587
+ }