@geminilight/mindos 0.6.59 → 0.6.60

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 (347) 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 +20 -19
  4. package/_standalone/.next/build-manifest.json +2 -2
  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/routes-manifest.json +6 -0
  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_client-reference-manifest.js +1 -1
  35. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  37. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  38. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  39. package/_standalone/.next/server/app/api/agents/copy-skill/route.js +1 -0
  40. package/_standalone/.next/server/app/api/agents/copy-skill/route.js.nft.json +1 -0
  41. package/_standalone/.next/server/app/api/agents/copy-skill/route_client-reference-manifest.js +1 -0
  42. package/_standalone/.next/server/app/api/agents/custom/detect/route.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.js +1 -1
  45. package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
  46. package/_standalone/.next/server/app/api/ask/route.js +17 -6
  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_client-reference-manifest.js +1 -1
  51. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  52. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  54. package/_standalone/.next/server/app/api/extract-pdf/route.js +2 -2
  55. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  56. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  57. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
  61. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  62. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  63. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  65. package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
  66. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  68. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  69. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  70. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  72. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  73. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  74. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  75. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  76. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  77. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  78. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  79. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  81. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  82. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  83. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  86. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  87. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  88. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  89. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  90. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  91. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  92. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  93. package/_standalone/.next/server/app/changes/page.js +2 -2
  94. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  95. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  96. package/_standalone/.next/server/app/echo/[segment]/page.js +1 -1
  97. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  98. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  99. package/_standalone/.next/server/app/echo/page.js +1 -1
  100. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  101. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  102. package/_standalone/.next/server/app/explore/page.js +1 -1
  103. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  104. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  105. package/_standalone/.next/server/app/help/page.js +1 -1
  106. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  107. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  108. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  109. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  110. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  111. package/_standalone/.next/server/app/login/page.js +1 -1
  112. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  113. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  114. package/_standalone/.next/server/app/page.js +1 -1
  115. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  116. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  117. package/_standalone/.next/server/app/setup/page.js +1 -1
  118. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  119. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  120. package/_standalone/.next/server/app/trash/page.js +3 -3
  121. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  122. package/_standalone/.next/server/app/view/[...path]/page.js +2 -2
  123. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  124. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  125. package/_standalone/.next/server/app/wiki/page.js +1 -1
  126. package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
  127. package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
  128. package/_standalone/.next/server/app-paths-manifest.json +20 -19
  129. package/_standalone/.next/server/chunks/1550.js +1 -1
  130. package/_standalone/.next/server/chunks/3484.js +1 -1
  131. package/_standalone/.next/server/chunks/530.js +35 -35
  132. package/_standalone/.next/server/chunks/{8343.js → 9753.js} +2 -2
  133. package/_standalone/.next/server/pages/500.html +2 -2
  134. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  135. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  136. package/_standalone/.next/static/K3wZNf5bj_AFYwtqcRXIf/_buildManifest.js +1 -0
  137. package/_standalone/.next/static/chunks/1369-7d0ac5d1564eed1e.js +1 -0
  138. package/_standalone/.next/static/chunks/{5581-dac72e9f16e5ea29.js → 5581-974dfb26d1d1b38f.js} +2 -2
  139. package/_standalone/.next/static/chunks/7249-b0a9c77b9a84b11c.js +11 -0
  140. package/_standalone/.next/static/chunks/7637-904b0a381dc3ec02.js +1 -0
  141. package/_standalone/.next/static/chunks/8520-76d1b05072178b43.js +22 -0
  142. package/_standalone/.next/static/chunks/9186-ead47513192f658b.js +1 -0
  143. package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/{route-2f4705aa66819b86.js → route-2ceea6eabf25b1f2.js} +1 -1
  144. package/_standalone/.next/static/chunks/app/_global-error/{page-2f4705aa66819b86.js → page-2ceea6eabf25b1f2.js} +1 -1
  145. package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-0ea3571c8fbae823.js +1 -0
  146. package/_standalone/.next/static/chunks/app/agents/{page-b172ea3743adb047.js → page-66858acbcd1d4bf8.js} +1 -1
  147. package/_standalone/.next/static/chunks/app/api/a2a/agents/{route-2f4705aa66819b86.js → route-2ceea6eabf25b1f2.js} +1 -1
  148. package/_standalone/.next/static/chunks/app/api/a2a/delegations/{route-2f4705aa66819b86.js → route-2ceea6eabf25b1f2.js} +1 -1
  149. package/_standalone/.next/static/chunks/app/api/a2a/discover/route-2ceea6eabf25b1f2.js +1 -0
  150. package/_standalone/.next/static/chunks/app/api/a2a/route-2ceea6eabf25b1f2.js +1 -0
  151. package/_standalone/.next/static/chunks/app/api/acp/config/route-2ceea6eabf25b1f2.js +1 -0
  152. package/_standalone/.next/static/chunks/app/api/acp/detect/route-2ceea6eabf25b1f2.js +1 -0
  153. package/_standalone/.next/static/chunks/app/api/acp/install/route-2ceea6eabf25b1f2.js +1 -0
  154. package/_standalone/.next/static/chunks/app/api/acp/registry/route-2ceea6eabf25b1f2.js +1 -0
  155. package/_standalone/.next/static/chunks/app/api/acp/session/route-2ceea6eabf25b1f2.js +1 -0
  156. package/_standalone/.next/static/chunks/app/api/agent-activity/route-2ceea6eabf25b1f2.js +1 -0
  157. package/_standalone/.next/static/chunks/app/api/agents/copy-skill/route-2ceea6eabf25b1f2.js +1 -0
  158. package/_standalone/.next/static/chunks/app/api/agents/custom/detect/route-2ceea6eabf25b1f2.js +1 -0
  159. package/_standalone/.next/static/chunks/app/api/agents/custom/route-2ceea6eabf25b1f2.js +1 -0
  160. package/_standalone/.next/static/chunks/app/api/ask/route-2ceea6eabf25b1f2.js +1 -0
  161. package/_standalone/.next/static/chunks/app/api/ask-sessions/route-2ceea6eabf25b1f2.js +1 -0
  162. package/_standalone/.next/static/chunks/app/api/auth/route-2ceea6eabf25b1f2.js +1 -0
  163. package/_standalone/.next/static/chunks/app/api/backlinks/route-2ceea6eabf25b1f2.js +1 -0
  164. package/_standalone/.next/static/chunks/app/api/bootstrap/route-2ceea6eabf25b1f2.js +1 -0
  165. package/_standalone/.next/static/chunks/app/api/changes/route-2ceea6eabf25b1f2.js +1 -0
  166. package/_standalone/.next/static/chunks/app/api/export/route-2ceea6eabf25b1f2.js +1 -0
  167. package/_standalone/.next/static/chunks/app/api/extract-pdf/route-2ceea6eabf25b1f2.js +1 -0
  168. package/_standalone/.next/static/chunks/app/api/file/import/route-2ceea6eabf25b1f2.js +1 -0
  169. package/_standalone/.next/static/chunks/app/api/file/raw/route-2ceea6eabf25b1f2.js +1 -0
  170. package/_standalone/.next/static/chunks/app/api/file/route-2ceea6eabf25b1f2.js +1 -0
  171. package/_standalone/.next/static/chunks/app/api/files/route-2ceea6eabf25b1f2.js +1 -0
  172. package/_standalone/.next/static/chunks/app/api/git/route-2ceea6eabf25b1f2.js +1 -0
  173. package/_standalone/.next/static/chunks/app/api/graph/route-2ceea6eabf25b1f2.js +1 -0
  174. package/_standalone/.next/static/chunks/app/api/health/route-2ceea6eabf25b1f2.js +1 -0
  175. package/_standalone/.next/static/chunks/app/api/inbox/route-2ceea6eabf25b1f2.js +1 -0
  176. package/_standalone/.next/static/chunks/app/api/init/route-2ceea6eabf25b1f2.js +1 -0
  177. package/_standalone/.next/static/chunks/app/api/mcp/agents/route-2ceea6eabf25b1f2.js +1 -0
  178. package/_standalone/.next/static/chunks/app/api/mcp/install/route-2ceea6eabf25b1f2.js +1 -0
  179. package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-2ceea6eabf25b1f2.js +1 -0
  180. package/_standalone/.next/static/chunks/app/api/mcp/restart/route-2ceea6eabf25b1f2.js +1 -0
  181. package/_standalone/.next/static/chunks/app/api/mcp/status/route-2ceea6eabf25b1f2.js +1 -0
  182. package/_standalone/.next/static/chunks/app/api/mcp/uninstall/route-2ceea6eabf25b1f2.js +1 -0
  183. package/_standalone/.next/static/chunks/app/api/monitoring/route-2ceea6eabf25b1f2.js +1 -0
  184. package/_standalone/.next/static/chunks/app/api/recent-files/route-2ceea6eabf25b1f2.js +1 -0
  185. package/_standalone/.next/static/chunks/app/api/restart/route-2ceea6eabf25b1f2.js +1 -0
  186. package/_standalone/.next/static/chunks/app/api/search/route-2ceea6eabf25b1f2.js +1 -0
  187. package/_standalone/.next/static/chunks/app/api/settings/list-models/route-2ceea6eabf25b1f2.js +1 -0
  188. package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-2ceea6eabf25b1f2.js +1 -0
  189. package/_standalone/.next/static/chunks/app/api/settings/route-2ceea6eabf25b1f2.js +1 -0
  190. package/_standalone/.next/static/chunks/app/api/settings/test-key/route-2ceea6eabf25b1f2.js +1 -0
  191. package/_standalone/.next/static/chunks/app/api/setup/check-path/route-2ceea6eabf25b1f2.js +1 -0
  192. package/_standalone/.next/static/chunks/app/api/setup/check-port/route-2ceea6eabf25b1f2.js +1 -0
  193. package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-2ceea6eabf25b1f2.js +1 -0
  194. package/_standalone/.next/static/chunks/app/api/setup/ls/route-2ceea6eabf25b1f2.js +1 -0
  195. package/_standalone/.next/static/chunks/app/api/setup/route-2ceea6eabf25b1f2.js +1 -0
  196. package/_standalone/.next/static/chunks/app/api/skills/route-2ceea6eabf25b1f2.js +1 -0
  197. package/_standalone/.next/static/chunks/app/api/sync/route-2ceea6eabf25b1f2.js +1 -0
  198. package/_standalone/.next/static/chunks/app/api/tree-version/route-2ceea6eabf25b1f2.js +1 -0
  199. package/_standalone/.next/static/chunks/app/api/uninstall/route-2ceea6eabf25b1f2.js +1 -0
  200. package/_standalone/.next/static/chunks/app/api/update/route-2ceea6eabf25b1f2.js +1 -0
  201. package/_standalone/.next/static/chunks/app/api/update-check/route-2ceea6eabf25b1f2.js +1 -0
  202. package/_standalone/.next/static/chunks/app/api/update-status/route-2ceea6eabf25b1f2.js +1 -0
  203. package/_standalone/.next/static/chunks/app/api/workflows/route-2ceea6eabf25b1f2.js +1 -0
  204. package/_standalone/.next/static/chunks/app/changes/page-dd0b00a7b81f74e2.js +1 -0
  205. package/_standalone/.next/static/chunks/app/echo/[segment]/{page-84b95256f6e38aae.js → page-bf5c290fa3ccff09.js} +1 -1
  206. package/_standalone/.next/static/chunks/app/echo/page-2ceea6eabf25b1f2.js +1 -0
  207. package/_standalone/.next/static/chunks/app/inbox/history/{page-26e71fb6f716a4c4.js → page-3279585360df132c.js} +1 -1
  208. package/_standalone/.next/static/chunks/app/{layout-b89b0d955f39a753.js → layout-6a0169582db11a08.js} +24 -24
  209. package/_standalone/.next/static/chunks/app/loading-2ceea6eabf25b1f2.js +1 -0
  210. package/_standalone/.next/static/chunks/app/{page-a8e6f085f38388bf.js → page-6a1f8d21c12b829e.js} +1 -1
  211. package/_standalone/.next/static/chunks/app/trash/page-ed7ba3b0b50223a6.js +1 -0
  212. package/_standalone/.next/static/chunks/app/view/[...path]/loading-2ceea6eabf25b1f2.js +1 -0
  213. package/_standalone/.next/static/chunks/app/view/[...path]/page-678139779971cfcb.js +12 -0
  214. package/_standalone/.next/static/chunks/app/wiki/page-194ae9af2d461481.js +1 -0
  215. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-2ceea6eabf25b1f2.js +1 -0
  216. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-2ceea6eabf25b1f2.js +1 -0
  217. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-2ceea6eabf25b1f2.js +1 -0
  218. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-2ceea6eabf25b1f2.js +1 -0
  219. package/_standalone/.next/static/css/9c558c42831fae58.css +1 -0
  220. package/_standalone/.next/trace +65 -64
  221. package/_standalone/.next/types/routes.d.ts +2 -1
  222. package/_standalone/.next/types/validator.ts +9 -0
  223. package/_standalone/__tests__/api/mcp-install.test.ts +4 -2
  224. package/_standalone/components/AskFab.tsx +7 -1
  225. package/_standalone/components/FileTree.tsx +83 -1
  226. package/_standalone/components/Panel.tsx +6 -1
  227. package/_standalone/components/agents/AgentsOverviewSection.tsx +13 -11
  228. package/_standalone/components/agents/CustomAgentModal.tsx +72 -18
  229. package/_standalone/components/ask/AskContent.tsx +19 -3
  230. package/_standalone/components/ask/FileChip.tsx +93 -12
  231. package/_standalone/components/changes/ChangesBanner.tsx +1 -1
  232. package/_standalone/components/walkthrough/WalkthroughTooltip.tsx +3 -1
  233. package/_standalone/components/walkthrough/steps.ts +1 -1
  234. package/_standalone/hooks/useAskChat.ts +10 -8
  235. package/_standalone/hooks/useFileUpload.ts +97 -43
  236. package/_standalone/hooks/useImageUpload.ts +1 -1
  237. package/_standalone/lib/inbox-upload.ts +86 -0
  238. package/_standalone/package-lock.json +2 -2
  239. package/_standalone/package.json +1 -1
  240. package/_standalone/scripts/extract-pdf.cjs +110 -3
  241. package/_standalone/tsconfig.tsbuildinfo +1 -1
  242. package/app/app/api/agents/copy-skill/route.ts +110 -0
  243. package/app/app/api/agents/custom/detect/route.ts +16 -1
  244. package/app/app/api/ask/route.ts +7 -1
  245. package/app/app/api/extract-pdf/route.ts +12 -5
  246. package/app/app/api/mcp/agents/route.ts +64 -2
  247. package/app/components/AskFab.tsx +7 -1
  248. package/app/components/FileTree.tsx +83 -1
  249. package/app/components/HomeContent.tsx +14 -6
  250. package/app/components/Panel.tsx +6 -1
  251. package/app/components/agents/AgentDetailContent.tsx +58 -1
  252. package/app/components/agents/AgentsOverviewSection.tsx +13 -11
  253. package/app/components/agents/CustomAgentModal.tsx +72 -18
  254. package/app/components/ask/AskContent.tsx +19 -3
  255. package/app/components/ask/FileChip.tsx +93 -12
  256. package/app/components/changes/ChangesBanner.tsx +1 -1
  257. package/app/components/changes/ChangesContentPage.tsx +368 -168
  258. package/app/components/walkthrough/WalkthroughTooltip.tsx +3 -1
  259. package/app/components/walkthrough/steps.ts +1 -1
  260. package/app/hooks/useAskChat.ts +10 -8
  261. package/app/hooks/useFileUpload.ts +97 -43
  262. package/app/hooks/useImageUpload.ts +1 -1
  263. package/app/lib/agent/prompt.ts +15 -4
  264. package/app/lib/custom-agents.ts +109 -1
  265. package/app/lib/file-ops.ts +58 -0
  266. package/app/lib/i18n/modules/ai-chat.ts +37 -0
  267. package/app/lib/i18n/modules/knowledge.ts +2 -0
  268. package/app/lib/inbox-upload.ts +86 -0
  269. package/app/lib/mcp-agents.ts +21 -1
  270. package/app/lib/types.ts +12 -0
  271. package/app/package.json +1 -1
  272. package/app/scripts/extract-pdf.cjs +110 -3
  273. package/package.json +1 -1
  274. package/_standalone/.next/static/chunks/4237-ffc6e7c15d4007b6.js +0 -1
  275. package/_standalone/.next/static/chunks/6878-e2c5459e1c608f89.js +0 -1
  276. package/_standalone/.next/static/chunks/7249-6cf8f2b78718c59e.js +0 -11
  277. package/_standalone/.next/static/chunks/8520-56ec9ff087c15204.js +0 -22
  278. package/_standalone/.next/static/chunks/9286-5b09baa5200318c2.js +0 -1
  279. package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-35ea6de1af2be3b5.js +0 -1
  280. package/_standalone/.next/static/chunks/app/api/a2a/discover/route-2f4705aa66819b86.js +0 -1
  281. package/_standalone/.next/static/chunks/app/api/a2a/route-2f4705aa66819b86.js +0 -1
  282. package/_standalone/.next/static/chunks/app/api/acp/config/route-2f4705aa66819b86.js +0 -1
  283. package/_standalone/.next/static/chunks/app/api/acp/detect/route-2f4705aa66819b86.js +0 -1
  284. package/_standalone/.next/static/chunks/app/api/acp/install/route-2f4705aa66819b86.js +0 -1
  285. package/_standalone/.next/static/chunks/app/api/acp/registry/route-2f4705aa66819b86.js +0 -1
  286. package/_standalone/.next/static/chunks/app/api/acp/session/route-2f4705aa66819b86.js +0 -1
  287. package/_standalone/.next/static/chunks/app/api/agent-activity/route-2f4705aa66819b86.js +0 -1
  288. package/_standalone/.next/static/chunks/app/api/agents/custom/detect/route-2f4705aa66819b86.js +0 -1
  289. package/_standalone/.next/static/chunks/app/api/agents/custom/route-2f4705aa66819b86.js +0 -1
  290. package/_standalone/.next/static/chunks/app/api/ask/route-2f4705aa66819b86.js +0 -1
  291. package/_standalone/.next/static/chunks/app/api/ask-sessions/route-2f4705aa66819b86.js +0 -1
  292. package/_standalone/.next/static/chunks/app/api/auth/route-2f4705aa66819b86.js +0 -1
  293. package/_standalone/.next/static/chunks/app/api/backlinks/route-2f4705aa66819b86.js +0 -1
  294. package/_standalone/.next/static/chunks/app/api/bootstrap/route-2f4705aa66819b86.js +0 -1
  295. package/_standalone/.next/static/chunks/app/api/changes/route-2f4705aa66819b86.js +0 -1
  296. package/_standalone/.next/static/chunks/app/api/export/route-2f4705aa66819b86.js +0 -1
  297. package/_standalone/.next/static/chunks/app/api/extract-pdf/route-2f4705aa66819b86.js +0 -1
  298. package/_standalone/.next/static/chunks/app/api/file/import/route-2f4705aa66819b86.js +0 -1
  299. package/_standalone/.next/static/chunks/app/api/file/raw/route-2f4705aa66819b86.js +0 -1
  300. package/_standalone/.next/static/chunks/app/api/file/route-2f4705aa66819b86.js +0 -1
  301. package/_standalone/.next/static/chunks/app/api/files/route-2f4705aa66819b86.js +0 -1
  302. package/_standalone/.next/static/chunks/app/api/git/route-2f4705aa66819b86.js +0 -1
  303. package/_standalone/.next/static/chunks/app/api/graph/route-2f4705aa66819b86.js +0 -1
  304. package/_standalone/.next/static/chunks/app/api/health/route-2f4705aa66819b86.js +0 -1
  305. package/_standalone/.next/static/chunks/app/api/inbox/route-2f4705aa66819b86.js +0 -1
  306. package/_standalone/.next/static/chunks/app/api/init/route-2f4705aa66819b86.js +0 -1
  307. package/_standalone/.next/static/chunks/app/api/mcp/agents/route-2f4705aa66819b86.js +0 -1
  308. package/_standalone/.next/static/chunks/app/api/mcp/install/route-2f4705aa66819b86.js +0 -1
  309. package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-2f4705aa66819b86.js +0 -1
  310. package/_standalone/.next/static/chunks/app/api/mcp/restart/route-2f4705aa66819b86.js +0 -1
  311. package/_standalone/.next/static/chunks/app/api/mcp/status/route-2f4705aa66819b86.js +0 -1
  312. package/_standalone/.next/static/chunks/app/api/mcp/uninstall/route-2f4705aa66819b86.js +0 -1
  313. package/_standalone/.next/static/chunks/app/api/monitoring/route-2f4705aa66819b86.js +0 -1
  314. package/_standalone/.next/static/chunks/app/api/recent-files/route-2f4705aa66819b86.js +0 -1
  315. package/_standalone/.next/static/chunks/app/api/restart/route-2f4705aa66819b86.js +0 -1
  316. package/_standalone/.next/static/chunks/app/api/search/route-2f4705aa66819b86.js +0 -1
  317. package/_standalone/.next/static/chunks/app/api/settings/list-models/route-2f4705aa66819b86.js +0 -1
  318. package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-2f4705aa66819b86.js +0 -1
  319. package/_standalone/.next/static/chunks/app/api/settings/route-2f4705aa66819b86.js +0 -1
  320. package/_standalone/.next/static/chunks/app/api/settings/test-key/route-2f4705aa66819b86.js +0 -1
  321. package/_standalone/.next/static/chunks/app/api/setup/check-path/route-2f4705aa66819b86.js +0 -1
  322. package/_standalone/.next/static/chunks/app/api/setup/check-port/route-2f4705aa66819b86.js +0 -1
  323. package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-2f4705aa66819b86.js +0 -1
  324. package/_standalone/.next/static/chunks/app/api/setup/ls/route-2f4705aa66819b86.js +0 -1
  325. package/_standalone/.next/static/chunks/app/api/setup/route-2f4705aa66819b86.js +0 -1
  326. package/_standalone/.next/static/chunks/app/api/skills/route-2f4705aa66819b86.js +0 -1
  327. package/_standalone/.next/static/chunks/app/api/sync/route-2f4705aa66819b86.js +0 -1
  328. package/_standalone/.next/static/chunks/app/api/tree-version/route-2f4705aa66819b86.js +0 -1
  329. package/_standalone/.next/static/chunks/app/api/uninstall/route-2f4705aa66819b86.js +0 -1
  330. package/_standalone/.next/static/chunks/app/api/update/route-2f4705aa66819b86.js +0 -1
  331. package/_standalone/.next/static/chunks/app/api/update-check/route-2f4705aa66819b86.js +0 -1
  332. package/_standalone/.next/static/chunks/app/api/update-status/route-2f4705aa66819b86.js +0 -1
  333. package/_standalone/.next/static/chunks/app/api/workflows/route-2f4705aa66819b86.js +0 -1
  334. package/_standalone/.next/static/chunks/app/changes/page-6d2f49651c0061f7.js +0 -1
  335. package/_standalone/.next/static/chunks/app/echo/page-2f4705aa66819b86.js +0 -1
  336. package/_standalone/.next/static/chunks/app/loading-2f4705aa66819b86.js +0 -1
  337. package/_standalone/.next/static/chunks/app/trash/page-f92b728b78ac0f7e.js +0 -1
  338. package/_standalone/.next/static/chunks/app/view/[...path]/loading-2f4705aa66819b86.js +0 -1
  339. package/_standalone/.next/static/chunks/app/view/[...path]/page-f87f4901b5e1a88f.js +0 -12
  340. package/_standalone/.next/static/chunks/app/wiki/page-641edb1f3cff2f93.js +0 -1
  341. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-2f4705aa66819b86.js +0 -1
  342. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-2f4705aa66819b86.js +0 -1
  343. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-2f4705aa66819b86.js +0 -1
  344. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-2f4705aa66819b86.js +0 -1
  345. package/_standalone/.next/static/css/6c104b118d3bc9b7.css +0 -1
  346. package/_standalone/.next/static/u8p6oIRTcr_ns-ElNZ9rl/_buildManifest.js +0 -1
  347. /package/_standalone/.next/static/{u8p6oIRTcr_ns-ElNZ9rl → K3wZNf5bj_AFYwtqcRXIf}/_ssgManifest.js +0 -0
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useRef, useState, useCallback } from 'react';
4
- import type { Message, ImagePart, AskMode } from '@/lib/types';
4
+ import type { Message, ImagePart, AskMode, LocalAttachment } from '@/lib/types';
5
5
  import type { ProviderId } from '@/lib/agent/providers';
