@geminilight/mindos 0.6.61 → 0.6.65

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 (313) hide show
  1. package/_standalone/.antigravity/mcp_config.json +14 -0
  2. package/_standalone/.mindos-build-version +1 -1
  3. package/_standalone/.next/BUILD_ID +1 -1
  4. package/_standalone/.next/app-path-routes-manifest.json +23 -23
  5. package/_standalone/.next/build-manifest.json +2 -2
  6. package/_standalone/.next/cache/.previewinfo +1 -1
  7. package/_standalone/.next/cache/.rscinfo +1 -1
  8. package/_standalone/.next/cache/config.json +3 -3
  9. package/_standalone/.next/prerender-manifest.json +3 -3
  10. package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
  11. package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/_standalone/.next/server/app/_global-error.html +2 -2
  13. package/_standalone/.next/server/app/_global-error.rsc +1 -1
  14. package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  15. package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  16. package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  17. package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  18. package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  19. package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  20. package/_standalone/.next/server/app/_not-found/page.js +1 -1
  21. package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  22. package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  23. package/_standalone/.next/server/app/agents/[agentKey]/page.js +1 -1
  24. package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
  25. package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
  26. package/_standalone/.next/server/app/agents/page.js +1 -1
  27. package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
  28. package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  29. package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
  30. package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
  31. package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
  32. package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
  33. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  34. package/_standalone/.next/server/app/api/acp/detect/route.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.js +1 -1
  38. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  39. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  40. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  41. package/_standalone/.next/server/app/api/agents/copy-skill/route.js.nft.json +1 -1
  42. package/_standalone/.next/server/app/api/agents/copy-skill/route_client-reference-manifest.js +1 -1
  43. package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
  44. package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
  45. package/_standalone/.next/server/app/api/ask/route.js +53 -47
  46. package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
  47. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  48. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  49. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  50. package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
  51. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  52. package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
  53. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  54. package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
  55. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  56. package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
  57. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  59. package/_standalone/.next/server/app/api/file/import/route.js +1 -1
  60. package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
  61. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  62. package/_standalone/.next/server/app/api/file/raw/route.js.nft.json +1 -1
  63. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
  65. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  66. package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  67. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  68. package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  69. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  70. package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
  71. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  72. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  73. package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -1
  74. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  75. package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
  76. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  77. package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
  78. package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
  79. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  81. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  82. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  83. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
  86. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  87. package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
  88. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  89. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  90. package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  91. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  92. package/_standalone/.next/server/app/api/settings/list-models/route.js +1 -1
  93. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  94. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  95. package/_standalone/.next/server/app/api/settings/route.js +1 -1
  96. package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  97. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  98. package/_standalone/.next/server/app/api/settings/test-key/route.js +1 -1
  99. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  100. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  101. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  102. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  103. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  104. package/_standalone/.next/server/app/api/setup/route.js +1 -1
  105. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  106. package/_standalone/.next/server/app/api/skills/route.js +1 -1
  107. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  108. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  109. package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
  110. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  111. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  112. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  113. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  114. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  115. package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
  116. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  117. package/_standalone/.next/server/app/changes/page.js +1 -1
  118. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  119. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  120. package/_standalone/.next/server/app/echo/[segment]/page.js +2 -2
  121. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  122. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  123. package/_standalone/.next/server/app/echo/page.js +1 -1
  124. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  125. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  126. package/_standalone/.next/server/app/explore/page.js +1 -1
  127. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  128. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  129. package/_standalone/.next/server/app/help/page.js +1 -1
  130. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  131. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  132. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  133. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  134. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  135. package/_standalone/.next/server/app/login/page.js +1 -1
  136. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  137. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  138. package/_standalone/.next/server/app/page.js +1 -1
  139. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  140. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  141. package/_standalone/.next/server/app/setup/page.js +2 -2
  142. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  143. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  144. package/_standalone/.next/server/app/trash/page.js +3 -3
  145. package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
  146. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  147. package/_standalone/.next/server/app/view/[...path]/page.js +2 -2
  148. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  149. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  150. package/_standalone/.next/server/app/wiki/page.js +1 -1
  151. package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
  152. package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
  153. package/_standalone/.next/server/app-paths-manifest.json +23 -23
  154. package/_standalone/.next/server/chunks/122.js +222 -0
  155. package/_standalone/.next/server/chunks/1550.js +1 -1
  156. package/_standalone/.next/server/chunks/1750.js +1 -1
  157. package/_standalone/.next/server/chunks/3113.js +52 -0
  158. package/_standalone/.next/server/chunks/6539.js +1 -1
  159. package/_standalone/.next/server/chunks/8388.js +3 -3
  160. package/_standalone/.next/server/chunks/953.js +3 -3
  161. package/_standalone/.next/server/pages/500.html +2 -2
  162. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  163. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  164. package/_standalone/.next/static/chunks/1001-99da82ec8d8c136f.js +1 -0
  165. package/_standalone/.next/static/chunks/1088-77544af0a50cb7a4.js +1 -0
  166. package/_standalone/.next/static/chunks/1467-87dde7eed498806f.js +1 -0
  167. package/_standalone/.next/static/chunks/5149-4d828886dda479fa.js +1 -0
  168. package/_standalone/.next/static/chunks/5581-c671163a2fe1b312.js +29 -0
  169. package/_standalone/.next/static/chunks/{7266-bb7be1128eccd48e.js → 5718-3837c3210a0e175f.js} +2 -2
  170. package/_standalone/.next/static/chunks/6636-53238eff89503f03.js +6 -0
  171. package/_standalone/.next/static/chunks/6757-1c1a89720fdda8f0.js +1 -0
  172. package/_standalone/.next/static/chunks/7129-20e9d2463a9da646.js +1 -0
  173. package/_standalone/.next/static/chunks/7294-cac25d97869afadc.js +1 -0
  174. package/_standalone/.next/static/chunks/8225-21e5cebc3731ddf0.js +1 -0
  175. package/_standalone/.next/static/chunks/8520-b51810e66293ceb8.js +22 -0
  176. package/_standalone/.next/static/chunks/9207-dc9c31b351a2ed78.js +1 -0
  177. package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-2f5cf97e03dc1cc9.js +1 -0
  178. package/_standalone/.next/static/chunks/app/agents/page-50eac58d511dcc6e.js +1 -0
  179. package/_standalone/.next/static/chunks/app/echo/[segment]/page-2a00f4686adf3885.js +11 -0
  180. package/_standalone/.next/static/chunks/app/layout-2cb7a6602d2e5d5f.js +168 -0
  181. package/_standalone/.next/static/chunks/app/{page-6a1f8d21c12b829e.js → page-5ab911b2226f6ff7.js} +1 -1
  182. package/_standalone/.next/static/chunks/app/setup/page-907b7c57fad2292b.js +1 -0
  183. package/_standalone/.next/static/chunks/app/trash/page-11a511b065ea84c2.js +1 -0
  184. package/_standalone/.next/static/chunks/app/view/[...path]/page-26e47dd4c533a58c.js +12 -0
  185. package/_standalone/.next/static/chunks/app/wiki/page-dce495b9048022fb.js +1 -0
  186. package/_standalone/.next/static/css/67e7918f5ed7d147.css +1 -0
  187. package/_standalone/.next/trace +65 -65
  188. package/_standalone/__tests__/acp/registry.test.ts +30 -20
  189. package/_standalone/__tests__/api/ask-attachments.test.ts +194 -0
  190. package/_standalone/__tests__/api/mcp-install.test.ts +49 -2
  191. package/_standalone/__tests__/api/settings.test.ts +16 -12
  192. package/_standalone/__tests__/api/setup.test.ts +11 -9
  193. package/_standalone/__tests__/api/test-key.test.ts +0 -10
  194. package/_standalone/__tests__/components/UpdateToast.test.ts +344 -0
  195. package/_standalone/__tests__/core/context.test.ts +48 -426
  196. package/_standalone/__tests__/lib/pi-skills.test.ts +4 -4
  197. package/_standalone/__tests__/lib/settings-ai-client.test.ts +32 -12
  198. package/_standalone/__tests__/setup.ts +5 -5
  199. package/_standalone/app/globals.css +4 -4
  200. package/_standalone/components/ActivityBar.tsx +17 -6
  201. package/_standalone/components/Panel.tsx +24 -6
  202. package/_standalone/components/SidebarLayout.tsx +36 -8
  203. package/_standalone/components/agents/AgentsMcpSection.tsx +2 -2
  204. package/_standalone/components/agents/AgentsOverviewSection.tsx +5 -1
  205. package/_standalone/components/agents/AgentsPanelA2aTab.tsx +173 -113
  206. package/_standalone/components/agents/AgentsSkillsSection.tsx +2 -2
  207. package/_standalone/components/ask/AskContent.tsx +83 -44
  208. package/_standalone/components/ask/AskHeader.tsx +8 -1
  209. package/_standalone/components/ask/MessageList.tsx +37 -3
  210. package/_standalone/components/ask/ProviderModelCapsule.tsx +444 -174
  211. package/_standalone/components/home/InboxSection.tsx +25 -25
  212. package/_standalone/components/settings/AiTab.tsx +353 -298
  213. package/_standalone/components/settings/CustomProviderFields.tsx +121 -0
  214. package/_standalone/components/settings/CustomProvidersCard.tsx +154 -0
  215. package/_standalone/components/settings/KnowledgeTab.tsx +6 -20
  216. package/_standalone/components/settings/McpAgentInstall.tsx +7 -2
  217. package/_standalone/components/settings/Primitives.tsx +48 -104
  218. package/_standalone/components/settings/ProviderModal.tsx +87 -0
  219. package/_standalone/components/settings/SettingsContent.tsx +2 -5
  220. package/_standalone/components/settings/TestButton.tsx +64 -0
  221. package/_standalone/components/settings/types.ts +3 -9
  222. package/_standalone/components/settings/useCustomProviderForm.ts +132 -0
  223. package/_standalone/components/setup/StepAI.tsx +12 -5
  224. package/_standalone/components/shared/ModelInput.tsx +220 -0
  225. package/_standalone/components/shared/ProviderSelect.tsx +126 -36
  226. package/_standalone/hooks/useAskChat.ts +100 -13
  227. package/_standalone/hooks/useAskPanel.ts +17 -1
  228. package/_standalone/lib/settings-ai-client.ts +17 -8
  229. package/_standalone/tsconfig.tsbuildinfo +1 -1
  230. package/app/.antigravity/mcp_config.json +14 -0
  231. package/app/app/api/ask/route.ts +154 -45
  232. package/app/app/api/mcp/agents/route.ts +3 -3
  233. package/app/app/api/settings/list-models/route.ts +36 -9
  234. package/app/app/api/settings/route.ts +14 -42
  235. package/app/app/api/settings/test-key/route.ts +78 -2
  236. package/app/app/api/setup/route.ts +36 -18
  237. package/app/app/api/skills/route.ts +1 -1
  238. package/app/app/globals.css +4 -4
  239. package/app/app/layout.tsx +5 -3
  240. package/app/app/view/[...path]/page.tsx +5 -0
  241. package/app/components/ActivityBar.tsx +17 -6
  242. package/app/components/HomeContent.tsx +11 -0
  243. package/app/components/InboxView.tsx +656 -0
  244. package/app/components/Panel.tsx +24 -6
  245. package/app/components/SidebarLayout.tsx +36 -8
  246. package/app/components/UpdateToast.tsx +255 -0
  247. package/app/components/agents/AgentDetailContent.tsx +8 -8
  248. package/app/components/agents/AgentsMcpSection.tsx +2 -2
  249. package/app/components/agents/AgentsOverviewSection.tsx +5 -1
  250. package/app/components/agents/AgentsPanelA2aTab.tsx +173 -113
  251. package/app/components/agents/AgentsSkillsSection.tsx +2 -2
  252. package/app/components/ask/AskContent.tsx +83 -44
  253. package/app/components/ask/AskHeader.tsx +8 -1
  254. package/app/components/ask/MessageList.tsx +37 -3
  255. package/app/components/ask/ProviderModelCapsule.tsx +444 -174
  256. package/app/components/home/InboxSection.tsx +25 -25
  257. package/app/components/settings/AiTab.tsx +353 -298
  258. package/app/components/settings/CustomProviderFields.tsx +121 -0
  259. package/app/components/settings/CustomProvidersCard.tsx +154 -0
  260. package/app/components/settings/KnowledgeTab.tsx +6 -20
  261. package/app/components/settings/McpAgentInstall.tsx +7 -2
  262. package/app/components/settings/Primitives.tsx +48 -104
  263. package/app/components/settings/ProviderModal.tsx +87 -0
  264. package/app/components/settings/SettingsContent.tsx +2 -5
  265. package/app/components/settings/TestButton.tsx +64 -0
  266. package/app/components/settings/types.ts +3 -9
  267. package/app/components/settings/useCustomProviderForm.ts +132 -0
  268. package/app/components/setup/StepAI.tsx +12 -5
  269. package/app/components/shared/ModelInput.tsx +220 -0
  270. package/app/components/shared/ProviderSelect.tsx +126 -36
  271. package/app/hooks/useAskChat.ts +100 -13
  272. package/app/hooks/useAskPanel.ts +17 -1
  273. package/app/lib/acp/registry.ts +92 -10
  274. package/app/lib/agent/context.ts +65 -0
  275. package/app/lib/agent/providers.ts +25 -0
  276. package/app/lib/agent/tools.ts +1 -1
  277. package/app/lib/custom-endpoints.ts +160 -0
  278. package/app/lib/fs.ts +8 -1
  279. package/app/lib/i18n/modules/ai-chat.ts +6 -0
  280. package/app/lib/i18n/modules/knowledge.ts +16 -0
  281. package/app/lib/i18n/modules/onboarding.ts +4 -0
  282. package/app/lib/i18n/modules/settings.ts +88 -2
  283. package/app/lib/mcp-agents.ts +11 -0
  284. package/app/lib/pi-integration/skills.ts +16 -4
  285. package/app/lib/settings-ai-client.ts +17 -8
  286. package/app/lib/settings.ts +68 -72
  287. package/app/lib/types.ts +4 -0
  288. package/bin/lib/mcp-agents.js +11 -0
  289. package/bin/lib/mcp-install.js +71 -7
  290. package/package.json +1 -1
  291. package/_standalone/.next/server/chunks/530.js +0 -218
  292. package/_standalone/.next/server/chunks/8955.js +0 -52
  293. package/_standalone/.next/static/chunks/1369-7d0ac5d1564eed1e.js +0 -1
  294. package/_standalone/.next/static/chunks/3427-2e61a5df1f5e55fb.js +0 -1
  295. package/_standalone/.next/static/chunks/5581-0c700c20718bd916.js +0 -29
  296. package/_standalone/.next/static/chunks/6297-085daa21037d5f81.js +0 -1
  297. package/_standalone/.next/static/chunks/6636-9bbc90fb3b8731fe.js +0 -6
  298. package/_standalone/.next/static/chunks/7637-904b0a381dc3ec02.js +0 -1
  299. package/_standalone/.next/static/chunks/8520-76d1b05072178b43.js +0 -22
  300. package/_standalone/.next/static/chunks/8658-16ff58b75ae37fbb.js +0 -1
  301. package/_standalone/.next/static/chunks/9905-a19d379cb225246e.js +0 -1
  302. package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-0ea3571c8fbae823.js +0 -1
  303. package/_standalone/.next/static/chunks/app/agents/page-66858acbcd1d4bf8.js +0 -1
  304. package/_standalone/.next/static/chunks/app/echo/[segment]/page-bf5c290fa3ccff09.js +0 -11
  305. package/_standalone/.next/static/chunks/app/layout-a5d5925b47e87cc3.js +0 -164
  306. package/_standalone/.next/static/chunks/app/setup/page-821714e7477be46c.js +0 -1
  307. package/_standalone/.next/static/chunks/app/trash/page-40bc7316806acd62.js +0 -1
  308. package/_standalone/.next/static/chunks/app/view/[...path]/page-6fbb14b8f322d0f0.js +0 -12
  309. package/_standalone/.next/static/chunks/app/wiki/page-ba36eccf4fe62cfe.js +0 -1
  310. package/_standalone/.next/static/css/b57c4eb3cc88308b.css +0 -1
  311. package/_standalone/lib/agent/context.ts +0 -403
  312. /package/_standalone/.next/static/{5GmVArEG8OX03azKICsGq → eIlwbGas1iRGonlPyEwj7}/_buildManifest.js +0 -0
  313. /package/_standalone/.next/static/{5GmVArEG8OX03azKICsGq → eIlwbGas1iRGonlPyEwj7}/_ssgManifest.js +0 -0
