@geminilight/mindos 0.6.57 → 0.6.59

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 (293) 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 +24 -24
  4. package/_standalone/.next/build-manifest.json +3 -3
  5. package/_standalone/.next/cache/.previewinfo +1 -1
  6. package/_standalone/.next/cache/.rscinfo +1 -1
  7. package/_standalone/.next/cache/config.json +3 -3
  8. package/_standalone/.next/prerender-manifest.json +3 -3
  9. package/_standalone/.next/react-loadable-manifest.json +1 -1
  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 +2 -2
  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 +2 -2
  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.js +1 -1
  34. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  35. package/_standalone/.next/server/app/api/acp/detect/route.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
  37. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.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/custom/detect/route.js +1 -1
  42. package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
  43. package/_standalone/.next/server/app/api/agents/custom/route.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 +5 -5
  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.nft.json +1 -1
  60. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  61. package/_standalone/.next/server/app/api/file/raw/route.js.nft.json +1 -1
  62. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  63. package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
  64. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  65. package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  66. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  68. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  69. package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
  70. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  72. package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -1
  73. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  74. package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
  75. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  76. package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
  77. package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
  78. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  79. package/_standalone/.next/server/app/api/mcp/install/route.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.js +1 -1
  84. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  86. package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
  87. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  88. package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
  89. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  90. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  91. package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  92. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.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.js +1 -1
  95. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  96. package/_standalone/.next/server/app/api/settings/route.js +1 -1
  97. package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  98. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  99. package/_standalone/.next/server/app/api/settings/test-key/route.js +1 -1
  100. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  101. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  102. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  103. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  104. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  105. package/_standalone/.next/server/app/api/setup/route.js +1 -1
  106. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  107. package/_standalone/.next/server/app/api/skills/route.js +1 -1
  108. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  109. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  110. package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
  111. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  112. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  113. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  114. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  115. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  116. package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
  117. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  118. package/_standalone/.next/server/app/changes/page.js +2 -2
  119. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  120. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  121. package/_standalone/.next/server/app/echo/[segment]/page.js +3 -3
  122. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  123. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  124. package/_standalone/.next/server/app/echo/page.js +1 -1
  125. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  126. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  127. package/_standalone/.next/server/app/explore/page.js +3 -3
  128. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  129. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  130. package/_standalone/.next/server/app/help/page.js +2 -2
  131. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  132. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  133. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  134. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  135. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  136. package/_standalone/.next/server/app/login/page.js +2 -2
  137. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  138. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  139. package/_standalone/.next/server/app/page.js +2 -8
  140. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  141. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  142. package/_standalone/.next/server/app/setup/page.js +2 -2
  143. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  144. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  145. package/_standalone/.next/server/app/trash/page.js +3 -3
  146. package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
  147. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  148. package/_standalone/.next/server/app/view/[...path]/page.js +3 -3
  149. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  150. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  151. package/_standalone/.next/server/app/wiki/page.js +2 -2
  152. package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
  153. package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
  154. package/_standalone/.next/server/app-paths-manifest.json +24 -24
  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/3484.js +1 -1
  158. package/_standalone/.next/server/chunks/530.js +61 -62
  159. package/_standalone/.next/server/chunks/6539.js +1 -1
  160. package/_standalone/.next/server/chunks/{2159.js → 8343.js} +2 -2
  161. package/_standalone/.next/server/chunks/9787.js +2 -0
  162. package/_standalone/.next/server/middleware-build-manifest.js +1 -1
  163. package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  164. package/_standalone/.next/server/pages/500.html +2 -2
  165. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  166. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  167. package/_standalone/.next/static/chunks/{1814.a7c127b2c73d1f70.js → 1814.a79b84d37df75c43.js} +1 -1
  168. package/_standalone/.next/static/chunks/3427-2e61a5df1f5e55fb.js +1 -0
  169. package/_standalone/.next/static/chunks/5581-dac72e9f16e5ea29.js +29 -0
  170. package/_standalone/.next/static/chunks/6297-085daa21037d5f81.js +1 -0
  171. package/_standalone/.next/static/chunks/7249-6cf8f2b78718c59e.js +11 -0
  172. package/_standalone/.next/static/chunks/8520-56ec9ff087c15204.js +22 -0
  173. package/_standalone/.next/static/chunks/9905-a19d379cb225246e.js +1 -0
  174. package/_standalone/.next/static/chunks/app/agents/[agentKey]/{page-7bdeab5af8e4f5f2.js → page-35ea6de1af2be3b5.js} +1 -1
  175. package/_standalone/.next/static/chunks/app/agents/page-b172ea3743adb047.js +1 -0
  176. package/_standalone/.next/static/chunks/app/changes/{page-5a72144d1080a699.js → page-6d2f49651c0061f7.js} +1 -1
  177. package/_standalone/.next/static/chunks/app/echo/[segment]/page-84b95256f6e38aae.js +11 -0
  178. package/_standalone/.next/static/chunks/app/explore/{page-d3d99308146c2240.js → page-d9f58000bc445360.js} +2 -2
  179. package/_standalone/.next/static/chunks/app/help/{page-222df603080b5fab.js → page-f8cb806371b3175f.js} +1 -1
  180. package/_standalone/.next/static/chunks/app/inbox/history/{page-07819cf95cb0805f.js → page-26e71fb6f716a4c4.js} +1 -1
  181. package/_standalone/.next/static/chunks/app/layout-b89b0d955f39a753.js +164 -0
  182. package/_standalone/.next/static/chunks/app/login/{page-0eeef685052869a6.js → page-18fb00d568cd1f0e.js} +1 -1
  183. package/_standalone/.next/static/chunks/app/page-a8e6f085f38388bf.js +1 -0
  184. package/_standalone/.next/static/chunks/app/setup/{page-99fcfc460fa29733.js → page-821714e7477be46c.js} +1 -1
  185. package/_standalone/.next/static/chunks/app/trash/page-f92b728b78ac0f7e.js +1 -0
  186. package/_standalone/.next/static/chunks/app/view/[...path]/{not-found-fc04c2bd4f35bc6f.js → not-found-6e0c75ad26ce8572.js} +1 -1
  187. package/_standalone/.next/static/chunks/app/view/[...path]/page-f87f4901b5e1a88f.js +12 -0
  188. package/_standalone/.next/static/chunks/app/wiki/page-641edb1f3cff2f93.js +1 -0
  189. package/_standalone/.next/static/chunks/{webpack-2c19436659aa657b.js → webpack-72e8d9e9073fd1f9.js} +1 -1
  190. package/_standalone/.next/static/css/6c104b118d3bc9b7.css +1 -0
  191. package/_standalone/.next/trace +64 -64
  192. package/_standalone/__tests__/api/mcp-install.test.ts +3 -2
  193. package/_standalone/__tests__/ask/non-streaming-api.test.ts +281 -0
  194. package/_standalone/__tests__/core/skill-install-logic.test.ts +1 -0
  195. package/_standalone/app/globals.css +2 -1
  196. package/_standalone/components/AskFab.tsx +4 -4
  197. package/_standalone/components/AskModal.tsx +1 -1
  198. package/_standalone/components/GuideCard.tsx +101 -152
  199. package/_standalone/components/RightAskPanel.tsx +2 -2
  200. package/_standalone/components/agents/CustomAgentModal.tsx +32 -8
  201. package/_standalone/components/ask/AskContent.tsx +90 -51
  202. package/_standalone/components/ask/AskHeader.tsx +218 -18
  203. package/_standalone/components/ask/MessageList.tsx +66 -47
  204. package/_standalone/components/ask/SessionHistory.tsx +86 -60
  205. package/_standalone/components/ask/SessionTabBar.tsx +29 -21
  206. package/_standalone/components/ask/ThinkingBlock.tsx +6 -5
  207. package/_standalone/components/ask/ToolCallBlock.tsx +10 -9
  208. package/_standalone/components/settings/SettingsContent.tsx +1 -1
  209. package/_standalone/data/skills/mindos/SKILL.md +72 -15
  210. package/_standalone/data/skills/mindos-zh/SKILL.md +73 -8
  211. package/_standalone/hooks/useAskSession.ts +23 -1
  212. package/_standalone/lib/stores/locale-store.ts +20 -6
  213. package/_standalone/tsconfig.tsbuildinfo +1 -1
  214. package/app/app/api/agents/custom/route.ts +8 -0
  215. package/app/app/api/ask/route.ts +171 -10
  216. package/app/app/api/mcp/agents/route.ts +5 -3
  217. package/app/app/api/settings/route.ts +9 -0
  218. package/app/app/api/settings/test-key/route.ts +13 -1
  219. package/app/app/globals.css +2 -1
  220. package/app/app/layout.tsx +16 -4
  221. package/app/components/AskFab.tsx +4 -4
  222. package/app/components/AskModal.tsx +1 -1
  223. package/app/components/GuideCard.tsx +101 -152
  224. package/app/components/HomeContent.tsx +116 -575
  225. package/app/components/RightAskPanel.tsx +2 -2
  226. package/app/components/WikiHomeContent.tsx +151 -3
  227. package/app/components/agents/CustomAgentModal.tsx +32 -8
  228. package/app/components/ask/AskContent.tsx +90 -51
  229. package/app/components/ask/AskHeader.tsx +218 -18
  230. package/app/components/ask/MessageList.tsx +66 -47
  231. package/app/components/ask/SessionHistory.tsx +86 -60
  232. package/app/components/ask/SessionTabBar.tsx +29 -21
  233. package/app/components/ask/ThinkingBlock.tsx +6 -5
  234. package/app/components/ask/ToolCallBlock.tsx +10 -9
  235. package/app/components/settings/SettingsContent.tsx +1 -1
  236. package/app/data/skills/mindos/SKILL.md +72 -15
  237. package/app/data/skills/mindos-zh/SKILL.md +73 -8
  238. package/app/hooks/useAskSession.ts +23 -1
  239. package/app/lib/custom-agents.ts +45 -2
  240. package/app/lib/i18n/modules/ai-chat.ts +97 -10
  241. package/app/lib/i18n/modules/onboarding.ts +12 -12
  242. package/app/lib/i18n/modules/panels.ts +10 -2
  243. package/app/lib/mcp-agents.ts +10 -0
  244. package/app/lib/stores/LocaleStoreInit.tsx +24 -1
  245. package/app/lib/stores/locale-store.ts +20 -6
  246. package/app/lib/types.ts +1 -0
  247. package/bin/lib/mcp-agents.js +10 -0
  248. package/package.json +1 -1
  249. package/skills/mindos/SKILL.md +69 -11
  250. package/skills/mindos/references/knowledge-health.md +120 -0
  251. package/skills/mindos-max/SKILL.md +238 -0
  252. package/skills/mindos-max-workspace/evals/evals.json +23 -0
  253. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/eval_metadata.json +11 -0
  254. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/old_skill/grading.json +28 -0
  255. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/old_skill/outputs/transcript.md +203 -0
  256. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/with_skill/grading.json +28 -0
  257. package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/with_skill/outputs/transcript.md +271 -0
  258. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/eval_metadata.json +11 -0
  259. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/old_skill/grading.json +28 -0
  260. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/old_skill/outputs/transcript.md +121 -0
  261. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/with_skill/grading.json +28 -0
  262. package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/with_skill/outputs/transcript.md +168 -0
  263. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/eval_metadata.json +11 -0
  264. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/old_skill/grading.json +28 -0
  265. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/old_skill/outputs/transcript.md +143 -0
  266. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/with_skill/grading.json +28 -0
  267. package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/with_skill/outputs/transcript.md +233 -0
  268. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/SKILL.md +165 -0
  269. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/README.md +12 -0
  270. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/post-task-hooks.md +27 -0
  271. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/preference-capture.md +41 -0
  272. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/sop-template.md +74 -0
  273. package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/write-supplement.md +119 -0
  274. package/skills/mindos-max-zh/SKILL.md +241 -0
  275. package/skills/mindos-zh/SKILL.md +72 -8
  276. package/_standalone/.next/server/chunks/2364.js +0 -2
  277. package/_standalone/.next/server/chunks/357.js +0 -1
  278. package/_standalone/.next/static/chunks/1053-5cb008a24930e271.js +0 -29
  279. package/_standalone/.next/static/chunks/178-105779afb62d36d9.js +0 -1
  280. package/_standalone/.next/static/chunks/2218-d54538000574ffef.js +0 -1
  281. package/_standalone/.next/static/chunks/2549-e63cf57fa927a41d.js +0 -1
  282. package/_standalone/.next/static/chunks/7249-8cd568ad23656622.js +0 -11
  283. package/_standalone/.next/static/chunks/9274-296ab35f9f09e42e.js +0 -1
  284. package/_standalone/.next/static/chunks/app/agents/page-5d1446665ddb3801.js +0 -1
  285. package/_standalone/.next/static/chunks/app/echo/[segment]/page-b0103509ce34444b.js +0 -11
  286. package/_standalone/.next/static/chunks/app/layout-b3919384ec2eb979.js +0 -186
  287. package/_standalone/.next/static/chunks/app/page-6436a99cda35132b.js +0 -7
  288. package/_standalone/.next/static/chunks/app/trash/page-8dc388695344fdd4.js +0 -1
  289. package/_standalone/.next/static/chunks/app/view/[...path]/page-b292b55305ecc021.js +0 -12
  290. package/_standalone/.next/static/chunks/app/wiki/page-d492256a93f0b8bc.js +0 -1
  291. package/_standalone/.next/static/css/fd84c8316ead16eb.css +0 -1
  292. /package/_standalone/.next/static/{zOaEtgJbdRMncnCBucULp → u8p6oIRTcr_ns-ElNZ9rl}/_buildManifest.js +0 -0
  293. /package/_standalone/.next/static/{zOaEtgJbdRMncnCBucULp → u8p6oIRTcr_ns-ElNZ9rl}/_ssgManifest.js +0 -0