6
6
  import { consumeUIMessageStream } from '@/lib/agent/stream-consumer';
7
7
  import { isRetryableError, retryDelay, sleep } from '@/lib/agent/reconnect';
@@ -18,7 +18,7 @@ export interface AskChatRefs {
18
18
  setMessages: React.Dispatch<React.SetStateAction<Message[]>>;
19
19
  }>;
20
20
  uploadRef: React.RefObject<{
21
- localAttachments: { name: string; content: string }[];
21
+ localAttachments: LocalAttachment[];
22
22
  }>;
23
23
  selectedSkillRef: React.RefObject<{ name: string } | null>;
24
24
  selectedAcpAgentRef: React.RefObject<unknown>;
@@ -103,12 +103,14 @@ export function useAskChat({
103
103
  messages: requestMessages,
104
104
  currentFile,
105
105
  attachedFiles: refs.attachedFilesRef.current,
106
- uploadedFiles: upl.localAttachments.map(f => ({
107
- name: f.name,
108
- content: f.content.length > 20_000
109
- ? f.content.slice(0, 20_000) + '\n\n[...truncated to first ~20000 chars]'
110
- : f.content,
111
- })),
106
+ uploadedFiles: upl.localAttachments
107
+ .filter(f => f.status !== 'loading')
108
+ .map(f => ({
109
+ name: f.name,
110
+ content: f.content.length > 80_000
111
+ ? f.content.slice(0, 80_000) + '\n\n[...truncated to first ~80000 chars]'
112
+ : f.content,
113
+ })),
112
114
  selectedAcpAgent: acpAgent,
113
115
  mode: chatMode,
114
116
  providerOverride: providerOverride ?? undefined,
@@ -22,28 +22,76 @@ function uint8ToBase64(bytes: Uint8Array): string {
22
22
  return btoa(binary);
23
23
  }
24
24
 
25
- async function extractPdfText(file: File): Promise<string> {
26
- const buffer = await file.arrayBuffer();
27
- const dataBase64 = uint8ToBase64(new Uint8Array(buffer));
25
+ /**
26
+ * Extract text from a PDF file via the backend API.
27
+ * Returns a LocalAttachment with `status` reflecting the outcome.
28
+ */
29
+ async function extractPdfToAttachment(file: File): Promise<LocalAttachment> {
30
+ const name = file.name;
28
31
 
29
- const res = await fetch('/api/extract-pdf', {
30
- method: 'POST',
31
- headers: { 'Content-Type': 'application/json' },
32
- body: JSON.stringify({ name: file.name, dataBase64 }),
33
- });
34
-
35
- let payload: { text?: string; extracted?: boolean; error?: string } = {};
36
32
  try {
37
- payload = await res.json();
38
- } catch {
39
- // ignore JSON parse error
40
- }
33
+ const buffer = await file.arrayBuffer();
34
+ const dataBase64 = uint8ToBase64(new Uint8Array(buffer));
41
35
 
42
- if (!res.ok) {
43
- throw new Error(payload.error || `PDF extraction failed (${res.status})`);
44
- }
36
+ const res = await fetch('/api/extract-pdf', {
37
+ method: 'POST',
38
+ headers: { 'Content-Type': 'application/json' },
39
+ body: JSON.stringify({ name, dataBase64 }),
40
+ });
41
+
42
+ let payload: {
43
+ text?: string;
44
+ extracted?: boolean;
45
+ error?: string;
46
+ truncated?: boolean;
47
+ totalChars?: number;
48
+ pagesParsed?: number;
49
+ } = {};
50
+ try {
51
+ payload = await res.json();
52
+ } catch {
53
+ throw new Error('Failed to parse extraction response');
54
+ }
55
+
56
+ if (!res.ok) {
57
+ throw new Error(payload.error || `PDF extraction failed (${res.status})`);
58
+ }
59
+
60
+ const extracted = payload.extracted ? (payload.text || '') : '';
61
+
62
+ if (!extracted) {
63
+ return {
64
+ name,
65
+ content: `[PDF: ${name}] Could not extract readable text (possibly scanned/image PDF).`,
66
+ status: 'error',
67
+ error: 'Scanned or image-only PDF — no extractable text',
68
+ };
69
+ }
70
+
71
+ const att: LocalAttachment = {
72
+ name,
73
+ content: `[PDF TEXT EXTRACTED: ${name}]\n\n${extracted}`,
74
+ status: 'success',
75
+ };
76
+
77
+ if (payload.truncated && payload.totalChars) {
78
+ att.truncatedInfo = {
79
+ totalChars: payload.totalChars,
80
+ includedChars: extracted.length,
81
+ totalPages: payload.pagesParsed ?? 0,
82
+ };
83
+ }
45
84
 
46
- return payload.extracted ? (payload.text || '') : '';
85
+ return att;
86
+ } catch (err) {
87
+ const msg = err instanceof Error ? err.message : 'Unknown error';
88
+ return {
89
+ name,
90
+ content: `[PDF: ${name}] Failed to extract text from this PDF.`,
91
+ status: 'error',
92
+ error: msg,
93
+ };
94
+ }
47
95
  }
48
96
 
49
97
  export function useFileUpload() {
@@ -73,37 +121,43 @@ export function useFileUpload() {
73
121
  setUploadError('');
74
122
  }
75
123
 
76
- const loaded = await Promise.all(
77
- accepted.map(async (f) => {
78
- const ext = getExt(f.name);
79
- if (ext === '.pdf') {
80
- try {
81
- const extracted = await extractPdfText(f);
82
- return {
83
- name: f.name,
84
- content: extracted
85
- ? `[PDF TEXT EXTRACTED: ${f.name}]\n\n${extracted}`
86
- : `[PDF: ${f.name}] Could not extract readable text (possibly scanned/image PDF).`,
87
- };
88
- } catch {
89
- return {
90
- name: f.name,
91
- content: `[PDF: ${f.name}] Failed to extract text from this PDF.`,
92
- };
93
- }
94
- }
95
- return { name: f.name, content: await f.text() };
96
- }),
97
- );
124
+ // Phase 1: Immediately add all files — PDFs start in 'loading' state
125
+ const pdfFiles: File[] = [];
126
+ const immediateItems: LocalAttachment[] = [];
127
+
128
+ for (const f of accepted) {
129
+ if (getExt(f.name) === '.pdf') {
130
+ immediateItems.push({ name: f.name, content: '', status: 'loading' });
131
+ pdfFiles.push(f);
132
+ } else {
133
+ immediateItems.push({
134
+ name: f.name,
135
+ content: await f.text(),
136
+ status: 'success',
137
+ });
138
+ }
139
+ }
98
140
 
99
141
  setLocalAttachments((prev) => {
100
142
  const merged = [...prev];
101
- for (const item of loaded) {
102
- if (!merged.some((m) => m.name === item.name && m.content === item.content))
103
- merged.push(item);
143
+ for (const item of immediateItems) {
144
+ if (!merged.some((m) => m.name === item.name)) merged.push(item);
104
145
  }
105
146
  return merged;
106
147
  });
148
+
149
+ // Phase 2: Extract PDFs in parallel, then update each one in-place
150
+ if (pdfFiles.length > 0) {
151
+ const results = await Promise.all(pdfFiles.map(extractPdfToAttachment));
152
+
153
+ setLocalAttachments((prev) =>
154
+ prev.map((att) => {
155
+ if (att.status !== 'loading') return att;
156
+ const result = results.find((r) => r.name === att.name);
157
+ return result ?? att;
158
+ }),
159
+ );
160
+ }
107
161
  }, []);
108
162
 
109
163
  const removeAttachment = useCallback((idx: number) => {
@@ -86,7 +86,7 @@ export function useImageUpload() {
86
86
  }
87
87
  try {
88
88
  const { data, mimeType } = await compressImage(file);
89
- results.push({ type: 'image', data, mimeType });
89
+ results.push({ type: 'image', data, mimeType, fileName: file.name || undefined });
90
90
  } catch {
91
91
  setImageError(`Failed to process image: ${file.name}`);
92
92
  }
@@ -6,12 +6,21 @@
6
6
  * - SKILL.md owns: knowledge-base-specific execution patterns, tool selection, safety rules
7
7
  * - Tool descriptions own: per-tool usage instructions (no duplication here)
8
8
  *
9
- * Token budget: ~600 tokens (down from ~900 in v2). Freed space = more room for
10
- * SKILL.md + bootstrap context within the same context window.
9
+ * Token budget: ~750 tokens (v4 added persona warmth + self-introduction).
10
+ * Freed space = more room for SKILL.md + bootstrap context within the same context window.
11
11
  */
12
12
  export const AGENT_SYSTEM_PROMPT = `You are MindOS Agent — the operator of the user's second brain.
13
13
 
14
- Persona: Methodical, strictly objective, execution-oriented. Zero fluff. Never use preambles like "Here is the result" or "I found...".
14
+ Persona: Warm yet precise, reliable, execution-oriented. Like a trusted notebook that understands you — quiet confidence, zero fluff. Be professional but never cold; be helpful but never verbose.
15
+
16
+ ## Self-Introduction
17
+
18
+ When the user greets you ("你好", "hi", "你是谁", "what can you do", etc.) or this appears to be their first message in a new conversation, introduce yourself briefly:
19
+
20
+ - Who: MindOS Agent, the operator of their personal knowledge base (second brain).
21
+ - What: You can search, read, write, and organize their notes; capture decisions and lessons; run workflows/SOPs; and help them build a lasting, structured memory.
22
+ - Tone: Warm, concise, confident. One short paragraph, then invite them to try something — e.g., "想查点什么,还是有东西要记下来?"
23
+ - Do NOT self-introduce when the user jumps straight into a task (search, save, edit, etc.).
15
24
 
16
25
  ## Core Directives
17
26
 
@@ -45,7 +54,9 @@ Persona: Methodical, strictly objective, execution-oriented. Zero fluff. Never u
45
54
  */
46
55
  export const CHAT_SYSTEM_PROMPT = `You are MindOS Agent — the operator of the user's second brain.
47
56
 
48
- Persona: Methodical, strictly objective, execution-oriented. Zero fluff. Never use preambles like "Here is the result" or "I found...".
57
+ Persona: Warm yet precise, reliable, execution-oriented. Like a trusted notebook that understands you — quiet confidence, zero fluff. Be professional but never cold; be helpful but never verbose.
58
+
59
+ When the user greets you or asks who you are, briefly introduce yourself: you're MindOS Agent, here to help them search and read their knowledge base. Keep it warm and concise, then invite them to ask something.
49
60
 
50
61
  ## Mode: Chat (Read-Only)
51
62
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  import fs from 'fs';
10
10
  import path from 'path';
11
- import { expandHome, MCP_AGENTS } from './mcp-agents';
11
+ import { expandHome, MCP_AGENTS, parseJsonc } from './mcp-agents';
12
12
  import type { AgentDef } from './mcp-agents';
13
13
  import { readSettings, writeSettings } from './settings';
14
14
 
@@ -39,6 +39,8 @@ export interface DetectResult {
39
39
  detectedSkillDir?: string;
40
40
  skillCount?: number;
41
41
  skillNames?: string[];
42
+ mcpServers?: string[];
43
+ mcpParseError?: string;
42
44
  suggestedName?: string;
43
45
  }
44
46
 
@@ -282,6 +284,112 @@ export function scanCustomAgentSkills(custom: CustomAgentDef): { skills: string[
282
284
  }
283
285
  }
284
286
 
287
+ /* ─── Enhanced Skill & MCP Detection ─── */
288
+
289
+ /**
290
+ * Parse JSON config to extract MCP server names from a config key.
291
+ */
292
+ function parseJsonMcpServers(content: string, key: string): string[] {
293
+ try {
294
+ const config = parseJsonc(content);
295
+ const servers = config[key];
296
+ if (servers && typeof servers === 'object') {
297
+ return Object.keys(servers).sort();
298
+ }
299
+ } catch {
300
+ return [];
301
+ }
302
+ return [];
303
+ }
304
+
305
+ /**
306
+ * Parse TOML config to extract MCP server names from a section key.
307
+ */
308
+ function parseTomlMcpServers(content: string, sectionKey: string): string[] {
309
+ const names = new Set<string>();
310
+ const lines = content.split('\n');
311
+ const sectionPrefix = `${sectionKey}.`;
312
+
313
+ for (const line of lines) {
314
+ const trimmed = line.trim();
315
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
316
+ const section = trimmed.slice(1, -1).trim();
317
+ if (section.startsWith(sectionPrefix)) {
318
+ const name = section.slice(sectionPrefix.length).split('.')[0];
319
+ if (name) names.add(name);
320
+ }
321
+ }
322
+ }
323
+
324
+ return [...names].sort();
325
+ }
326
+
327
+ /**
328
+ * Detect config format from file extension.
329
+ */
330
+ function detectConfigFormat(configPath: string): 'json' | 'toml' {
331
+ return configPath.toLowerCase().endsWith('.toml') ? 'toml' : 'json';
332
+ }
333
+
334
+ /**
335
+ * Comprehensive profile detection for a custom agent.
336
+ * Returns MCP servers, skills, and any parse errors.
337
+ */
338
+ export function detectCustomAgentProfile(
339
+ baseDir: string,
340
+ configPath: string,
341
+ configKey: string,
342
+ ): {
343
+ mcpServers: string[];
344
+ skillNames: string[];
345
+ skillDir: string;
346
+ configFormat: 'json' | 'toml';
347
+ parseError?: string;
348
+ } {
349
+ const expanded = expandHome(baseDir);
350
+ const configAbsPath = expandHome(configPath);
351
+
352
+ const result = {
353
+ mcpServers: [] as string[],
354
+ skillNames: [] as string[],
355
+ skillDir: '',
356
+ configFormat: detectConfigFormat(configPath) as 'json' | 'toml',
357
+ parseError: undefined as string | undefined,
358
+ };
359
+
360
+ // 1. Read MCP servers from config
361
+ if (fs.existsSync(configAbsPath)) {
362
+ try {
363
+ const content = fs.readFileSync(configAbsPath, 'utf-8');
364
+ result.mcpServers =
365
+ result.configFormat === 'json'
366
+ ? parseJsonMcpServers(content, configKey)
367
+ : parseTomlMcpServers(content, configKey);
368
+ } catch (err) {
369
+ result.parseError = `Failed to parse MCP config: ${err instanceof Error ? err.message : 'Unknown error'}`;
370
+ }
371
+ }
372
+
373
+ // 2. Scan Skill directory
374
+ const skillDirPath = path.join(expanded, 'skills');
375
+ if (fs.existsSync(skillDirPath)) {
376
+ result.skillDir = baseDir.endsWith('/') ? baseDir + 'skills/' : baseDir + '/skills/';
377
+ try {
378
+ const entries = fs.readdirSync(skillDirPath, { withFileTypes: true });
379
+ result.skillNames = entries
380
+ .filter(e => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith('.'))
381
+ .map(e => e.name)
382
+ .sort((a, b) => a.localeCompare(b));
383
+ } catch {
384
+ // Skill dir exists but not readable, continue
385
+ }
386
+ } else {
387
+ result.skillDir = baseDir.endsWith('/') ? baseDir + 'skills/' : baseDir + '/skills/';
388
+ }
389
+
390
+ return result;
391
+ }
392
+
285
393
  /* ─── Validation ─── */
286
394
 
287
395
  export function validateCustomAgentInput(input: {
@@ -0,0 +1,58 @@
1
+ /**
2
+ * File operations utilities.
3
+ * Used for recursive directory copying and other file system tasks.
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+
9
+ /**
10
+ * Recursively copy a directory and all its contents.
11
+ *
12
+ * @param src Source directory path
13
+ * @param dst Destination directory path
14
+ * @throws Error if source doesn't exist or copy fails
15
+ */
16
+ export async function copyDir(src: string, dst: string): Promise<void> {
17
+ // Create destination directory
18
+ await fs.promises.mkdir(dst, { recursive: true });
19
+
20
+ // Read source directory
21
+ const entries = await fs.promises.readdir(src, { withFileTypes: true });
22
+
23
+ for (const entry of entries) {
24
+ const srcPath = path.join(src, entry.name);
25
+ const dstPath = path.join(dst, entry.name);
26
+
27
+ if (entry.isDirectory()) {
28
+ // Recursively copy subdirectory
29
+ await copyDir(srcPath, dstPath);
30
+ } else if (entry.isFile()) {
31
+ // Copy file
32
+ await fs.promises.copyFile(srcPath, dstPath);
33
+ } else if (entry.isSymbolicLink()) {
34
+ // Copy symbolic link target
35
+ const linkTarget = await fs.promises.readlink(srcPath);
36
+ await fs.promises.symlink(linkTarget, dstPath);
37
+ }
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Check if a directory exists.
43
+ */
44
+ export function dirExists(dir: string): boolean {
45
+ try {
46
+ const stat = fs.statSync(dir);
47
+ return stat.isDirectory();
48
+ } catch {
49
+ return false;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Create a directory recursively.
55
+ */
56
+ export async function ensureDir(dir: string): Promise<void> {
57
+ await fs.promises.mkdir(dir, { recursive: true });
58
+ }
@@ -125,6 +125,7 @@ export const aiChatEn = {
125
125
  },
126
126
  loading: 'Loading changes...',
127
127
  empty: 'No content changes yet.',
128
+ emptyHint: 'Changes made to your files will appear here when you or an agent edits content.',
128
129
  open: 'Open',
129
130
  unchangedLines: (n: number) => `... ${n} unchanged lines ...`,
130
131
  operations: {
@@ -144,6 +145,24 @@ export const aiChatEn = {
144
145
  import_file: 'Import file',
145
146
  legacy_agent_diff_import: 'Import from Agent Diff',
146
147
  },
148
+ /** Frontend-side summary translations for known backend summary patterns */
149
+ summaries: {
150
+ updatedFileContent: 'Updated file content',
151
+ appendedContent: 'Appended content to file',
152
+ insertedLines: (n: number) => `Inserted ${n} line(s)`,
153
+ updatedLines: (start: number, end: number) => `Updated lines ${start}-${end}`,
154
+ insertedAfterHeading: (h: string) => `Inserted content after heading "${h}"`,
155
+ updatedSection: (h: string) => `Updated section "${h}"`,
156
+ movedToTrash: 'Moved to trash',
157
+ renamedFile: (name: string) => `Renamed file to ${name}`,
158
+ createdFile: 'Created file',
159
+ movedFile: (p: string) => `Moved file to ${p}`,
160
+ createdSpace: 'Created space',
161
+ renamedSpace: (name: string) => `Renamed space to ${name}`,
162
+ appendedCsvRow: (n: number) => `Appended CSV row (${n} cell${n === 1 ? '' : 's'})`,
163
+ importedFile: 'Imported file into knowledge base',
164
+ importedLegacyDiff: 'Imported legacy agent diff',
165
+ },
147
166
  relativeTime: {
148
167
  justNow: 'just now',
149
168
  minutesAgo: (n: number) => `${n}m ago`,
@@ -307,6 +326,7 @@ export const aiChatZh = {
307
326
  },
308
327
  loading: '正在加载变更...',
309
328
  empty: '暂无内容变更。',
329
+ emptyHint: '你或 Agent 编辑文件时,变更会显示在这里。',
310
330
  open: '打开',
311
331
  unchangedLines: (n: number) => `... ${n} 行未变更 ...`,
312
332
  operations: {
@@ -326,6 +346,23 @@ export const aiChatZh = {
326
346
  import_file: '导入文件',
327
347
  legacy_agent_diff_import: '从 Agent Diff 导入',
328
348
  },
349
+ summaries: {
350
+ updatedFileContent: '更新了文件内容',
351
+ appendedContent: '追加了文件内容',
352
+ insertedLines: (n: number) => `插入了 ${n} 行`,
353
+ updatedLines: (start: number, end: number) => `更新了第 ${start}-${end} 行`,
354
+ insertedAfterHeading: (h: string) => `在标题「${h}」后插入了内容`,
355
+ updatedSection: (h: string) => `更新了章节「${h}」`,
356
+ movedToTrash: '移到了回收站',
357
+ renamedFile: (name: string) => `重命名为 ${name}`,
358
+ createdFile: '创建了文件',
359
+ movedFile: (p: string) => `移动到了 ${p}`,
360
+ createdSpace: '创建了空间',
361
+ renamedSpace: (name: string) => `重命名空间为 ${name}`,
362
+ appendedCsvRow: (n: number) => `追加了 CSV 行(${n} 个单元格)`,
363
+ importedFile: '导入了文件到知识库',
364
+ importedLegacyDiff: '从 Agent Diff 导入了变更',
365
+ },
329
366
  relativeTime: {
330
367
  justNow: '刚刚',
331
368
  minutesAgo: (n: number) => `${n} 分钟前`,
@@ -103,6 +103,7 @@ export const knowledgeEn = {
103
103
  viewAllHistory: (n: number) => `View all ${n} records →`,
104
104
  agingHint: '7+ days',
105
105
  savedToast: (n: number) => `${n} file${n === 1 ? '' : 's'} saved to Capture`,
106
+ savedToDir: (n: number, dir: string) => `${n} file${n === 1 ? '' : 's'} saved to ${dir}`,
106
107
  savedWithSkipped: (saved: number, skipped: number) =>
107
108
  saved > 0
108
109
  ? `${saved} saved, ${skipped} skipped (unsupported format)`
@@ -481,6 +482,7 @@ export const knowledgeZh = {
481
482
  viewAllHistory: (n: number) => `查看全部 ${n} 条记录 →`,
482
483
  agingHint: '7天+',
483
484
  savedToast: (n: number) => `${n} 个文件已保存到暂存台`,
485
+ savedToDir: (n: number, dir: string) => `${n} 个文件已保存到 ${dir}`,
484
486
  savedWithSkipped: (saved: number, skipped: number) =>
485
487
  saved > 0
486
488
  ? `已保存 ${saved} 个,跳过 ${skipped} 个(格式不支持)`
@@ -91,3 +91,89 @@ export async function quickDropToInbox(
91
91
  toast.error(t.inbox.saveFailed, 4000);
92
92
  }
93
93
  }
94
+
95
+ /**
96
+ * Drop files into a specific directory via /api/file/import.
97
+ * Used when user drags external files onto a directory in the file tree.
98
+ */
99
+ export async function quickDropToDirectory(
100
+ files: File[],
101
+ targetDir: string,
102
+ t: ReturnType<typeof useLocale>['t'],
103
+ ) {
104
+ const payload: Array<{ name: string; content: string; encoding?: string }> = [];
105
+ let oversizedCount = 0;
106
+
107
+ const BINARY_EXTS = new Set([
108
+ 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'ico',
109
+ 'mp3', 'wav', 'm4a', 'ogg', 'flac', 'aac', 'mp4', 'webm', 'mov', 'mkv',
110
+ ]);
111
+
112
+ for (const file of files) {
113
+ if (file.size > MAX_FILE_SIZE) {
114
+ oversizedCount++;
115
+ continue;
116
+ }
117
+ try {
118
+ const ext = (file.name.split('.').pop() ?? '').toLowerCase();
119
+ if (BINARY_EXTS.has(ext)) {
120
+ const buf = await file.arrayBuffer();
121
+ payload.push({ name: file.name, content: arrayBufferToBase64(buf), encoding: 'base64' });
122
+ } else {
123
+ const text = await file.text();
124
+ payload.push({ name: file.name, content: text });
125
+ }
126
+ } catch {
127
+ /* skip unreadable files */
128
+ }
129
+ }
130
+
131
+ if (payload.length === 0) {
132
+ if (oversizedCount > 0) {
133
+ toast.error(t.inbox.tooLarge(oversizedCount), 4000);
134
+ } else if (files.length > 0) {
135
+ toast.error(t.inbox.saveFailed, 4000);
136
+ }
137
+ return;
138
+ }
139
+
140
+ const dirName = targetDir.split('/').pop() || targetDir;
141
+
142
+ try {
143
+ const res = await fetch('/api/file/import', {
144
+ method: 'POST',
145
+ headers: { 'Content-Type': 'application/json' },
146
+ body: JSON.stringify({
147
+ files: payload,
148
+ targetSpace: targetDir,
149
+ organize: false,
150
+ conflict: 'rename',
151
+ }),
152
+ });
153
+
154
+ if (!res.ok) {
155
+ const data = await res.json().catch(() => ({}));
156
+ console.error('[TreeDrop] Save failed:', data.error);
157
+ toast.error(t.inbox.saveFailed, 4000);
158
+ return;
159
+ }
160
+
161
+ const result = await res.json();
162
+ const saved = result.created?.length ?? 0;
163
+ const skipped = result.skipped?.length ?? 0;
164
+
165
+ if (saved > 0 && (skipped + oversizedCount) > 0) {
166
+ toast.success(t.inbox.savedWithSkipped(saved, skipped + oversizedCount), 4000);
167
+ } else if (saved > 0) {
168
+ toast.success(t.inbox.savedToDir(saved, dirName), 3000);
169
+ } else {
170
+ if (oversizedCount > 0) toast.error(t.inbox.tooLarge(oversizedCount), 4000);
171
+ if (skipped > 0) toast.error(t.inbox.savedWithSkipped(0, skipped), 4000);
172
+ }
173
+
174
+ window.dispatchEvent(new Event('mindos:files-changed'));
175
+ } catch (err) {
176
+ console.error('[TreeDrop] Network error:', err);
177
+ toast.error(t.inbox.saveFailed, 4000);
178
+ }
179
+ }
@@ -5,7 +5,7 @@ import { execSync } from 'child_process';
5
5
 
6
6
  /** Parse JSONC — strips single-line (//) and block comments before JSON.parse */
7
7
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
- function parseJsonc(text: string): any {
8
+ export function parseJsonc(text: string): any {
9
9
  let stripped = text.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*$)/gm, (m, g) => g ? '' : m);
10
10
  stripped = stripped.replace(/\/\*[\s\S]*?\*\//g, '');
11
11
  if (!stripped.trim()) return {};
@@ -244,6 +244,24 @@ export const MCP_AGENTS: Record<string, AgentDef> = {
244
244
  presenceCli: 'agy',
245
245
  presenceDirs: ['~/.gemini/antigravity/'],
246
246
  },
247
+ 'qclaw': {
248
+ name: 'QClaw',
249
+ project: null,
250
+ global: '~/.qclaw/mcp.json',
251
+ key: 'mcpServers',
252
+ preferredTransport: 'stdio',
253
+ presenceCli: 'qclaw',
254
+ presenceDirs: ['~/.qclaw/'],
255
+ },
256
+ 'workbuddy': {
257
+ name: 'WorkBuddy',
258
+ project: null,
259
+ global: '~/.workbuddy/mcp.json',
260
+ key: 'mcpServers',
261
+ preferredTransport: 'stdio',
262
+ presenceCli: 'workbuddy',
263
+ presenceDirs: ['~/.workbuddy/'],
264
+ },
247
265
  };
248
266
 
249
267
  /**
@@ -271,6 +289,8 @@ export const SKILL_AGENT_REGISTRY: Record<string, SkillAgentRegistration> = {
271
289
  'github-copilot': { mode: 'universal' },
272
290
  'codex': { mode: 'universal' },
273
291
  'antigravity': { mode: 'additional', skillAgentName: 'antigravity' },
292
+ 'qclaw': { mode: 'unsupported' },
293
+ 'workbuddy': { mode: 'unsupported' },
274
294
  };
275
295
 
276
296
  export interface SkillWorkspaceProfile {
package/app/lib/types.ts CHANGED
@@ -52,6 +52,8 @@ export interface ImagePart {
52
52
  /** Base64-encoded image data (no data: prefix) */
53
53
  data: string;
54
54
  mimeType: ImageMimeType;
55
+ /** Original file name, if available */
56
+ fileName?: string;
55
57
  }
56
58
 
57
59
  export type MessagePart = TextPart | ToolCallPart | ReasoningPart | ImagePart;
@@ -72,6 +74,16 @@ export interface Message {
72
74
  export interface LocalAttachment {
73
75
  name: string;
74
76
  content: string;
77
+ /** Extraction status for PDF uploads. Absent / undefined = legacy (treated as success). */
78
+ status?: 'loading' | 'success' | 'error';
79
+ /** Human-readable error message (only when status = 'error'). */
80
+ error?: string;
81
+ /** Present when the full text was too long and had to be truncated. */
82
+ truncatedInfo?: {
83
+ totalChars: number;
84
+ includedChars: number;
85
+ totalPages: number;
86
+ };
75
87
  }
76
88
 
77
89
  /** User-facing Ask modes. 'organize' is internal-only (not selectable by users). */