@@ -30,6 +30,9 @@ export interface ProviderPreset {
30
30
  id: ProviderId;
31
31
  name: string;
32
32
  nameZh: string;
33
+ shortLabel: string; // 3-8 char label for capsule display (e.g., 'Claude', 'GPT', 'GLM-CN')
34
+ description?: string; // Helper text for settings (e.g., "China region version")
35
+ descriptionZh?: string; // Chinese helper text
33
36
  defaultModel: string;
34
37
  /** If ProviderId differs from pi-ai's KnownProvider (e.g. deepseek → openai) */
35
38
  piProviderOverride?: KnownProvider;
@@ -49,6 +52,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
49
52
  id: 'anthropic',
50
53
  name: 'Anthropic',
51
54
  nameZh: 'Anthropic',
55
+ shortLabel: 'Anthropic',
52
56
  defaultModel: 'claude-sonnet-4-6',
53
57
  supportsBaseUrl: true,
54
58
  supportsThinking: true,
@@ -60,6 +64,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
60
64
  id: 'openai',
61
65
  name: 'OpenAI',
62
66
  nameZh: 'OpenAI',
67
+ shortLabel: 'OpenAI',
63
68
  defaultModel: 'gpt-5.4',
64
69
  supportsBaseUrl: true,
65
70
  supportsThinking: true,
@@ -71,6 +76,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
71
76
  id: 'google',
72
77
  name: 'Google Gemini',
73
78
  nameZh: 'Google Gemini',
79
+ shortLabel: 'Gemini',
74
80
  defaultModel: 'gemini-2.5-flash',
75
81
  supportsBaseUrl: false,
76
82
  supportsThinking: true,
@@ -82,6 +88,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
82
88
  id: 'groq',
83
89
  name: 'Groq',
84
90
  nameZh: 'Groq',
91
+ shortLabel: 'Groq',
85
92
  defaultModel: 'llama-3.3-70b-versatile',
86
93
  supportsBaseUrl: false,
87
94
  supportsThinking: false,
@@ -93,6 +100,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
93
100
  id: 'xai',
94
101
  name: 'xAI (Grok)',
95
102
  nameZh: 'xAI (Grok)',
103
+ shortLabel: 'xAI',
96
104
  defaultModel: 'grok-3',
97
105
  supportsBaseUrl: false,
98
106
  supportsThinking: false,
@@ -103,6 +111,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
103
111
  id: 'openrouter',
104
112
  name: 'OpenRouter',
105
113
  nameZh: 'OpenRouter',
114
+ shortLabel: 'OpenRouter',
106
115
  defaultModel: 'anthropic/claude-sonnet-4',
107
116
  supportsBaseUrl: false,
108
117
  supportsThinking: false,
@@ -113,6 +122,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
113
122
  id: 'mistral',
114
123
  name: 'Mistral',
115
124
  nameZh: 'Mistral',
125
+ shortLabel: 'Mistral',
116
126
  defaultModel: 'mistral-large-latest',
117
127
  supportsBaseUrl: false,
118
128
  supportsThinking: false,
@@ -123,6 +133,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
123
133
  id: 'deepseek',
124
134
  name: 'DeepSeek',
125
135
  nameZh: 'DeepSeek',
136
+ shortLabel: 'DeepSeek',
126
137
  defaultModel: 'deepseek-chat',
127
138
  piProviderOverride: 'openai' as KnownProvider,
128
139
  fixedBaseUrl: 'https://api.deepseek.com/v1',
@@ -136,6 +147,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
136
147
  id: 'zai',
137
148
  name: 'ZhipuAI (GLM)',
138
149
  nameZh: '智谱 AI (GLM 国际版)',
150
+ shortLabel: '智谱GLM',
139
151
  defaultModel: 'glm-4-plus',
140
152
  supportsBaseUrl: false,
141
153
  supportsThinking: true,
@@ -146,6 +158,9 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
146
158
  id: 'zai-cn',
147
159
  name: 'ZhipuAI (GLM China)',
148
160
  nameZh: '智谱 AI (GLM 国内版)',
161
+ shortLabel: '智谱GLM-CN',
162
+ description: 'China region version',
163
+ descriptionZh: '中国区版本',
149
164
  defaultModel: 'glm-4-plus',
150
165
  piProviderOverride: 'zai' as KnownProvider,
151
166
  fixedBaseUrl: 'https://open.bigmodel.cn/api/coding/paas/v4',
@@ -159,6 +174,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
159
174
  id: 'kimi-coding',
160
175
  name: 'Kimi Coding',
161
176
  nameZh: 'Kimi Coding (月之暗面)',
177
+ shortLabel: 'Kimi Coding',
162
178
  defaultModel: 'kimi-k2-thinking',
163
179
  supportsBaseUrl: false,
164
180
  supportsThinking: true,
@@ -169,6 +185,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
169
185
  id: 'cerebras',
170
186
  name: 'Cerebras',
171
187
  nameZh: 'Cerebras',
188
+ shortLabel: 'Cerebras',
172
189
  defaultModel: 'llama-4-scout-17b-16e',
173
190
  supportsBaseUrl: false,
174
191
  supportsThinking: false,
@@ -179,6 +196,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
179
196
  id: 'minimax',
180
197
  name: 'MiniMax',
181
198
  nameZh: 'MiniMax (国际版)',
199
+ shortLabel: 'MiniMax',
182
200
  defaultModel: 'MiniMax-M2.5',
183
201
  supportsBaseUrl: false,
184
202
  supportsThinking: true,
@@ -189,6 +207,9 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
189
207
  id: 'minimax-cn',
190
208
  name: 'MiniMax (China)',
191
209
  nameZh: 'MiniMax (国内版)',
210
+ shortLabel: 'MiniMax-CN',
211
+ description: 'China region version',
212
+ descriptionZh: '中国区版本',
192
213
  defaultModel: 'MiniMax-M2.5',
193
214
  supportsBaseUrl: false,
194
215
  supportsThinking: true,
@@ -199,6 +220,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
199
220
  id: 'huggingface',
200
221
  name: 'Hugging Face',
201
222
  nameZh: 'Hugging Face',
223
+ shortLabel: 'HuggingFace',
202
224
  defaultModel: 'Qwen/Qwen3-235B-A22B-Thinking-2507',
203
225
  supportsBaseUrl: false,
204
226
  supportsThinking: true,
@@ -209,6 +231,9 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
209
231
  id: 'ollama',
210
232
  name: 'Ollama',
211
233
  nameZh: 'Ollama (本地)',
234
+ shortLabel: 'Ollama',
235
+ description: 'Local server (requires setup)',
236
+ descriptionZh: '本地服务器 (需要本地部署)',
212
237
  defaultModel: 'llama3.2',
213
238
  piProviderOverride: 'openai' as KnownProvider,
214
239
  fixedBaseUrl: 'http://localhost:11434/v1',
@@ -388,7 +388,7 @@ export const knowledgeBaseTools: AgentTool<any>[] = [
388
388
  parameters: ListSkillsParams,
389
389
  execute: safeExecute(async () => {
390
390
  const projectRoot = process.env.MINDOS_PROJECT_ROOT || path.resolve(process.cwd(), '..');
391
- const skills = scanSkillDirs({ projectRoot, mindRoot: getMindRoot() });
391
+ const skills = await scanSkillDirs({ projectRoot, mindRoot: getMindRoot() });
392
392
  if (skills.length === 0) return textResult('No skills found.');
393
393
  return textResult(skills.map((skill) => `- **${skill.name}** [${skill.origin}]${skill.enabled ? '' : ' (disabled)'} — ${skill.description || 'No description'}\n Path: ${skill.path}`).join('\n'));
394
394
  }),
@@ -0,0 +1,160 @@
1
+ import { type ProviderId, isProviderId, PROVIDER_PRESETS } from './agent/providers';
2
+
3
+ // ─── Unified Provider ───────────────────────────────────────────
4
+
5
+ /**
6
+ * A provider configuration. All providers are equal — each has a
7
+ * user-visible name, a protocol (openai/anthropic/google/…), and
8
+ * connection details (apiKey, model, baseUrl).
9
+ */
10
+ export interface Provider {
11
+ id: string; // "p_" + 8 random alphanumeric chars
12
+ name: string; // User-visible display name
13
+ protocol: ProviderId; // Which API protocol to use
14
+ apiKey: string;
15
+ model: string;
16
+ baseUrl: string;
17
+ }
18
+
19
+ const P_PREFIX = 'p_';
20
+
21
+ /** Generate a unique provider ID */
22
+ export function generateProviderId(): string {
23
+ return P_PREFIX + Math.random().toString(36).slice(2, 10);
24
+ }
25
+
26
+ /** Check if a string is a provider ID (p_*) */
27
+ export function isProviderEntryId(id: string): boolean {
28
+ return typeof id === 'string' && id.startsWith(P_PREFIX);
29
+ }
30
+
31
+ /** Validate that an unknown value is a valid Provider */
32
+ export function isValidProvider(e: unknown): e is Provider {
33
+ if (!e || typeof e !== 'object') return false;
34
+ const obj = e as Record<string, unknown>;
35
+ return (
36
+ typeof obj.id === 'string' && obj.id.startsWith(P_PREFIX) &&
37
+ typeof obj.name === 'string' && obj.name.trim().length > 0 &&
38
+ typeof obj.protocol === 'string' && isProviderId(obj.protocol) &&
39
+ typeof obj.apiKey === 'string' &&
40
+ typeof obj.model === 'string' &&
41
+ typeof obj.baseUrl === 'string'
42
+ );
43
+ }
44
+
45
+ /** Parse an array of providers from unknown config data, filtering invalid entries */
46
+ export function parseProviders(raw: unknown): Provider[] {
47
+ if (!Array.isArray(raw)) return [];
48
+ return raw.filter(isValidProvider);
49
+ }
50
+
51
+ /** Find a provider by ID from a list */
52
+ export function findProvider(providers: Provider[], id: string): Provider | undefined {
53
+ return providers.find(p => p.id === id);
54
+ }
55
+
56
+ // ─── Migration from old format ──────────────────────────────────
57
+
58
+ interface OldProviderConfig { apiKey?: string; model?: string; baseUrl?: string }
59
+ interface OldCustomProvider {
60
+ id: string; name: string; baseProviderId: string;
61
+ apiKey: string; model: string; baseUrl: string;
62
+ }
63
+
64
+ /**
65
+ * Detect whether config.json uses the old format (ai.providers is a dict)
66
+ * and migrate to the new format (ai.providers is an array).
67
+ *
68
+ * Returns null if already in new format (no migration needed).
69
+ */
70
+ export function migrateProviders(parsed: Record<string, unknown>): {
71
+ activeProvider: string;
72
+ providers: Provider[];
73
+ } | null {
74
+ const ai = parsed.ai as Record<string, unknown> | undefined;
75
+ if (!ai) return null;
76
+
77
+ // Already new format: providers is an array
78
+ if (Array.isArray(ai.providers)) return null;
79
+
80
+ // Old format: providers is a dict (or missing)
81
+ const oldProviders = (ai.providers ?? {}) as Record<string, OldProviderConfig>;
82
+ const oldActive = (ai.provider ?? 'openai') as string;
83
+ const oldCustom = (parsed.customProviders ?? []) as OldCustomProvider[];
84
+
85
+ const newProviders: Provider[] = [];
86
+ let activeId = '';
87
+
88
+ // 1. Migrate built-in providers (only those with actual content)
89
+ for (const [protocolId, cfg] of Object.entries(oldProviders)) {
90
+ if (!cfg || !isProviderId(protocolId)) continue;
91
+ // Skip empty entries (no key, no model, no baseUrl)
92
+ if (!cfg.apiKey && !cfg.model && !cfg.baseUrl) continue;
93
+
94
+ const preset = PROVIDER_PRESETS[protocolId];
95
+ const id = generateProviderId();
96
+ newProviders.push({
97
+ id,
98
+ name: preset?.name ?? protocolId,
99
+ protocol: protocolId as ProviderId,
100
+ apiKey: cfg.apiKey ?? '',
101
+ model: cfg.model ?? '',
102
+ baseUrl: cfg.baseUrl ?? '',
103
+ });
104
+
105
+ if (protocolId === oldActive) activeId = id;
106
+ }
107
+
108
+ // 2. Migrate custom providers
109
+ for (const cp of oldCustom) {
110
+ if (!cp.name || !cp.baseProviderId) continue;
111
+ const id = generateProviderId();
112
+ newProviders.push({
113
+ id,
114
+ name: cp.name,
115
+ protocol: (isProviderId(cp.baseProviderId) ? cp.baseProviderId : 'openai') as ProviderId,
116
+ apiKey: cp.apiKey ?? '',
117
+ model: cp.model ?? '',
118
+ baseUrl: cp.baseUrl ?? '',
119
+ });
120
+
121
+ // If old active was a custom provider ID, map it
122
+ if (cp.id === oldActive) activeId = id;
123
+ }
124
+
125
+ // 3. If no active provider was mapped, pick the first one or create a default
126
+ if (!activeId) {
127
+ if (newProviders.length > 0) {
128
+ activeId = newProviders[0].id;
129
+ } else {
130
+ // No providers at all — create default OpenAI entry
131
+ const id = generateProviderId();
132
+ newProviders.push({
133
+ id,
134
+ name: 'OpenAI',
135
+ protocol: 'openai',
136
+ apiKey: '',
137
+ model: PROVIDER_PRESETS.openai?.defaultModel ?? '',
138
+ baseUrl: '',
139
+ });
140
+ activeId = id;
141
+ }
142
+ }
143
+
144
+ return { activeProvider: activeId, providers: newProviders };
145
+ }
146
+
147
+ // ─── Backward compat re-exports (to minimize churn during migration) ──
148
+
149
+ /** @deprecated Use Provider instead */
150
+ export type CustomProvider = Provider;
151
+ /** @deprecated Use generateProviderId instead */
152
+ export const generateCustomProviderId = generateProviderId;
153
+ /** @deprecated Use isProviderEntryId instead */
154
+ export function isCustomProviderId(id: string): boolean {
155
+ return isProviderEntryId(id) || (typeof id === 'string' && id.startsWith('cp_'));
156
+ }
157
+ /** @deprecated Use parseProviders instead */
158
+ export const parseCustomProviders = parseProviders;
159
+ /** @deprecated Use findProvider instead */
160
+ export const findCustomProvider = findProvider;
package/app/lib/fs.ts CHANGED
@@ -94,7 +94,13 @@ function sameFileList(a: string[], b: string[]): boolean {
94
94
  /** Monotonically increasing counter — bumped on every file mutation so the
95
95
  * client can cheaply detect changes without rebuilding the full tree. */
96
96
  export function getTreeVersion(): number {
97
- if (_cache && !isCacheValid()) {
97
+ if (!_cache) {
98
+ // Cache was invalidated (by watcher or explicit invalidateCache) — rebuild.
99
+ // _treeVersion was already bumped by the invalidator, no need to bump again.
100
+ _cache = buildCache(getMindRoot());
101
+ _searchIndex = null;
102
+ } else if (!isCacheValid()) {
103
+ // Cache expired by TTL — rebuild and check if files actually changed
98
104
  const next = buildCache(getMindRoot());
99
105
  const changed = !sameFileList(_cache.allFiles, next.allFiles);
100
106
  _cache = next;
@@ -202,6 +208,7 @@ export function startFileWatcher(): void {
202
208
  if (_watchDebounce) clearTimeout(_watchDebounce);
203
209
  _watchDebounce = setTimeout(() => {
204
210
  _cache = null; // Invalidate tree cache — next read will rebuild
211
+ _treeVersion++; // Bump version so polling clients detect the change
205
212
  _watchDebounce = null;
206
213
  }, 500);
207
214
  });
@@ -98,6 +98,9 @@ export const aiChatEn = {
98
98
  providerCapsule: 'Switch model provider',
99
99
  providerDefault: 'Default',
100
100
  providerNoKey: 'No configured providers',
101
+ selectModel: 'Select model',
102
+ searchModels: 'Search models...',
103
+ loadingModels: 'Loading models...',
101
104
  },
102
105
  changes: {
103
106
  unreadBanner: (n: number) => `${n} content change${n === 1 ? '' : 's'} unread`,
@@ -299,6 +302,9 @@ export const aiChatZh = {
299
302
  providerCapsule: '切换模型服务商',
300
303
  providerDefault: '默认',
301
304
  providerNoKey: '暂无已配置的服务商',
305
+ selectModel: '选择模型',
306
+ searchModels: '搜索模型...',
307
+ loadingModels: '加载模型中...',
302
308
  },
303
309
  changes: {
304
310
  unreadBanner: (n: number) => `${n} 条内容变更未读`,
@@ -124,6 +124,9 @@ export const knowledgeEn = {
124
124
  copyName: 'Copy Name',
125
125
  fileRemoved: 'File removed from Inbox',
126
126
  fileRemoveFailed: 'Failed to remove file',
127
+ fileCount: (n: number) => `${n} file${n === 1 ? '' : 's'}`,
128
+ viewEmptyGuide: 'Files dropped here are staged for AI-powered organization into your knowledge base.',
129
+ viewOrganizeTip: 'Click AI Organize to sort these files into the right spaces in your knowledge base.',
127
130
  },
128
131
  pulse: {
129
132
  title: 'Your Agents',
@@ -342,6 +345,11 @@ export const knowledgeEn = {
342
345
  back: '← Back',
343
346
  sourceLabel: 'Source',
344
347
  changesCount: (ok: number, total: number) => `${ok}/${total} changes`,
348
+ changesSummary: (n: number) => `→ ${n} ${n === 1 ? 'change' : 'changes'}`,
349
+ nFiles: (n: number) => `${n} file${n === 1 ? '' : 's'}`,
350
+ statusUndone: 'undone',
351
+ statusCreated: 'created',
352
+ statusUpdated: 'updated',
345
353
  recordCount: (n: number) => `${n} record${n !== 1 ? 's' : ''}`,
346
354
  today: 'Today',
347
355
  yesterday: 'Yesterday',
@@ -508,6 +516,9 @@ export const knowledgeZh = {
508
516
  copyName: '复制文件名',
509
517
  fileRemoved: '文件已从暂存台移除',
510
518
  fileRemoveFailed: '移除文件失败',
519
+ fileCount: (n: number) => `${n} 个文件`,
520
+ viewEmptyGuide: '拖入的文件将暂存于此,等待 AI 整理到知识库中。',
521
+ viewOrganizeTip: '点击 AI 整理,将这些文件分类到知识库的合适位置。',
511
522
  },
512
523
  pulse: {
513
524
  title: '你的 Agent',
@@ -726,6 +737,11 @@ export const knowledgeZh = {
726
737
  back: '← 返回',
727
738
  sourceLabel: '来源',
728
739
  changesCount: (ok: number, total: number) => `${ok}/${total} 处变更`,
740
+ changesSummary: (n: number) => `→ ${n} 处变更`,
741
+ nFiles: (n: number) => `${n} 个文件`,
742
+ statusUndone: '已撤销',
743
+ statusCreated: '已创建',
744
+ statusUpdated: '已更新',
729
745
  recordCount: (n: number) => `${n} 条记录`,
730
746
  today: '今天',
731
747
  yesterday: '昨天',
@@ -33,6 +33,8 @@ export const onboardingEn = {
33
33
  apiKey: 'API Key',
34
34
  apiKeyExisting: 'Existing key configured. Leave blank to keep it.',
35
35
  model: 'Model',
36
+ listModels: 'Browse',
37
+ noModelsFound: 'No models found',
36
38
  baseUrl: 'Base URL',
37
39
  baseUrlHint: 'Optional. For proxies or custom API endpoints.',
38
40
  // Step 3
@@ -255,6 +257,8 @@ export const onboardingZh = {
255
257
  apiKey: 'API 密钥',
256
258
  apiKeyExisting: '已配置密钥。留空即保持不变。',
257
259
  model: '模型',
260
+ listModels: '选择模型',
261
+ noModelsFound: '未找到可用模型',
258
262
  baseUrl: '接口地址',
259
263
  baseUrlHint: '可选。用于代理或自定义 API 端点。',
260
264
  // Step 3
@@ -5,7 +5,7 @@ export const settingsEn = {
5
5
  title: 'Settings',
6
6
  tabs: { ai: 'AI', appearance: 'Appearance', knowledge: 'General', sync: 'Sync', mcp: 'Connections', plugins: 'Plugins', shortcuts: 'Shortcuts', monitoring: 'Monitoring', agents: 'Agents', update: 'Update', uninstall: 'Uninstall' },
7
7
  ai: {
8
- provider: 'Provider',
8
+ provider: 'Model Providers',
9
9
  model: 'Model',
10
10
  apiKey: 'API Key',
11
11
  baseUrl: 'Base URL',
@@ -30,6 +30,39 @@ export const settingsEn = {
30
30
  testKeyUnknown: 'Test failed',
31
31
  listModels: 'Browse',
32
32
  noModelsFound: 'No models found',
33
+ resetProvider: 'Reset',
34
+ resetProviderConfirm: 'Click again to confirm',
35
+ },
36
+ customProviders: {
37
+ title: 'Model Providers',
38
+ subtitle: 'Add custom API endpoints with your own names',
39
+ addButton: '+ Add Provider',
40
+ editButton: 'Edit',
41
+ deleteButton: 'Delete',
42
+ testButton: 'Test',
43
+ emptyState: 'No custom providers yet. Add one to use custom API endpoints or proxies.',
44
+ modal: {
45
+ titleAdd: 'Add Model Provider',
46
+ titleEdit: 'Edit Model Provider',
47
+ fieldName: 'Name',
48
+ fieldNameHint: 'e.g., Company GPT-4, Local LLaMA',
49
+ fieldProtocol: 'Protocol',
50
+ fieldProtocolHint: '(Most local servers use OpenAI-compatible)',
51
+ fieldBaseUrl: 'Base URL',
52
+ fieldBaseUrlHint: 'e.g., https://api.company.com/v1 or http://localhost:8080/v1',
53
+ fieldApiKey: 'API Key',
54
+ fieldApiKeyHint: 'Leave empty if not required (e.g., for local servers)',
55
+ fieldModel: 'Model',
56
+ fieldModelHint: 'e.g., gpt-4-turbo, llama3.2',
57
+ buttonCancel: 'Cancel',
58
+ buttonSave: 'Save & Test',
59
+ buttonSaveOnly: 'Save',
60
+ validating: 'Testing connection...',
61
+ success: '✓ Connected',
62
+ error: 'Connection failed',
63
+ },
64
+ deleteConfirm: (name: string) => `Delete "${name}"? This cannot be undone.`,
65
+ deleteConfirmButton: 'Delete',
33
66
  },
34
67
  agent: {
35
68
  title: 'Agent Behavior',
@@ -430,6 +463,16 @@ export const settingsEn = {
430
463
  coreDesktopTooOldHint: 'Please update MindOS Desktop first.',
431
464
  coreHint: 'Core updates only restart services — no app restart needed.',
432
465
  shellTitle: 'MindOS Desktop',
466
+ // Update Toast Notification
467
+ updateToast: {
468
+ titleSingle: (type: string, version: string) => `${type} v${version} available`,
469
+ titleMultiple: 'Updates available',
470
+ desktopLabel: 'Desktop',
471
+ coreLabel: 'Core',
472
+ viewDetails: 'View Details',
473
+ skipVersion: 'Skip Version',
474
+ skipAll: 'Skip All',
475
+ },
433
476
  },
434
477
  uninstall: {
435
478
  title: 'Uninstall MindOS',
@@ -462,7 +505,7 @@ export const settingsZh = {
462
505
  title: '设置',
463
506
  tabs: { ai: 'AI', appearance: '外观', knowledge: '通用', sync: '同步', mcp: '连接', plugins: '插件', shortcuts: '快捷键', monitoring: '监控', agents: '智能体', update: '更新', uninstall: '卸载' },
464
507
  ai: {
465
- provider: '服务商',
508
+ provider: '模型服务商',
466
509
  model: '模型',
467
510
  apiKey: 'API 密钥',
468
511
  baseUrl: '接口地址',
@@ -487,6 +530,39 @@ export const settingsZh = {
487
530
  testKeyUnknown: '测试失败',
488
531
  listModels: '选择模型',
489
532
  noModelsFound: '未找到可用模型',
533
+ resetProvider: '重置',
534
+ resetProviderConfirm: '再次点击确认',
535
+ },
536
+ customProviders: {
537
+ title: 'Model Providers',
538
+ subtitle: '添加自定义 API 端点并为其命名',
539
+ addButton: '+ 添加 Provider',
540
+ editButton: '编辑',
541
+ deleteButton: '删除',
542
+ testButton: '测试',
543
+ emptyState: '还没有自定义 Provider。添加一个来使用自定义 API 端点或代理。',
544
+ modal: {
545
+ titleAdd: '添加 Model Provider',
546
+ titleEdit: '编辑 Model Provider',
547
+ fieldName: '名称',
548
+ fieldNameHint: '例如:公司 GPT-4、本地 LLaMA',
549
+ fieldProtocol: '协议',
550
+ fieldProtocolHint: '(大多数本地服务使用 OpenAI 兼容接口)',
551
+ fieldBaseUrl: '接口地址',
552
+ fieldBaseUrlHint: '例如:https://api.company.com/v1 或 http://localhost:8080/v1',
553
+ fieldApiKey: 'API 密钥',
554
+ fieldApiKeyHint: '本地服务可留空',
555
+ fieldModel: '模型',
556
+ fieldModelHint: '例如:gpt-4-turbo、llama3.2',
557
+ buttonCancel: '取消',
558
+ buttonSave: '保存并测试',
559
+ buttonSaveOnly: '保存',
560
+ validating: '测试连接中...',
561
+ success: '✓ 已连接',
562
+ error: '连接失败',
563
+ },
564
+ deleteConfirm: (name: string) => `删除 "${name}"?此操作不可撤销。`,
565
+ deleteConfirmButton: '删除',
490
566
  },
491
567
  agent: {
492
568
  title: 'Agent 行为',
@@ -887,6 +963,16 @@ export const settingsZh = {
887
963
  coreDesktopTooOldHint: '请先更新 MindOS Desktop。',
888
964
  coreHint: '核心更新只需重启服务,无需重启应用。',
889
965
  shellTitle: 'MindOS Desktop',
966
+ // Update Toast Notification
967
+ updateToast: {
968
+ titleSingle: (type: string, version: string) => `${type} v${version} 可用`,
969
+ titleMultiple: '有可用更新',
970
+ desktopLabel: '桌面版',
971
+ coreLabel: '运行时',
972
+ viewDetails: '查看详情',
973
+ skipVersion: '跳过此版本',
974
+ skipAll: '全部跳过',
975
+ },
890
976
  },
891
977
  uninstall: {
892
978
  title: '卸载 MindOS',
@@ -270,6 +270,16 @@ export const MCP_AGENTS: Record<string, AgentDef> = {
270
270
  preferredTransport: 'stdio',
271
271
  presenceDirs: ['~/.lingma/'],
272
272
  },
273
+ 'copaw': {
274
+ name: 'CoPaw',
275
+ project: null,
276
+ global: '~/.copaw/config.json',
277
+ key: 'mcp',
278
+ globalNestedKey: 'mcp.clients',
279
+ preferredTransport: 'stdio',
280
+ presenceCli: 'copaw',
281
+ presenceDirs: ['~/.copaw/'],
282
+ },
273
283
  };
274
284
 
275
285
  /**
@@ -300,6 +310,7 @@ export const SKILL_AGENT_REGISTRY: Record<string, SkillAgentRegistration> = {
300
310
  'qclaw': { mode: 'unsupported' },
301
311
  'workbuddy': { mode: 'unsupported' },
302
312
  'lingma': { mode: 'unsupported' },
313
+ 'copaw': { mode: 'unsupported' },
303
314
  };
304
315
 
305
316
  export interface SkillWorkspaceProfile {
@@ -83,7 +83,7 @@ export function getPiSkillSearchDirs(projectRoot: string, mindRoot: string) {
83
83
  ];
84
84
  }
85
85
 
86
- export function scanSkillDirs(options: ScanSkillOptions): PiSkillInfo[] {
86
+ export async function scanSkillDirs(options: ScanSkillOptions): Promise<PiSkillInfo[]> {
87
87
  const { projectRoot, mindRoot, disabledSkills = [] } = options;
88
88
  const skills: PiSkillInfo[] = [];
89
89
  const seen = new Set<string>();
@@ -91,12 +91,24 @@ export function scanSkillDirs(options: ScanSkillOptions): PiSkillInfo[] {
91
91
  for (const sourceDef of getPiSkillSearchDirs(projectRoot, mindRoot)) {
92
92
  if (!fs.existsSync(sourceDef.dir)) continue;
93
93
 
94
- for (const entry of fs.readdirSync(sourceDef.dir, { withFileTypes: true })) {
94
+ let entries: fs.Dirent[];
95
+ try {
96
+ entries = await fs.promises.readdir(sourceDef.dir, { withFileTypes: true });
97
+ } catch {
98
+ continue;
99
+ }
100
+
101
+ for (const entry of entries) {
95
102
  if (!entry.isDirectory()) continue;
96
103
  const skillFile = path.join(sourceDef.dir, entry.name, 'SKILL.md');
97
- if (!fs.existsSync(skillFile)) continue;
104
+
105
+ let content: string;
106
+ try {
107
+ content = await fs.promises.readFile(skillFile, 'utf-8');
108
+ } catch {
109
+ continue;
110
+ }
98
111
 
99
- const content = fs.readFileSync(skillFile, 'utf-8');
100
112
  const { name, description } = parseSkillMd(content);
101
113
  const skillName = name || entry.name;
102
114
  if (!skillName || seen.has(skillName)) continue;
@@ -2,26 +2,35 @@
2
2
  * Client-side mirror of "can /api/ask run?" using GET /api/settings payload.
3
3
  * Must stay aligned with server `effectiveAiConfig()` provider + key resolution.
4
4
  */
5
- import { type ProviderId, PROVIDER_PRESETS, isProviderId, getApiKeyEnvVar } from './agent/providers';
5
+ import { PROVIDER_PRESETS, isProviderId, getApiKeyEnvVar } from './agent/providers';
6
+ import { type Provider } from './custom-endpoints';
6
7
 
7
8
  export type SettingsJsonForAi = {
8
9
  ai?: {
9
- provider?: string;
10
- providers?: Partial<Record<string, { apiKey?: string }>>;
10
+ activeProvider?: string;
11
+ providers?: Provider[];
11
12
  };
12
13
  envOverrides?: Partial<Record<string, boolean>>;
13
14
  };
14
15
 
15
16
  export function isAiConfiguredForAsk(data: SettingsJsonForAi): boolean {
16
- const provId = data.ai?.provider;
17
- const provider: ProviderId = (provId && isProviderId(provId)) ? provId : 'anthropic';
17
+ const providers = data.ai?.providers ?? [];
18
+ const activeId = data.ai?.activeProvider;
18
19
  const env = data.envOverrides ?? {};
19
20
 
20
- const k = data.ai?.providers?.[provider]?.apiKey;
21
- if (typeof k === 'string' && k.length > 0) return true;
21
+ const current = activeId ? providers.find(p => p.id === activeId) : providers[0];
22
+ if (!current) return false;
22
23
 
23
- const envVar = getApiKeyEnvVar(provider);
24
+ // Has API key directly
25
+ if (current.apiKey && current.apiKey.length > 0) return true;
26
+
27
+ // Has env var override
28
+ const envVar = isProviderId(current.protocol) ? getApiKeyEnvVar(current.protocol) : undefined;
24
29
  if (envVar && env[envVar]) return true;
25
30
 
31
+ // Has fallback key (e.g. Ollama)
32
+ const preset = isProviderId(current.protocol) ? PROVIDER_PRESETS[current.protocol] : undefined;
33
+ if (preset?.apiKeyFallback) return true;
34
+
26
35
  return false;
27
36
  }