@@ -1,623 +1,164 @@
1
1
  'use client';
2
2
 
3
- import Link from 'next/link';
4
- import { FileText, Table, Clock, Sparkles, ArrowRight, FilePlus, Search, ChevronDown, Folder, Brain, Plus, Trash2, Check, Loader2, X, FolderInput, History, Star } from 'lucide-react';
5
- import { useState, useEffect, useMemo, useCallback } from 'react';
3
+ import { useState, useCallback } from 'react';
6
4
  import { useLocale } from '@/lib/stores/locale-store';
7
- import { encodePath, relativeTime, extractEmoji, stripEmoji } from '@/lib/utils';
8
- import { usePinnedFiles } from '@/lib/hooks/usePinnedFiles';
5
+ import { FolderSync, PenLine, BarChart3, Sparkles, ArrowUpRight } from 'lucide-react';
9
6
  import OnboardingView from './OnboardingView';
10
7
  import Logo from './Logo';
11
8
  import GuideCard from './GuideCard';
12
- import SystemPulse from './SystemPulse';
13
- import { InboxSection } from './home/InboxSection';
14
- import { scanExampleFilesAction, cleanupExamplesAction } from '@/lib/actions';
9
+ import AskContent from '@/components/ask/AskContent';
15
10
  import type { SpaceInfo } from '@/app/page';
16
- import RecentActivityFeed from '@/components/agents/RecentActivityFeed';
17
11
 
18
12
  interface RecentFile {
19
13
  path: string;
20
14
  mtime: number;
21
15
  }
22
16
 
23
- interface SpaceGroup {
24
- space: string;
25
- spacePath: string;
26
- files: RecentFile[];
27
- latestMtime: number;
28
- totalFiles: number;
17
+ function injectAskInput(text: string) {
18
+ window.dispatchEvent(new CustomEvent('mindos:home-suggestion', { detail: { text } }));
29
19
  }
30
20
 
31
- function triggerSearch() {
32
- window.dispatchEvent(new KeyboardEvent('keydown', { key: 'k', metaKey: true, bubbles: true }));
33
- }
34
-
35
- function triggerAsk() {
36
- window.dispatchEvent(new KeyboardEvent('keydown', { key: '/', metaKey: true, bubbles: true }));
37
- }
38
-
39
- /** Group recent files by their top-level directory (Space) */
40
- function groupBySpace(recent: RecentFile[], spaces: SpaceInfo[]): { groups: SpaceGroup[]; rootFiles: RecentFile[] } {
41
- const groupMap = new Map<string, SpaceGroup>();
42
- const rootFiles: RecentFile[] = [];
43
-
44
- for (const file of recent) {
45
- const parts = file.path.split('/');
46
- if (parts.length < 2) {
47
- rootFiles.push(file);
48
- continue;
49
- }
50
- const spaceName = parts[0];
51
- const spaceInfo = spaces.find(s => s.name === spaceName);
52
-
53
- if (!groupMap.has(spaceName)) {
54
- groupMap.set(spaceName, {
55
- space: spaceName,
56
- spacePath: spaceName + '/',
57
- files: [],
58
- latestMtime: 0,
59
- totalFiles: spaceInfo?.fileCount ?? 0,
60
- });
61
- }
62
- const g = groupMap.get(spaceName)!;
63
- g.files.push(file);
64
- g.latestMtime = Math.max(g.latestMtime, file.mtime);
65
- }
66
-
67
- const groups = [...groupMap.values()].sort((a, b) => b.latestMtime - a.latestMtime);
68
- return { groups, rootFiles };
69
- }
70
-
71
- /* ── Shared small components ── */
72
-
73
- interface SectionTitleProps {
74
- icon: React.ReactNode;
75
- children: React.ReactNode;
76
- count?: number;
77
- action?: React.ReactNode;
78
- }
79
-
80
- function SectionTitle({ icon, children, count, action }: SectionTitleProps) {
81
- return (
82
- <div className="flex items-center gap-2.5 mb-5">
83
- <div className="flex items-center justify-center w-6 h-6 rounded-md bg-[var(--amber-subtle)] text-[var(--amber)]">
84
- {icon}
85
- </div>
86
- <h2 className="text-[13px] font-semibold text-foreground tracking-wide">
87
- {children}
88
- </h2>
89
- {count != null && count > 0 && (
90
- <span className="inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 text-[10px] font-semibold rounded-full bg-muted text-muted-foreground tabular-nums">{count}</span>
91
- )}
92
- {action ? <div className="ml-auto">{action}</div> : null}
93
- </div>
94
- );
95
- }
96
-
97
- /** Reusable "Show more / Show less" toggle */
98
- function ToggleButton({ expanded, onToggle, showLabel, hideLabel, className = '' }: {
99
- expanded: boolean;
100
- onToggle: () => void;
101
- showLabel: string;
102
- hideLabel: string;
103
- className?: string;
104
- }) {
105
- return (
106
- <button
107
- onClick={onToggle}
108
- aria-expanded={expanded}
109
- className={`flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer ${className}`}
110
- >
111
- <ChevronDown size={12} className={`transition-transform duration-200 ${expanded ? 'rotate-180' : ''}`} />
112
- <span>{expanded ? hideLabel : showLabel}</span>
113
- </button>
114
- );
115
- }
116
-
117
- /** Reusable file row for recent-file lists */
118
- function FileRow({ filePath, mtime, formatTime, subPath }: {
119
- filePath: string;
120
- mtime: number;
121
- formatTime: (t: number) => string;
122
- subPath?: string;
123
- }) {
124
- const isCSV = filePath.endsWith('.csv');
125
- const name = filePath.split('/').pop() || filePath;
126
- return (
127
- <Link
128
- href={`/view/${encodePath(filePath)}`}
129
- className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted group overflow-hidden"
130
- >
131
- {isCSV
132
- ? <Table size={12} className="shrink-0 text-success" />
133
- : <FileText size={12} className="shrink-0 text-muted-foreground" />
134
- }
135
- <div className="flex-1 min-w-0">
136
- <span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
137
- {subPath && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{subPath}</span>}
138
- </div>
139
- <span className="text-xs shrink-0 tabular-nums text-muted-foreground/40" suppressHydrationWarning>
140
- {formatTime(mtime)}
141
- </span>
142
- </Link>
143
- );
144
- }
145
-
146
- const FILES_PER_GROUP = 3;
147
- const SPACES_PER_ROW = 6;
21
+ const TAB_ICONS = [FolderSync, PenLine, BarChart3, Sparkles];
148
22
 
149
23
  export default function HomeContent({ recent, existingFiles, spaces }: { recent: RecentFile[]; existingFiles?: string[]; spaces?: SpaceInfo[] }) {
150
24
  const { t } = useLocale();
151
- const [showAll, setShowAll] = useState(false);
152
- const [showAllSpaces, setShowAllSpaces] = useState(false);
153
- const [suggestionIdx, setSuggestionIdx] = useState(0);
25
+ const [activeTab, setActiveTab] = useState(0);
26
+ const [maximized, setMaximized] = useState(false);
154
27
 
155
- const suggestions = t.ask?.suggestions ?? [
156
- 'Summarize this document',
157
- 'List all action items and TODOs',
158
- 'What are the key points?',
159
- 'Find related notes on this topic',
160
- ];
28
+ const toggleMaximize = useCallback(() => setMaximized(v => !v), []);
161
29
 
162
- useEffect(() => {
163
- const interval = setInterval(() => {
164
- setSuggestionIdx(i => (i + 1) % suggestions.length);
165
- }, 4000);
166
- return () => clearInterval(interval);
167
- }, [suggestions.length]);
168
-
169
- const spaceList = spaces ?? [];
170
- const { groups, rootFiles } = useMemo(() => groupBySpace(recent, spaceList), [recent, spaceList]);
30
+ // Auto-fullscreen when user sends the first message in a session
31
+ const handleFirstMessage = useCallback(() => {
32
+ setMaximized(true);
33
+ }, []);
171
34
 
172
35
  if (recent.length === 0) {
173
36
  return <OnboardingView />;
174
37
  }
175
38
 
176
- const formatTime = (mtime: number) => relativeTime(mtime, t.home.relativeTime);
39
+ const categories: { label: string; items: { label: string; desc: string; prompt: string }[] }[] =
40
+ (t.ask as Record<string, unknown>)?.homeCategories as typeof categories ?? [];
177
41
 
178
- const lastFile = recent[0];
42
+ const current = categories[activeTab];
179
43
 
44
+ /*
45
+ * Single render tree — AskContent is always mounted in the same position.
46
+ * Normal vs fullscreen is purely a CSS layout change, so chat state is preserved.
47
+ */
180
48
  return (
181
- <div className="content-width px-4 md:px-6 py-10 md:py-14">
182
- <GuideCard />
183
- <ExampleCleanupBanner />
49
+ <div className="flex flex-col h-[100dvh]">
50
+
51
+ {/* ── Landing chrome: hidden when maximized ── */}
52
+ {!maximized && (
53
+ <>
54
+ {/* Guide Card */}
55
+ <div className="flex-shrink-0 px-4 md:px-6 pt-4 pb-6">
56
+ <div className="max-w-4xl mx-auto">
57
+ <GuideCard />
58
+ </div>
59
+ </div>
184
60
 
185
- {/* ══════════ Hero ══════════ */}
186
- <div className="mb-14">
187
- {/* Brand mark */}
188
- <div className="flex items-center gap-5 mb-1">
189
- <Logo id="home-hero" className="w-14 h-7 opacity-90" />
190
- <h1 className="text-[2rem] font-brand leading-none">
191
- <span className="text-foreground">Mind</span><span className="text-[var(--amber)]">OS</span>
192
- </h1>
193
- </div>
194
- <p className="text-sm text-muted-foreground/50 mt-3 max-w-md leading-relaxed">
195
- {t.app.tagline}
196
- </p>
61
+ {/* Spacer top */}
62
+ <div className="flex-1 min-h-0" />
197
63
 
198
- {/* Command bar — the single most important action */}
199
- <div className="w-full max-w-xl flex flex-col sm:flex-row items-stretch sm:items-center gap-2 mt-8">
200
- <button
201
- onClick={triggerAsk}
202
- title="⌘/"
203
- data-walkthrough="ask-button"
204
- className="flex-1 flex items-center gap-3 px-4 py-3.5 rounded-xl border border-border/50 shadow-sm bg-card/80 backdrop-blur-sm transition-all duration-200 hover:border-[var(--amber)]/40 hover:shadow-md hover:-translate-y-0.5 group"
205
- >
206
- <Sparkles size={16} className="shrink-0 text-[var(--amber)] group-hover:scale-110 transition-transform duration-150" />
207
- <div className="flex-1 min-h-[1.5rem] flex items-center">
208
- <span
209
- key={suggestionIdx}
210
- className="text-sm text-left text-muted-foreground animate-in fade-in duration-300"
211
- >
212
- {suggestions[suggestionIdx]}
213
- </span>
64
+ {/* Hero */}
65
+ <div className="flex-shrink-0 flex flex-col items-center text-center px-4 md:px-6 pb-8">
66
+ <div className="flex items-center gap-4 mb-3">
67
+ <Logo id="home-hero" className="w-10 h-5 opacity-90" />
68
+ <h1 className="text-2xl font-brand leading-none">
69
+ <span className="text-foreground">Mind</span><span className="text-[var(--amber)]">OS</span>
70
+ </h1>
214
71
  </div>
215
- <kbd className="hidden sm:inline-flex items-center gap-0.5 px-2 py-0.5 rounded text-xs font-mono font-medium bg-[var(--amber-dim)] text-[var(--amber-text)]">
216
- ⌘/
217
- </kbd>
218
- </button>
219
- <button
220
- onClick={triggerSearch}
221
- title="⌘K"
222
- className="flex items-center gap-2 px-3.5 py-3.5 rounded-xl border border-border/50 text-sm text-muted-foreground transition-all duration-200 shrink-0 hover:bg-muted/60 hover:shadow-sm hover:-translate-y-0.5"
223
- >
224
- <Search size={14} />
225
- <kbd className="hidden sm:inline-flex items-center px-1.5 py-0.5 rounded text-xs font-mono bg-muted">
226
- ⌘K
227
- </kbd>
228
- </button>
229
- </div>
72
+ <p className="text-sm text-muted-foreground/50 max-w-sm leading-relaxed">
73
+ {t.app.tagline}
74
+ </p>
75
+ </div>
76
+ </>
77
+ )}
230
78
 
231
- {/* Quick actions only 2: New + Continue */}
232
- <div className="flex items-center gap-3 mt-5">
233
- <Link
234
- href="/view/Untitled.md"
235
- className="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 hover:shadow-md hover:-translate-y-0.5 bg-[var(--amber)] text-[var(--amber-foreground)]"
236
- >
237
- <FilePlus size={14} />
238
- <span>{t.home.newNote}</span>
239
- </Link>
240
- {lastFile && (
241
- <Link
242
- href={`/view/${encodePath(lastFile.path)}`}
243
- className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors text-muted-foreground hover:text-foreground hover:bg-muted"
244
- >
245
- <ArrowRight size={14} className="text-[var(--amber)]/60" />
246
- <span>{t.home.continueEditing}</span>
247
- <span className="text-xs opacity-40 truncate max-w-32" suppressHydrationWarning>
248
- {lastFile.path.split('/').pop()}
249
- </span>
250
- </Link>
251
- )}
79
+ {/* ── Chatbot area: always mounted, layout changes with maximized ── */}
80
+ <div className={
81
+ maximized
82
+ ? 'flex-1 min-h-0 flex flex-col overflow-hidden'
83
+ : 'flex-shrink-0 px-4 md:px-6 flex justify-center'
84
+ }>
85
+ <div className={maximized ? 'flex-1 min-h-0 flex flex-col overflow-hidden' : 'w-full max-w-4xl'}>
86
+ <div className={maximized ? 'flex-1 min-h-0 flex flex-col overflow-hidden' : 'rounded-xl border border-border/50 shadow-sm overflow-hidden flex flex-col max-h-[50vh]'}>
87
+ <AskContent
88
+ visible={true}
89
+ variant="home"
90
+ maximized={maximized}
91
+ onMaximize={toggleMaximize}
92
+ onFirstMessage={handleFirstMessage}
93
+ />
94
+ </div>
252
95
  </div>
253
96
  </div>
254
97
 
255
- {/* ══════════ Knowledge Pulse ══════════ */}
256
- <SystemPulse />
257
-
258
- {/* ══════════ Recent Agent Activity ══════════ */}
259
- <div className="mb-10">
260
- <RecentActivityFeed />
261
- </div>
262
-
263
- {/* ── Visual divider ── */}
264
- <div className="border-t border-border/30 mb-10" />
265
-
266
- {/* ══════════ Inbox ══════════ */}
267
- <InboxSection />
98
+ {/* ── Bottom chrome: hidden when maximized ── */}
99
+ {!maximized && (
100
+ <>
101
+ {/* Tabs + Prompt Grid */}
102
+ {categories.length > 0 && current && (
103
+ <div className="flex-shrink-0 flex justify-center px-4 md:px-6 pt-6">
104
+ <div className="w-full max-w-4xl">
105
+
106
+ {/* Pill Tabs */}
107
+ <div className="flex items-center justify-center gap-1.5 mb-5">
108
+ {categories.map((cat, i) => {
109
+ const Icon = TAB_ICONS[i % TAB_ICONS.length];
110
+ const isActive = i === activeTab;
111
+ return (
112
+ <button
113
+ key={cat.label}
114
+ type="button"
115
+ onClick={() => setActiveTab(i)}
116
+ className={`flex items-center gap-1.5 px-4 py-2 text-xs font-medium rounded-full transition-all duration-150 ${
117
+ isActive
118
+ ? 'bg-[var(--amber)]/12 text-[var(--amber)]'
119
+ : 'text-muted-foreground/50 hover:text-muted-foreground hover:bg-muted/40'
120
+ }`}
121
+ >
122
+ <Icon size={13} />
123
+ <span>{cat.label}</span>
124
+ </button>
125
+ );
126
+ })}
127
+ </div>
268
128
 
269
- {/* ══════════ Spaces ══════════ */}
270
- {(spaceList.length > 0 || true) && (
271
- <section className="mb-12">
272
- <SectionTitle
273
- icon={<Brain size={14} />}
274
- count={spaceList.length > 0 ? spaceList.length : undefined}
275
- action={<CreateSpaceButton t={t} />}
276
- >
277
- {t.home.spaces}
278
- </SectionTitle>
279
- {spaceList.length > 0 ? (
280
- <>
281
- <div className="grid grid-cols-2 sm:grid-cols-3 gap-2.5">
282
- {(showAllSpaces ? spaceList : spaceList.slice(0, SPACES_PER_ROW)).map(s => {
283
- const emoji = extractEmoji(s.name);
284
- const label = stripEmoji(s.name);
285
- const isEmpty = s.fileCount === 0;
286
- return (
287
- <Link
288
- key={s.name}
289
- href={`/view/${encodePath(s.path)}`}
290
- className={`flex items-start gap-3 px-4 py-3.5 rounded-xl border transition-all duration-200 ${
291
- isEmpty
292
- ? 'border-dashed border-border/50 opacity-50 hover:opacity-70'
293
- : 'border-border/60 hover:border-[var(--amber)]/30 hover:shadow-md hover:-translate-y-0.5 bg-card/40'
294
- }`}
129
+ {/* Prompt Cards 2x2 grid */}
130
+ <div className="grid grid-cols-2 gap-2">
131
+ {current.items.map((item, i) => (
132
+ <button
133
+ key={`${activeTab}-${i}`}
134
+ type="button"
135
+ onClick={() => injectAskInput(item.prompt)}
136
+ className="group relative text-left px-4 py-3.5 rounded-xl border border-border/30 hover:border-border/60 transition-all duration-150 hover:shadow-sm"
295
137
  >
296
- {emoji ? (
297
- <span className="text-lg leading-none shrink-0 mt-0.5" suppressHydrationWarning>{emoji}</span>
298
- ) : (
299
- <Folder size={16} className="shrink-0 text-[var(--amber)] mt-0.5" />
300
- )}
301
- <div className="min-w-0 flex-1">
302
- <span className="text-sm font-medium truncate block text-foreground">{label}</span>
303
- {s.description && (
304
- <span className="text-xs text-muted-foreground line-clamp-1 mt-0.5" suppressHydrationWarning>{s.description}</span>
305
- )}
306
- <span className="text-xs text-muted-foreground/50 mt-0.5 block tabular-nums">
307
- {t.home.nFiles(s.fileCount)}
308
- </span>
138
+ <div className="flex items-start justify-between gap-2">
139
+ <div className="min-w-0">
140
+ <div className="text-[13px] font-medium text-foreground/90 leading-snug mb-0.5">{item.label}</div>
141
+ <div className="text-xs text-muted-foreground/60 leading-relaxed">{item.desc}</div>
142
+ </div>
143
+ <ArrowUpRight size={14} className="shrink-0 mt-0.5 text-muted-foreground/20 group-hover:text-[var(--amber)] transition-colors" />
309
144
  </div>
310
- </Link>
311
- );
312
- })}
313
- </div>
314
- {spaceList.length > SPACES_PER_ROW && (
315
- <ToggleButton
316
- expanded={showAllSpaces}
317
- onToggle={() => setShowAllSpaces(v => !v)}
318
- showLabel={t.home.showMore}
319
- hideLabel={t.home.showLess}
320
- className="mt-2"
321
- />
322
- )}
323
- </>
324
- ) : (
325
- <p className="text-xs text-muted-foreground py-2">
326
- {t.home.noSpacesYet ?? 'No spaces yet. Create one to organize your knowledge.'}
327
- </p>
328
- )}
329
- </section>
330
- )}
331
-
332
- {/* ══════════ Pinned Files ══════════ */}
333
- <PinnedFilesSection formatTime={formatTime} />
334
-
335
- {/* ── Visual divider ── */}
336
- <div className="border-t border-border/30 mb-10" />
337
-
338
- {/* ══════════ Recently Edited ══════════ */}
339
- {recent.length > 0 && (
340
- <section className="mb-12">
341
- <SectionTitle
342
- icon={<Clock size={14} />}
343
- count={recent.length}
344
- action={
345
- <Link
346
- href="/changes"
347
- className="flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80"
348
- >
349
- <History size={12} />
350
- <span>{t.home.changeHistory}</span>
351
- </Link>
352
- }
353
- >
354
- {t.home.recentlyEdited}
355
- </SectionTitle>
356
-
357
- {groups.length > 0 ? (
358
- <div className="flex flex-col gap-3">
359
- {groups.map((group) => {
360
- const visibleFiles = showAll ? group.files : group.files.slice(0, FILES_PER_GROUP);
361
- const hasMoreFiles = group.files.length > FILES_PER_GROUP;
362
- return (
363
- <div key={group.space}>
364
- <Link
365
- href={`/view/${encodePath(group.spacePath)}`}
366
- className="flex items-center gap-2 px-1 py-1.5 rounded-lg group transition-colors hover:bg-muted/50"
367
- >
368
- <Folder size={14} className="shrink-0 text-[var(--amber)]" />
369
- <span className="text-xs font-semibold text-foreground group-hover:text-[var(--amber)] transition-colors" suppressHydrationWarning>
370
- {group.space}
371
- </span>
372
- <span className="text-xs text-muted-foreground/50 tabular-nums" suppressHydrationWarning>
373
- {t.home.nFiles(group.totalFiles)} · {formatTime(group.latestMtime)}
374
- </span>
375
- {hasMoreFiles && !showAll && (
376
- <span className="text-xs text-muted-foreground/30 tabular-nums">
377
- +{group.files.length - FILES_PER_GROUP}
378
- </span>
379
- )}
380
- </Link>
381
- <div className="flex flex-col gap-0.5 ml-2 border-l-2 border-border/20 pl-3">
382
- {visibleFiles.map(({ path: filePath, mtime }) => (
383
- <FileRow
384
- key={filePath}
385
- filePath={filePath}
386
- mtime={mtime}
387
- formatTime={formatTime}
388
- subPath={filePath.split('/').slice(1, -1).join('/')}
389
- />
390
- ))}
391
- </div>
392
- </div>
393
- );
394
- })}
395
-
396
- {rootFiles.length > 0 && (
397
- <div>
398
- <div className="flex items-center gap-2 px-1 py-1.5">
399
- <FileText size={14} className="shrink-0 text-muted-foreground/50" />
400
- <span className="text-xs font-semibold text-muted-foreground/60">
401
- {t.home.other}
402
- </span>
403
- </div>
404
- <div className="flex flex-col gap-0.5 ml-2 border-l-2 border-border/20 pl-3">
405
- {rootFiles.map(({ path: filePath, mtime }) => (
406
- <FileRow key={filePath} filePath={filePath} mtime={mtime} formatTime={formatTime} />
407
- ))}
408
- </div>
145
+ </button>
146
+ ))}
409
147
  </div>
410
- )}
411
-
412
- {groups.some(g => g.files.length > FILES_PER_GROUP) && (
413
- <ToggleButton
414
- expanded={showAll}
415
- onToggle={() => setShowAll(v => !v)}
416
- showLabel={t.home.showMore}
417
- hideLabel={t.home.showLess}
418
- className="mt-1 ml-1"
419
- />
420
- )}
421
- </div>
422
- ) : (
423
- <div className="relative pl-4">
424
- <div className="absolute left-0 top-1 bottom-1 w-0.5 rounded-full bg-gradient-to-b from-[var(--amber)]/20 via-border/30 to-transparent" />
425
- <div className="flex flex-col gap-0.5">
426
- {(showAll ? recent : recent.slice(0, 5)).map(({ path: filePath, mtime }, idx) => {
427
- const isCSV = filePath.endsWith('.csv');
428
- const name = filePath.split('/').pop() || filePath;
429
- const dir = filePath.split('/').slice(0, -1).join('/');
430
- return (
431
- <div key={filePath} className="relative group">
432
- <div
433
- aria-hidden="true"
434
- className={`absolute -left-[5px] top-1/2 -translate-y-1/2 rounded-full transition-all duration-200 group-hover:scale-125 ${
435
- idx === 0
436
- ? 'w-2.5 h-2.5 bg-[var(--amber)] ring-[3px] ring-[var(--amber)]/15 shadow-sm shadow-[var(--amber)]/20'
437
- : 'w-1.5 h-1.5 bg-muted-foreground/25 group-hover:bg-[var(--amber)]/50'
438
- }`}
439
- />
440
- <Link
441
- href={`/view/${encodePath(filePath)}`}
442
- className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 group-hover:translate-x-0.5 hover:bg-muted overflow-hidden"
443
- >
444
- {isCSV
445
- ? <Table size={12} className="shrink-0 text-success" />
446
- : <FileText size={12} className="shrink-0 text-muted-foreground/50" />
447
- }
448
- <div className="flex-1 min-w-0">
449
- <span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
450
- {dir && <span className="text-xs truncate block text-muted-foreground/40" suppressHydrationWarning>{dir}</span>}
451
- </div>
452
- <span className="text-xs shrink-0 tabular-nums text-muted-foreground/40" suppressHydrationWarning>
453
- {formatTime(mtime)}
454
- </span>
455
- </Link>
456
- </div>
457
- );
458
- })}
459
148
  </div>
460
- {recent.length > 5 && (
461
- <ToggleButton
462
- expanded={showAll}
463
- onToggle={() => setShowAll(v => !v)}
464
- showLabel={t.home.showMore}
465
- hideLabel={t.home.showLess}
466
- className="mt-2 ml-3"
467
- />
468
- )}
469
149
  </div>
470
150
  )}
471
- </section>
472
- )}
473
-
474
- {/* Footer */}
475
- <div className="mt-6 py-8 border-t border-border/20 flex items-center justify-center gap-2 text-[11px] text-muted-foreground/25">
476
- <Logo id="home-footer" className="w-5 h-2.5 opacity-30" />
477
- <span>{t.app.footer}</span>
478
- </div>
479
- </div>
480
- );
481
- }
482
151
 
483
- /* ── Pinned Files Section ── */
484
- function PinnedFilesSection({ formatTime }: { formatTime: (t: number) => string }) {
485
- const { t } = useLocale();
486
- const { pinnedFiles, removePin } = usePinnedFiles();
152
+ {/* Spacer bottom */}
153
+ <div className="flex-1 min-h-0" />
487
154
 
488
- if (pinnedFiles.length === 0) {
489
- return (
490
- <section className="mb-12">
491
- <SectionTitle icon={<Star size={14} />}>
492
- {t.pinnedFiles.title}
493
- </SectionTitle>
494
- <div className="py-8 px-6 rounded-xl border border-border/40 bg-card/30 text-center">
495
- <div className="inline-flex items-center justify-center w-10 h-10 rounded-full bg-[var(--amber-subtle)] mb-3">
496
- <Star size={18} className="text-[var(--amber)]/60" />
155
+ {/* Footer */}
156
+ <div className="flex-shrink-0 py-4 flex items-center justify-center gap-2 text-[11px] text-muted-foreground/20">
157
+ <Logo id="home-footer" className="w-4 h-2 opacity-20" />
158
+ <span>{t.app.footer}</span>
497
159
  </div>
498
- <p className="text-sm font-medium text-muted-foreground/70 mb-1">
499
- {t.pinnedFiles.empty ?? 'No pinned files'}
500
- </p>
501
- <p className="text-xs text-muted-foreground/40 max-w-xs mx-auto leading-relaxed">
502
- {t.pinnedFiles.emptyHint ?? 'Click the star icon on any file to pin it here'}
503
- </p>
504
- </div>
505
- </section>
506
- );
507
- }
508
-
509
- return (
510
- <section className="mb-12">
511
- <SectionTitle icon={<Star size={14} />} count={pinnedFiles.length}>
512
- {t.pinnedFiles.title}
513
- </SectionTitle>
514
- <div className="flex flex-col gap-0.5">
515
- {pinnedFiles.map((filePath) => {
516
- const name = filePath.split('/').pop() || filePath;
517
- const dir = filePath.split('/').slice(0, -1).join('/');
518
- const isCSV = filePath.endsWith('.csv');
519
- return (
520
- <div key={filePath} className="group/pin relative">
521
- <Link
522
- href={`/view/${encodePath(filePath)}`}
523
- className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted overflow-hidden"
524
- >
525
- <Star size={12} className="shrink-0 fill-[var(--amber)] text-[var(--amber)]" />
526
- {isCSV
527
- ? <Table size={12} className="shrink-0 text-success" />
528
- : <FileText size={12} className="shrink-0 text-muted-foreground" />
529
- }
530
- <div className="flex-1 min-w-0">
531
- <span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
532
- {dir && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{dir}</span>}
533
- </div>
534
- </Link>
535
- <button
536
- onClick={(e) => { e.preventDefault(); e.stopPropagation(); removePin(filePath); }}
537
- className="absolute right-2 top-1/2 -translate-y-1/2 hidden group-hover/pin:flex p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
538
- title={t.pinnedFiles.removedToast}
539
- >
540
- <X size={12} />
541
- </button>
542
- </div>
543
- );
544
- })}
545
- </div>
546
- </section>
547
- );
548
- }
549
-
550
- /* ── Create Space: title-bar button ── */
551
- function CreateSpaceButton({ t }: { t: ReturnType<typeof useLocale>['t'] }) {
552
- return (
553
- <button
554
- onClick={() => window.dispatchEvent(new Event('mindos:create-space'))}
555
- className="flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer"
556
- >
557
- <Plus size={12} />
558
- <span>{t.home.newSpace}</span>
559
- </button>
560
- );
561
- }
562
-
563
- /* ── Example files cleanup banner ── */
564
- function ExampleCleanupBanner() {
565
- const { t } = useLocale();
566
- const [count, setCount] = useState<number | null>(null);
567
- const [cleaning, setCleaning] = useState(false);
568
- const [done, setDone] = useState(false);
569
- const [dismissed, setDismissed] = useState(false);
570
-
571
- useEffect(() => {
572
- scanExampleFilesAction().then(r => {
573
- if (r.files.length > 0) setCount(r.files.length);
574
- }).catch((err) => { console.warn("[HomeContent] scanExampleFilesAction failed:", err); });
575
- }, []);
576
-
577
- const handleCleanup = useCallback(async () => {
578
- if (count === null) return;
579
- setCleaning(true);
580
- try {
581
- const r = await cleanupExamplesAction();
582
- if (r.success) {
583
- setDone(true);
584
- setTimeout(() => setDismissed(true), 2500);
585
- }
586
- } catch { /* silent — banner stays, user can retry */ }
587
- setCleaning(false);
588
- }, [count]);
589
-
590
- if (dismissed || count === null || count === 0) return null;
591
-
592
- if (done) {
593
- return (
594
- <div className="mb-6 flex items-center gap-2.5 px-4 py-3 rounded-xl border border-success/30 bg-success/5 animate-in fade-in duration-300">
595
- <Check size={14} className="text-success shrink-0" />
596
- <span className="text-xs text-success">{t.home.cleanupExamplesDone}</span>
597
- </div>
598
- );
599
- }
600
-
601
- return (
602
- <div className="mb-6 flex items-center gap-3 px-4 py-3 rounded-xl border border-border bg-muted/30 animate-in fade-in duration-300">
603
- <span className="text-sm leading-none shrink-0">🧪</span>
604
- <span className="text-xs text-muted-foreground flex-1">
605
- {t.home.cleanupExamples(count)}
606
- </span>
607
- <button
608
- onClick={handleCleanup}
609
- disabled={cleaning}
610
- className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-lg transition-colors shrink-0 disabled:opacity-50 bg-[var(--amber-dim)] text-[var(--amber-text)] hover:opacity-80"
611
- >
612
- {cleaning ? <Loader2 size={12} className="animate-spin" /> : <Trash2 size={12} />}
613
- {t.home.cleanupExamplesButton}
614
- </button>
615
- <button
616
- onClick={() => setDismissed(true)}
617
- className="p-1 rounded hover:bg-muted transition-colors text-muted-foreground shrink-0"
618
- >
619
- <X size={12} />
620
- </button>
160
+ </>
161
+ )}
621
162
  </div>
622
163
  );
623
164
  }