@geminilight/mindos 0.6.39 → 0.6.41

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 (759) hide show
  1. package/README.md +31 -15
  2. package/README_zh.md +31 -15
  3. package/_standalone/.mindos-build-version +1 -1
  4. package/_standalone/.next/BUILD_ID +1 -1
  5. package/_standalone/.next/app-path-routes-manifest.json +19 -18
  6. package/_standalone/.next/build-manifest.json +3 -3
  7. package/_standalone/.next/cache/.previewinfo +1 -1
  8. package/_standalone/.next/cache/.rscinfo +1 -1
  9. package/_standalone/.next/cache/config.json +3 -3
  10. package/_standalone/.next/prerender-manifest.json +3 -3
  11. package/_standalone/.next/react-loadable-manifest.json +68 -2
  12. package/_standalone/.next/routes-manifest.json +6 -0
  13. package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
  14. package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  15. package/_standalone/.next/server/app/_global-error.html +2 -2
  16. package/_standalone/.next/server/app/_global-error.rsc +1 -1
  17. package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  18. package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  19. package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  20. package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  21. package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  22. package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  23. package/_standalone/.next/server/app/_not-found/page.js +2 -2
  24. package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  25. package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  26. package/_standalone/.next/server/app/agents/[agentKey]/page.js +2 -2
  27. package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
  28. package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
  29. package/_standalone/.next/server/app/agents/page.js +3 -3
  30. package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
  31. package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  32. package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
  33. package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
  34. package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
  35. package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/config/route.js +1 -1
  37. package/_standalone/.next/server/app/api/acp/config/route.js.nft.json +1 -1
  38. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  39. package/_standalone/.next/server/app/api/acp/detect/route.js +1 -1
  40. package/_standalone/.next/server/app/api/acp/detect/route.js.nft.json +1 -1
  41. package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
  42. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
  43. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  44. package/_standalone/.next/server/app/api/acp/session/route.js +1 -1
  45. package/_standalone/.next/server/app/api/acp/session/route.js.nft.json +1 -1
  46. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  47. package/_standalone/.next/server/app/api/agent-activity/route.js +1 -1
  48. package/_standalone/.next/server/app/api/agent-activity/route.js.nft.json +1 -1
  49. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  50. package/_standalone/.next/server/app/api/ask/route.js +137 -99
  51. package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
  52. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  54. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  55. package/_standalone/.next/server/app/api/backlinks/route.js +1 -1
  56. package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
  57. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/bootstrap/route.js +1 -1
  59. package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
  60. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  61. package/_standalone/.next/server/app/api/changes/route.js +1 -1
  62. package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
  63. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/export/route.js +3 -3
  65. package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
  66. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  68. package/_standalone/.next/server/app/api/file/import/route.js +2 -19
  69. package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
  70. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/file/route.js +1 -18
  72. package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
  73. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  74. package/_standalone/.next/server/app/api/files/route.js +1 -1
  75. package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  76. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  77. package/_standalone/.next/server/app/api/git/route.js +1 -1
  78. package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  79. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/graph/route.js +1 -1
  81. package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
  82. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  83. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/inbox/route.js +1 -0
  85. package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -0
  86. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -0
  87. package/_standalone/.next/server/app/api/init/route.js +1 -1
  88. package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
  89. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  90. package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
  91. package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
  92. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  93. package/_standalone/.next/server/app/api/mcp/install/route.js +1 -1
  94. package/_standalone/.next/server/app/api/mcp/install/route.js.nft.json +1 -1
  95. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  96. package/_standalone/.next/server/app/api/mcp/install-skill/route.js.nft.json +1 -1
  97. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  98. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  99. package/_standalone/.next/server/app/api/mcp/status/route.js +1 -1
  100. package/_standalone/.next/server/app/api/mcp/status/route.js.nft.json +1 -1
  101. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  102. package/_standalone/.next/server/app/api/monitoring/route.js +1 -1
  103. package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
  104. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  105. package/_standalone/.next/server/app/api/recent-files/route.js +1 -1
  106. package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
  107. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  108. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  109. package/_standalone/.next/server/app/api/search/route.js +1 -1
  110. package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  111. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  112. package/_standalone/.next/server/app/api/settings/list-models/route.js +1 -1
  113. package/_standalone/.next/server/app/api/settings/list-models/route.js.nft.json +1 -1
  114. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  115. package/_standalone/.next/server/app/api/settings/reset-token/route.js +1 -1
  116. package/_standalone/.next/server/app/api/settings/reset-token/route.js.nft.json +1 -1
  117. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  118. package/_standalone/.next/server/app/api/settings/route.js +1 -1
  119. package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  120. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  121. package/_standalone/.next/server/app/api/settings/test-key/route.js +1 -1
  122. package/_standalone/.next/server/app/api/settings/test-key/route.js.nft.json +1 -1
  123. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  124. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  125. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  126. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  127. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  128. package/_standalone/.next/server/app/api/setup/route.js +1 -1
  129. package/_standalone/.next/server/app/api/setup/route.js.nft.json +1 -1
  130. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  131. package/_standalone/.next/server/app/api/skills/route.js +2 -2
  132. package/_standalone/.next/server/app/api/skills/route.js.nft.json +1 -1
  133. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  134. package/_standalone/.next/server/app/api/sync/route.js +1 -1
  135. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  136. package/_standalone/.next/server/app/api/tree-version/route.js +1 -1
  137. package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
  138. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  139. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  140. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  141. package/_standalone/.next/server/app/api/update-check/route.js +1 -1
  142. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  143. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  144. package/_standalone/.next/server/app/api/workflows/route.js +2 -2
  145. package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
  146. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  147. package/_standalone/.next/server/app/changes/page.js +2 -2
  148. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  149. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  150. package/_standalone/.next/server/app/echo/[segment]/page.js +6 -6
  151. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  152. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  153. package/_standalone/.next/server/app/echo/page.js +2 -2
  154. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  155. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  156. package/_standalone/.next/server/app/explore/page.js +3 -3
  157. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  158. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  159. package/_standalone/.next/server/app/help/page.js +2 -2
  160. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  161. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  162. package/_standalone/.next/server/app/login/page.js +2 -2
  163. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  164. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  165. package/_standalone/.next/server/app/page.js +3 -3
  166. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  167. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  168. package/_standalone/.next/server/app/setup/page.js +2 -2
  169. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  170. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  171. package/_standalone/.next/server/app/trash/page.js +3 -3
  172. package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
  173. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  174. package/_standalone/.next/server/app/view/[...path]/page.js +4 -4
  175. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  176. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  177. package/_standalone/.next/server/app-paths-manifest.json +19 -18
  178. package/_standalone/.next/server/chunks/1550.js +1 -1
  179. package/_standalone/.next/server/chunks/1750.js +1 -0
  180. package/_standalone/.next/server/chunks/{9414.js → 2190.js} +1 -1
  181. package/_standalone/.next/server/chunks/2536.js +52 -0
  182. package/_standalone/.next/server/chunks/5648.js +2 -0
  183. package/_standalone/.next/server/chunks/6539.js +1 -1
  184. package/_standalone/.next/server/chunks/8388.js +15 -0
  185. package/_standalone/.next/server/chunks/953.js +42 -2
  186. package/_standalone/.next/server/chunks/9539.js +219 -0
  187. package/_standalone/.next/server/functions-config-manifest.json +2 -1
  188. package/_standalone/.next/server/instrumentation.js +1 -1
  189. package/_standalone/.next/server/middleware-build-manifest.js +1 -1
  190. package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  191. package/_standalone/.next/server/pages/500.html +2 -2
  192. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  193. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  194. package/_standalone/.next/static/Ij3PFh-a0zi5K_ANoSAW0/_buildManifest.js +1 -0
  195. package/_standalone/.next/static/chunks/1053-b70535785cc5aaee.js +29 -0
  196. package/_standalone/.next/static/chunks/1239.10a0710c2772ab34.js +1 -0
  197. package/_standalone/.next/static/chunks/{1814.e2da5460ded71d71.js → 1814.2ee1d03297c0bccd.js} +1 -1
  198. package/_standalone/.next/static/chunks/{1384-55276d40a9da4e88.js → 1880-c2a9e76201841c86.js} +2 -2
  199. package/_standalone/.next/static/chunks/{1a258343-030e4d6735874dd4.js → 1a258343-9803591e4aaee1f6.js} +1 -1
  200. package/_standalone/.next/static/chunks/2631.dc56e83472bde281.js +1 -0
  201. package/_standalone/.next/static/chunks/2872.045858d00bd8307f.js +8 -0
  202. package/_standalone/.next/static/chunks/2968.f10ccee9e7e2324d.js +2 -0
  203. package/_standalone/.next/static/chunks/3160-83a7e0b94414b3ac.js +1 -0
  204. package/_standalone/.next/static/chunks/3637.0541ac2d0ea7de1f.js +1 -0
  205. package/_standalone/.next/static/chunks/4033.6666700547b20141.js +1 -0
  206. package/_standalone/.next/static/chunks/4563-b2a2ce80aff845af.js +6 -0
  207. package/_standalone/.next/static/chunks/516.24ee058b1d4b1fed.js +8 -0
  208. package/_standalone/.next/static/chunks/5627.c4337d7289acb31f.js +1 -0
  209. package/_standalone/.next/static/chunks/5956.b445072b35915129.js +1 -0
  210. package/_standalone/.next/static/chunks/6357-c645842834c0d4cd.js +1 -0
  211. package/_standalone/.next/static/chunks/6826.7b7d94dd0fd83812.js +1 -0
  212. package/_standalone/.next/static/chunks/{8409-de5726a4a278d28f.js → 6926-4af497b83952fa87.js} +1 -1
  213. package/_standalone/.next/static/chunks/6981-3d7dcac2d12a5670.js +1 -0
  214. package/_standalone/.next/static/chunks/7144-5febf62f1a79fe64.js +1 -0
  215. package/_standalone/.next/static/chunks/7266-bb7be1128eccd48e.js +13 -0
  216. package/_standalone/.next/static/chunks/7753.63831cfc54a55fbb.js +1 -0
  217. package/_standalone/.next/static/chunks/862.9f526e964489e2e5.js +1 -0
  218. package/_standalone/.next/static/chunks/9300.118b8c840634383f.js +28 -0
  219. package/_standalone/.next/static/chunks/95247769.3b5caae1c1a76ce1.js +4 -0
  220. package/_standalone/.next/static/chunks/9602-423291fdb36396d1.js +1 -0
  221. package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/route-400c3c09b1540c14.js +1 -0
  222. package/_standalone/.next/static/chunks/app/_global-error/page-400c3c09b1540c14.js +1 -0
  223. package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-773071a99c4daac2.js +1 -0
  224. package/_standalone/.next/static/chunks/app/agents/page-6102a884b2cb3cfe.js +5 -0
  225. package/_standalone/.next/static/chunks/app/api/a2a/agents/route-400c3c09b1540c14.js +1 -0
  226. package/_standalone/.next/static/chunks/app/api/a2a/delegations/route-400c3c09b1540c14.js +1 -0
  227. package/_standalone/.next/static/chunks/app/api/a2a/discover/route-400c3c09b1540c14.js +1 -0
  228. package/_standalone/.next/static/chunks/app/api/a2a/route-400c3c09b1540c14.js +1 -0
  229. package/_standalone/.next/static/chunks/app/api/acp/config/route-400c3c09b1540c14.js +1 -0
  230. package/_standalone/.next/static/chunks/app/api/acp/detect/route-400c3c09b1540c14.js +1 -0
  231. package/_standalone/.next/static/chunks/app/api/acp/install/route-400c3c09b1540c14.js +1 -0
  232. package/_standalone/.next/static/chunks/app/api/acp/registry/route-400c3c09b1540c14.js +1 -0
  233. package/_standalone/.next/static/chunks/app/api/acp/session/route-400c3c09b1540c14.js +1 -0
  234. package/_standalone/.next/static/chunks/app/api/agent-activity/route-400c3c09b1540c14.js +1 -0
  235. package/_standalone/.next/static/chunks/app/api/ask/route-400c3c09b1540c14.js +1 -0
  236. package/_standalone/.next/static/chunks/app/api/ask-sessions/route-400c3c09b1540c14.js +1 -0
  237. package/_standalone/.next/static/chunks/app/api/auth/route-400c3c09b1540c14.js +1 -0
  238. package/_standalone/.next/static/chunks/app/api/backlinks/route-400c3c09b1540c14.js +1 -0
  239. package/_standalone/.next/static/chunks/app/api/bootstrap/route-400c3c09b1540c14.js +1 -0
  240. package/_standalone/.next/static/chunks/app/api/changes/route-400c3c09b1540c14.js +1 -0
  241. package/_standalone/.next/static/chunks/app/api/export/route-400c3c09b1540c14.js +1 -0
  242. package/_standalone/.next/static/chunks/app/api/extract-pdf/route-400c3c09b1540c14.js +1 -0
  243. package/_standalone/.next/static/chunks/app/api/file/import/route-400c3c09b1540c14.js +1 -0
  244. package/_standalone/.next/static/chunks/app/api/file/route-400c3c09b1540c14.js +1 -0
  245. package/_standalone/.next/static/chunks/app/api/files/route-400c3c09b1540c14.js +1 -0
  246. package/_standalone/.next/static/chunks/app/api/git/route-400c3c09b1540c14.js +1 -0
  247. package/_standalone/.next/static/chunks/app/api/graph/route-400c3c09b1540c14.js +1 -0
  248. package/_standalone/.next/static/chunks/app/api/health/route-400c3c09b1540c14.js +1 -0
  249. package/_standalone/.next/static/chunks/app/api/inbox/route-400c3c09b1540c14.js +1 -0
  250. package/_standalone/.next/static/chunks/app/api/init/route-400c3c09b1540c14.js +1 -0
  251. package/_standalone/.next/static/chunks/app/api/mcp/agents/route-400c3c09b1540c14.js +1 -0
  252. package/_standalone/.next/static/chunks/app/api/mcp/install/route-400c3c09b1540c14.js +1 -0
  253. package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-400c3c09b1540c14.js +1 -0
  254. package/_standalone/.next/static/chunks/app/api/mcp/restart/route-400c3c09b1540c14.js +1 -0
  255. package/_standalone/.next/static/chunks/app/api/mcp/status/route-400c3c09b1540c14.js +1 -0
  256. package/_standalone/.next/static/chunks/app/api/monitoring/route-400c3c09b1540c14.js +1 -0
  257. package/_standalone/.next/static/chunks/app/api/recent-files/route-400c3c09b1540c14.js +1 -0
  258. package/_standalone/.next/static/chunks/app/api/restart/route-400c3c09b1540c14.js +1 -0
  259. package/_standalone/.next/static/chunks/app/api/search/route-400c3c09b1540c14.js +1 -0
  260. package/_standalone/.next/static/chunks/app/api/settings/list-models/route-400c3c09b1540c14.js +1 -0
  261. package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-400c3c09b1540c14.js +1 -0
  262. package/_standalone/.next/static/chunks/app/api/settings/route-400c3c09b1540c14.js +1 -0
  263. package/_standalone/.next/static/chunks/app/api/settings/test-key/route-400c3c09b1540c14.js +1 -0
  264. package/_standalone/.next/static/chunks/app/api/setup/check-path/route-400c3c09b1540c14.js +1 -0
  265. package/_standalone/.next/static/chunks/app/api/setup/check-port/route-400c3c09b1540c14.js +1 -0
  266. package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-400c3c09b1540c14.js +1 -0
  267. package/_standalone/.next/static/chunks/app/api/setup/ls/route-400c3c09b1540c14.js +1 -0
  268. package/_standalone/.next/static/chunks/app/api/setup/route-400c3c09b1540c14.js +1 -0
  269. package/_standalone/.next/static/chunks/app/api/skills/route-400c3c09b1540c14.js +1 -0
  270. package/_standalone/.next/static/chunks/app/api/sync/route-400c3c09b1540c14.js +1 -0
  271. package/_standalone/.next/static/chunks/app/api/tree-version/route-400c3c09b1540c14.js +1 -0
  272. package/_standalone/.next/static/chunks/app/api/uninstall/route-400c3c09b1540c14.js +1 -0
  273. package/_standalone/.next/static/chunks/app/api/update/route-400c3c09b1540c14.js +1 -0
  274. package/_standalone/.next/static/chunks/app/api/update-check/route-400c3c09b1540c14.js +1 -0
  275. package/_standalone/.next/static/chunks/app/api/update-status/route-400c3c09b1540c14.js +1 -0
  276. package/_standalone/.next/static/chunks/app/api/workflows/route-400c3c09b1540c14.js +1 -0
  277. package/_standalone/.next/static/chunks/app/changes/page-350992cf5091bc5b.js +1 -0
  278. package/_standalone/.next/static/chunks/app/echo/[segment]/page-addf014fcf23fad5.js +11 -0
  279. package/_standalone/.next/static/chunks/app/echo/page-400c3c09b1540c14.js +1 -0
  280. package/_standalone/.next/static/chunks/app/explore/page-5eb2835e9e3ab4bb.js +4 -0
  281. package/_standalone/.next/static/chunks/app/help/page-2325d25b6846ca07.js +1 -0
  282. package/_standalone/.next/static/chunks/app/layout-42cdbce19f404567.js +186 -0
  283. package/_standalone/.next/static/chunks/app/login/page-24236460fa7c11d0.js +1 -0
  284. package/_standalone/.next/static/chunks/app/page-8c9643b649e01735.js +7 -0
  285. package/_standalone/.next/static/chunks/app/setup/page-d158b8cb533feb1e.js +1 -0
  286. package/_standalone/.next/static/chunks/app/trash/page-e9ab74ffeb96af41.js +1 -0
  287. package/_standalone/.next/static/chunks/app/view/[...path]/loading-400c3c09b1540c14.js +1 -0
  288. package/_standalone/.next/static/chunks/app/view/[...path]/not-found-61474670d6bb6116.js +1 -0
  289. package/_standalone/.next/static/chunks/app/view/[...path]/page-764a69a1c8bd4eef.js +12 -0
  290. package/_standalone/.next/static/chunks/e71f6c19-4df85185bf989b49.js +1 -0
  291. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-400c3c09b1540c14.js +1 -0
  292. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-400c3c09b1540c14.js +1 -0
  293. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-400c3c09b1540c14.js +1 -0
  294. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-400c3c09b1540c14.js +1 -0
  295. package/_standalone/.next/static/chunks/webpack-7b276daaa930d480.js +1 -0
  296. package/_standalone/.next/static/css/bc9179074eaf65ae.css +1 -0
  297. package/_standalone/.next/trace +63 -53
  298. package/_standalone/.next/types/routes.d.ts +2 -1
  299. package/_standalone/.next/types/validator.ts +9 -0
  300. package/_standalone/__tests__/agent/chat-mode.test.ts +103 -0
  301. package/_standalone/__tests__/agents/agents-content-dashboard.test.tsx +4 -3
  302. package/_standalone/__tests__/api/bootstrap.test.ts +0 -2
  303. package/_standalone/__tests__/api/file.test.ts +22 -1
  304. package/_standalone/__tests__/api/install-skill.test.ts +2 -2
  305. package/_standalone/__tests__/api/mcp-install.test.ts +32 -10
  306. package/_standalone/__tests__/api/setup.test.ts +2 -2
  307. package/_standalone/__tests__/api/test-key.test.ts +73 -147
  308. package/_standalone/__tests__/ask/ask-content-input-during-run.test.tsx +1 -1
  309. package/_standalone/__tests__/ask/mode-capsule.test.ts +95 -0
  310. package/_standalone/__tests__/cli/agent-routing.test.ts +232 -0
  311. package/_standalone/__tests__/cli/file-subcommands.test.ts +379 -0
  312. package/_standalone/__tests__/core/inbox.test.ts +250 -0
  313. package/_standalone/__tests__/core/skill-install-logic.test.ts +3 -3
  314. package/_standalone/__tests__/core/sync-status.test.ts +1 -1
  315. package/_standalone/__tests__/core/tools.test.ts +8 -6
  316. package/_standalone/__tests__/lib/echo-pages-visual-i18n.test.ts +2 -2
  317. package/_standalone/__tests__/lib/i18n-new-keys.test.ts +2 -2
  318. package/_standalone/__tests__/panels/agents-panel-hub.test.tsx +2 -2
  319. package/_standalone/__tests__/settings/activity-bar-update-badge.test.tsx +1 -1
  320. package/_standalone/__tests__/settings/settings-update-badge.test.tsx +1 -1
  321. package/_standalone/__tests__/settings/update-tab-availability-sync.test.tsx +1 -1
  322. package/_standalone/__tests__/settings/update-tab-browser.test.tsx +1 -1
  323. package/_standalone/__tests__/settings/update-tab-desktop.test.tsx +1 -1
  324. package/_standalone/__tests__/setup.ts +3 -5
  325. package/_standalone/app/globals.css +11 -1
  326. package/_standalone/components/ActivityBar.tsx +26 -10
  327. package/_standalone/components/AskFab.tsx +1 -1
  328. package/_standalone/components/AskModal.tsx +1 -1
  329. package/_standalone/components/Backlinks.tsx +1 -1
  330. package/_standalone/components/CreateSpaceModal.tsx +7 -55
  331. package/_standalone/components/EchoSpotlight.tsx +1 -1
  332. package/_standalone/components/ExportModal.tsx +1 -1
  333. package/_standalone/components/FileTree.tsx +66 -80
  334. package/_standalone/components/FindInPage.tsx +1 -1
  335. package/_standalone/components/GuideCard.tsx +1 -1
  336. package/_standalone/components/ImportModal.tsx +1 -1
  337. package/_standalone/components/KeyboardShortcuts.tsx +1 -1
  338. package/_standalone/components/MarkdownView.tsx +41 -16
  339. package/_standalone/components/OnboardingView.tsx +1 -1
  340. package/_standalone/components/OrganizeToast.tsx +1 -1
  341. package/_standalone/components/Panel.tsx +82 -4
  342. package/_standalone/components/QuickSuggestion.tsx +1 -1
  343. package/_standalone/components/RightAgentDetailPanel.tsx +2 -2
  344. package/_standalone/components/RightAskPanel.tsx +88 -22
  345. package/_standalone/components/SearchModal.tsx +1 -1
  346. package/_standalone/components/Sidebar.tsx +4 -4
  347. package/_standalone/components/SidebarLayout.tsx +52 -16
  348. package/_standalone/components/SpaceInitToast.tsx +1 -1
  349. package/_standalone/components/SyncStatusBar.tsx +2 -2
  350. package/_standalone/components/SystemPulse.tsx +12 -6
  351. package/_standalone/components/TableOfContents.tsx +86 -39
  352. package/_standalone/components/agents/AgentActivitySection.tsx +225 -0
  353. package/_standalone/components/agents/AgentsMcpSection.tsx +10 -16
  354. package/_standalone/components/agents/AgentsOverviewSection.tsx +28 -27
  355. package/_standalone/components/agents/AgentsPanelA2aTab.tsx +1 -1
  356. package/_standalone/components/agents/AgentsPanelSessionsTab.tsx +6 -1
  357. package/_standalone/components/agents/AgentsSkillsSection.tsx +1 -1
  358. package/_standalone/components/agents/DiscoverAgentModal.tsx +1 -1
  359. package/_standalone/components/agents/RecentActivityFeed.tsx +49 -88
  360. package/_standalone/components/agents/agent-activity-shared.tsx +110 -0
  361. package/_standalone/components/ask/AgentSelectorCapsule.tsx +1 -1
  362. package/_standalone/components/ask/AskContent.tsx +332 -486
  363. package/_standalone/components/ask/AskHeader.tsx +61 -0
  364. package/_standalone/components/ask/FileChip.tsx +9 -5
  365. package/_standalone/components/ask/MessageList.tsx +88 -21
  366. package/_standalone/components/ask/ModeCapsule.tsx +180 -0
  367. package/_standalone/components/ask/ProviderModelCapsule.tsx +284 -0
  368. package/_standalone/components/ask/SessionHistory.tsx +63 -10
  369. package/_standalone/components/ask/SessionTabBar.tsx +1 -1
  370. package/_standalone/components/ask/ThinkingBlock.tsx +1 -1
  371. package/_standalone/components/ask/ToolCallBlock.tsx +28 -24
  372. package/_standalone/components/changes/ChangesBanner.tsx +1 -1
  373. package/_standalone/components/echo/EchoInsightCollapsible.tsx +1 -1
  374. package/_standalone/components/echo/EchoSegmentNav.tsx +1 -1
  375. package/_standalone/components/home/InboxSection.tsx +268 -0
  376. package/_standalone/components/panels/AgentsPanel.tsx +3 -2
  377. package/_standalone/components/panels/AgentsPanelHubNav.tsx +2 -6
  378. package/_standalone/components/panels/DiscoverPanel.tsx +1 -1
  379. package/_standalone/components/panels/EchoPanel.tsx +1 -1
  380. package/_standalone/components/panels/EchoSidebarStats.tsx +1 -1
  381. package/_standalone/components/panels/ImportHistoryPanel.tsx +1 -1
  382. package/_standalone/components/panels/PanelHeader.tsx +1 -1
  383. package/_standalone/components/panels/PluginsPanel.tsx +1 -1
  384. package/_standalone/components/panels/SearchPanel.tsx +5 -2
  385. package/_standalone/components/panels/SyncPopover.tsx +1 -1
  386. package/_standalone/components/panels/WorkflowsPanel.tsx +1 -1
  387. package/_standalone/components/renderers/agent-inspector/AgentInspectorRenderer.tsx +18 -0
  388. package/_standalone/components/renderers/todo/TodoRenderer.tsx +489 -75
  389. package/_standalone/components/settings/AiTab.tsx +198 -127
  390. package/_standalone/components/settings/AppearanceTab.tsx +48 -50
  391. package/_standalone/components/settings/KnowledgeTab.tsx +92 -27
  392. package/_standalone/components/settings/McpAgentInstall.tsx +95 -28
  393. package/_standalone/components/settings/McpSkillsSection.tsx +2 -2
  394. package/_standalone/components/settings/McpTab.tsx +498 -216
  395. package/_standalone/components/settings/PluginsTab.tsx +1 -1
  396. package/_standalone/components/settings/SettingsContent.tsx +17 -8
  397. package/_standalone/components/settings/SyncTab.tsx +615 -230
  398. package/_standalone/components/settings/UninstallTab.tsx +1 -1
  399. package/_standalone/components/settings/UpdateTab.tsx +2 -2
  400. package/_standalone/components/settings/types.ts +7 -5
  401. package/_standalone/components/setup/StepAI.tsx +70 -49
  402. package/_standalone/components/setup/StepAgents.tsx +113 -47
  403. package/_standalone/components/setup/StepDots.tsx +1 -1
  404. package/_standalone/components/setup/StepReview.tsx +186 -31
  405. package/_standalone/components/setup/types.ts +17 -8
  406. package/_standalone/components/shared/ProviderSelect.tsx +134 -0
  407. package/_standalone/components/walkthrough/WalkthroughOverlay.tsx +2 -2
  408. package/_standalone/components/walkthrough/WalkthroughTooltip.tsx +2 -2
  409. package/_standalone/components/walkthrough/index.ts +1 -1
  410. package/_standalone/data/skills/mindos/SKILL.md +93 -93
  411. package/_standalone/data/skills/mindos/references/write-supplement.md +119 -0
  412. package/_standalone/data/skills/mindos-zh/SKILL.md +100 -104
  413. package/_standalone/data/skills/mindos-zh/references/write-supplement.md +119 -0
  414. package/_standalone/hooks/useAcpDetection.ts +1 -1
  415. package/_standalone/hooks/useAskChat.ts +248 -0
  416. package/_standalone/hooks/useAskPanel.ts +24 -4
  417. package/_standalone/hooks/useAskSession.ts +15 -0
  418. package/_standalone/lib/acp/types.ts +1 -1
  419. package/_standalone/lib/api.ts +3 -1
  420. package/_standalone/lib/core/types.ts +2 -0
  421. package/_standalone/lib/i18n/modules/ai-chat.ts +35 -13
  422. package/_standalone/lib/i18n/modules/features.ts +5 -5
  423. package/_standalone/lib/i18n/modules/knowledge.ts +86 -2
  424. package/_standalone/lib/i18n/modules/navigation.ts +6 -2
  425. package/_standalone/lib/i18n/modules/onboarding.ts +69 -29
  426. package/_standalone/lib/i18n/modules/panels.ts +78 -29
  427. package/_standalone/lib/i18n/modules/settings.ts +280 -24
  428. package/_standalone/lib/inbox-upload.ts +93 -0
  429. package/_standalone/lib/mcp-snippets.ts +5 -1
  430. package/_standalone/lib/settings-ai-client.ts +13 -12
  431. package/_standalone/lib/space-ai-init.ts +66 -0
  432. package/_standalone/lib/stores/McpStoreInit.tsx +18 -0
  433. package/_standalone/lib/stores/WalkthroughInit.tsx +20 -0
  434. package/_standalone/lib/stores/locale-store.ts +55 -0
  435. package/_standalone/lib/stores/mcp-store.ts +156 -0
  436. package/_standalone/lib/stores/walkthrough-store.ts +118 -0
  437. package/_standalone/package-lock.json +40 -8
  438. package/_standalone/package.json +3 -1
  439. package/_standalone/tsconfig.json +1 -1
  440. package/_standalone/tsconfig.tsbuildinfo +1 -1
  441. package/app/app/api/acp/detect/route.ts +29 -20
  442. package/app/app/api/agent-activity/route.ts +1 -1
  443. package/app/app/api/ask/route.ts +105 -30
  444. package/app/app/api/ask-sessions/route.ts +1 -0
  445. package/app/app/api/bootstrap/route.ts +1 -3
  446. package/app/app/api/file/route.ts +34 -4
  447. package/app/app/api/inbox/route.ts +61 -0
  448. package/app/app/api/mcp/install/route.ts +2 -1
  449. package/app/app/api/mcp/status/route.ts +14 -6
  450. package/app/app/api/settings/list-models/route.ts +73 -53
  451. package/app/app/api/settings/route.ts +46 -55
  452. package/app/app/api/settings/test-key/route.ts +57 -114
  453. package/app/app/api/setup/route.ts +31 -21
  454. package/app/app/api/sync/route.ts +122 -12
  455. package/app/app/api/update-check/route.ts +2 -2
  456. package/app/app/globals.css +11 -1
  457. package/app/app/layout.tsx +2 -3
  458. package/app/app/login/page.tsx +1 -1
  459. package/app/app/view/[...path]/ViewPageClient.tsx +22 -37
  460. package/app/app/view/[...path]/not-found.tsx +1 -1
  461. package/app/components/ActivityBar.tsx +26 -10
  462. package/app/components/AskFab.tsx +1 -1
  463. package/app/components/AskModal.tsx +1 -1
  464. package/app/components/Backlinks.tsx +1 -1
  465. package/app/components/CreateSpaceModal.tsx +7 -55
  466. package/app/components/DirView.tsx +93 -11
  467. package/app/components/EchoSpotlight.tsx +1 -1
  468. package/app/components/ExportModal.tsx +1 -1
  469. package/app/components/FileTree.tsx +66 -80
  470. package/app/components/FindInPage.tsx +1 -1
  471. package/app/components/GuideCard.tsx +1 -1
  472. package/app/components/HomeContent.tsx +21 -14
  473. package/app/components/ImportModal.tsx +1 -1
  474. package/app/components/KeyboardShortcuts.tsx +1 -1
  475. package/app/components/MarkdownView.tsx +41 -16
  476. package/app/components/OnboardingView.tsx +1 -1
  477. package/app/components/OrganizeToast.tsx +1 -1
  478. package/app/components/Panel.tsx +82 -4
  479. package/app/components/QuickSuggestion.tsx +1 -1
  480. package/app/components/RightAgentDetailPanel.tsx +2 -2
  481. package/app/components/RightAskPanel.tsx +88 -22
  482. package/app/components/SearchModal.tsx +1 -1
  483. package/app/components/Sidebar.tsx +4 -4
  484. package/app/components/SidebarLayout.tsx +52 -16
  485. package/app/components/SpaceInitToast.tsx +1 -1
  486. package/app/components/SyncStatusBar.tsx +2 -2
  487. package/app/components/SystemPulse.tsx +12 -6
  488. package/app/components/TableOfContents.tsx +86 -39
  489. package/app/components/TrashPageClient.tsx +1 -1
  490. package/app/components/UpdateOverlay.tsx +2 -2
  491. package/app/components/agents/AgentActivitySection.tsx +225 -0
  492. package/app/components/agents/AgentDetailContent.tsx +234 -3
  493. package/app/components/agents/AgentsContentPage.tsx +13 -2
  494. package/app/components/agents/AgentsMcpSection.tsx +10 -16
  495. package/app/components/agents/AgentsOverviewSection.tsx +28 -27
  496. package/app/components/agents/AgentsPanelA2aTab.tsx +1 -1
  497. package/app/components/agents/AgentsPanelSessionsTab.tsx +6 -1
  498. package/app/components/agents/AgentsSkillsSection.tsx +1 -1
  499. package/app/components/agents/DiscoverAgentModal.tsx +1 -1
  500. package/app/components/agents/RecentActivityFeed.tsx +49 -88
  501. package/app/components/agents/agent-activity-shared.tsx +110 -0
  502. package/app/components/agents/agents-content-model.ts +2 -2
  503. package/app/components/ask/AgentSelectorCapsule.tsx +1 -1
  504. package/app/components/ask/AskContent.tsx +332 -486
  505. package/app/components/ask/AskHeader.tsx +61 -0
  506. package/app/components/ask/FileChip.tsx +9 -5
  507. package/app/components/ask/MessageList.tsx +88 -21
  508. package/app/components/ask/ModeCapsule.tsx +180 -0
  509. package/app/components/ask/ProviderModelCapsule.tsx +284 -0
  510. package/app/components/ask/SessionHistory.tsx +63 -10
  511. package/app/components/ask/SessionTabBar.tsx +1 -1
  512. package/app/components/ask/ThinkingBlock.tsx +1 -1
  513. package/app/components/ask/ToolCallBlock.tsx +28 -24
  514. package/app/components/changes/ChangesBanner.tsx +1 -1
  515. package/app/components/changes/ChangesContentPage.tsx +1 -1
  516. package/app/components/echo/EchoInsightCollapsible.tsx +1 -1
  517. package/app/components/echo/EchoSegmentNav.tsx +1 -1
  518. package/app/components/echo/EchoSegmentPageClient.tsx +1 -1
  519. package/app/components/explore/ExploreContent.tsx +1 -1
  520. package/app/components/help/HelpContent.tsx +2 -1
  521. package/app/components/home/InboxSection.tsx +268 -0
  522. package/app/components/panels/AgentsPanel.tsx +3 -2
  523. package/app/components/panels/AgentsPanelHubNav.tsx +2 -6
  524. package/app/components/panels/DiscoverPanel.tsx +1 -1
  525. package/app/components/panels/EchoPanel.tsx +1 -1
  526. package/app/components/panels/EchoSidebarStats.tsx +1 -1
  527. package/app/components/panels/ImportHistoryPanel.tsx +1 -1
  528. package/app/components/panels/PanelHeader.tsx +1 -1
  529. package/app/components/panels/PluginsPanel.tsx +1 -1
  530. package/app/components/panels/SearchPanel.tsx +5 -2
  531. package/app/components/panels/SyncPopover.tsx +1 -1
  532. package/app/components/panels/WorkflowsPanel.tsx +1 -1
  533. package/app/components/renderers/agent-inspector/AgentInspectorRenderer.tsx +18 -0
  534. package/app/components/renderers/todo/TodoRenderer.tsx +489 -75
  535. package/app/components/settings/AiTab.tsx +198 -127
  536. package/app/components/settings/AppearanceTab.tsx +48 -50
  537. package/app/components/settings/KnowledgeTab.tsx +92 -27
  538. package/app/components/settings/McpAgentInstall.tsx +95 -28
  539. package/app/components/settings/McpSkillsSection.tsx +2 -2
  540. package/app/components/settings/McpTab.tsx +498 -216
  541. package/app/components/settings/PluginsTab.tsx +1 -1
  542. package/app/components/settings/SettingsContent.tsx +17 -8
  543. package/app/components/settings/SyncTab.tsx +615 -230
  544. package/app/components/settings/UninstallTab.tsx +1 -1
  545. package/app/components/settings/UpdateTab.tsx +2 -2
  546. package/app/components/settings/types.ts +7 -5
  547. package/app/components/setup/StepAI.tsx +70 -49
  548. package/app/components/setup/StepAgents.tsx +113 -47
  549. package/app/components/setup/StepDots.tsx +1 -1
  550. package/app/components/setup/StepReview.tsx +186 -31
  551. package/app/components/setup/index.tsx +83 -48
  552. package/app/components/setup/types.ts +17 -8
  553. package/app/components/shared/ProviderSelect.tsx +134 -0
  554. package/app/components/walkthrough/WalkthroughOverlay.tsx +2 -2
  555. package/app/components/walkthrough/WalkthroughTooltip.tsx +2 -2
  556. package/app/components/walkthrough/index.ts +1 -1
  557. package/app/data/skills/mindos/SKILL.md +93 -93
  558. package/app/data/skills/mindos/references/write-supplement.md +119 -0
  559. package/app/data/skills/mindos-zh/SKILL.md +100 -104
  560. package/app/data/skills/mindos-zh/references/write-supplement.md +119 -0
  561. package/app/hooks/useAcpDetection.ts +1 -1
  562. package/app/hooks/useAskChat.ts +248 -0
  563. package/app/hooks/useAskPanel.ts +24 -4
  564. package/app/hooks/useAskSession.ts +15 -0
  565. package/app/lib/acp/types.ts +1 -1
  566. package/app/lib/actions.ts +13 -0
  567. package/app/lib/agent/log.ts +2 -0
  568. package/app/lib/agent/model.ts +69 -81
  569. package/app/lib/agent/prompt.ts +27 -0
  570. package/app/lib/agent/providers.ts +299 -0
  571. package/app/lib/agent/tools.ts +26 -4
  572. package/app/lib/api.ts +3 -1
  573. package/app/lib/core/agent-audit-log.ts +7 -0
  574. package/app/lib/core/fs-ops.ts +9 -4
  575. package/app/lib/core/inbox.ts +181 -0
  576. package/app/lib/core/index.ts +4 -0
  577. package/app/lib/core/tree.ts +3 -0
  578. package/app/lib/core/types.ts +2 -0
  579. package/app/lib/fs.ts +20 -2
  580. package/app/lib/i18n/modules/ai-chat.ts +35 -13
  581. package/app/lib/i18n/modules/features.ts +5 -5
  582. package/app/lib/i18n/modules/knowledge.ts +86 -2
  583. package/app/lib/i18n/modules/navigation.ts +6 -2
  584. package/app/lib/i18n/modules/onboarding.ts +69 -29
  585. package/app/lib/i18n/modules/panels.ts +78 -29
  586. package/app/lib/i18n/modules/settings.ts +280 -24
  587. package/app/lib/inbox-upload.ts +93 -0
  588. package/app/lib/mcp-agents.ts +7 -9
  589. package/app/lib/mcp-snippets.ts +5 -1
  590. package/app/lib/settings-ai-client.ts +13 -12
  591. package/app/lib/settings.ts +48 -33
  592. package/app/lib/space-ai-init.ts +66 -0
  593. package/app/lib/stores/LocaleStoreInit.tsx +18 -0
  594. package/app/lib/stores/McpStoreInit.tsx +18 -0
  595. package/app/lib/stores/WalkthroughInit.tsx +20 -0
  596. package/app/lib/stores/locale-store.ts +55 -0
  597. package/app/lib/stores/mcp-store.ts +156 -0
  598. package/app/lib/stores/walkthrough-store.ts +118 -0
  599. package/app/lib/types.ts +20 -0
  600. package/app/package.json +3 -1
  601. package/app/tsconfig.json +1 -1
  602. package/bin/cli.js +168 -1385
  603. package/bin/commands/agent.js +156 -20
  604. package/bin/commands/api.js +14 -11
  605. package/bin/commands/ask.js +79 -68
  606. package/bin/commands/build.js +26 -0
  607. package/bin/commands/config.js +170 -0
  608. package/bin/commands/dev.js +58 -0
  609. package/bin/commands/doctor.js +205 -0
  610. package/bin/commands/file.js +558 -40
  611. package/bin/commands/gateway.js +42 -0
  612. package/bin/commands/init-skills.js +56 -0
  613. package/bin/commands/logs.js +32 -0
  614. package/bin/commands/mcp-cmd.js +57 -0
  615. package/bin/commands/onboard.js +25 -0
  616. package/bin/commands/open.js +41 -0
  617. package/bin/commands/restart.js +48 -0
  618. package/bin/commands/search.js +16 -14
  619. package/bin/commands/space.js +100 -25
  620. package/bin/commands/start.js +262 -0
  621. package/bin/commands/status.js +2 -2
  622. package/bin/commands/stop.js +14 -0
  623. package/bin/commands/sync-cmd.js +134 -0
  624. package/bin/commands/token.js +98 -0
  625. package/bin/commands/uninstall.js +154 -0
  626. package/bin/commands/update.js +286 -0
  627. package/bin/lib/build.js +1 -1
  628. package/bin/lib/colors.js +8 -7
  629. package/bin/lib/command.js +37 -96
  630. package/bin/lib/config.js +5 -0
  631. package/bin/lib/csv.js +19 -0
  632. package/bin/lib/jsonc.js +12 -0
  633. package/bin/lib/markdown.js +69 -0
  634. package/bin/lib/mcp-agents.js +27 -8
  635. package/bin/lib/mcp-build.js +1 -1
  636. package/bin/lib/mcp-install.js +13 -4
  637. package/bin/lib/one-shot.js +88 -0
  638. package/bin/lib/path-expand.js +9 -0
  639. package/bin/lib/remote.js +65 -0
  640. package/bin/lib/repl.js +167 -0
  641. package/bin/lib/{utils.js → shell.js} +10 -26
  642. package/bin/lib/skill-check.js +1 -1
  643. package/bin/lib/sse-stream.js +167 -0
  644. package/bin/lib/sync.js +140 -34
  645. package/mcp/README.md +2 -2
  646. package/mcp/dist/index.cjs +43 -43
  647. package/mcp/package.json +1 -1
  648. package/mcp/src/index.ts +77 -61
  649. package/package.json +2 -2
  650. package/scripts/setup.js +183 -121
  651. package/skills/mindos/SKILL.md +93 -93
  652. package/skills/mindos/references/preference-capture.md +4 -4
  653. package/skills/mindos/references/write-supplement.md +2 -2
  654. package/skills/mindos-zh/SKILL.md +100 -104
  655. package/skills/mindos-zh/references/preference-capture.md +4 -4
  656. package/skills/mindos-zh/references/write-supplement.md +2 -2
  657. package/templates/empty/INSTRUCTION.md +0 -1
  658. package/templates/en/INSTRUCTION.md +0 -1
  659. package/templates/template-generation-skill.md +0 -1
  660. package/templates/zh/INSTRUCTION.md +0 -1
  661. package/_standalone/.next/server/chunks/1473.js +0 -52
  662. package/_standalone/.next/server/chunks/248.js +0 -15
  663. package/_standalone/.next/server/chunks/359.js +0 -2
  664. package/_standalone/.next/server/chunks/4931.js +0 -202
  665. package/_standalone/.next/server/chunks/7670.js +0 -1
  666. package/_standalone/.next/static/chunks/1038-ed04d6651ec92312.js +0 -1
  667. package/_standalone/.next/static/chunks/1263-6df1734e4273adb1.js +0 -25
  668. package/_standalone/.next/static/chunks/275-ebcaaedabe706903.js +0 -1
  669. package/_standalone/.next/static/chunks/3637.4bcd01a4db78b894.js +0 -1
  670. package/_standalone/.next/static/chunks/5637-b97c869adf70c82e.js +0 -1
  671. package/_standalone/.next/static/chunks/5681-a53362a1cd629dc6.js +0 -1
  672. package/_standalone/.next/static/chunks/9602-35ca17b688f1a4fe.js +0 -1
  673. package/_standalone/.next/static/chunks/9670-d59e4d45ed705f58.js +0 -6
  674. package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/route-d4762cc48529e566.js +0 -1
  675. package/_standalone/.next/static/chunks/app/_global-error/page-d4762cc48529e566.js +0 -1
  676. package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-519d4da1142db5ef.js +0 -1
  677. package/_standalone/.next/static/chunks/app/agents/page-b709cf3103321609.js +0 -5
  678. package/_standalone/.next/static/chunks/app/api/a2a/agents/route-d4762cc48529e566.js +0 -1
  679. package/_standalone/.next/static/chunks/app/api/a2a/delegations/route-d4762cc48529e566.js +0 -1
  680. package/_standalone/.next/static/chunks/app/api/a2a/discover/route-d4762cc48529e566.js +0 -1
  681. package/_standalone/.next/static/chunks/app/api/a2a/route-d4762cc48529e566.js +0 -1
  682. package/_standalone/.next/static/chunks/app/api/acp/config/route-d4762cc48529e566.js +0 -1
  683. package/_standalone/.next/static/chunks/app/api/acp/detect/route-d4762cc48529e566.js +0 -1
  684. package/_standalone/.next/static/chunks/app/api/acp/install/route-d4762cc48529e566.js +0 -1
  685. package/_standalone/.next/static/chunks/app/api/acp/registry/route-d4762cc48529e566.js +0 -1
  686. package/_standalone/.next/static/chunks/app/api/acp/session/route-d4762cc48529e566.js +0 -1
  687. package/_standalone/.next/static/chunks/app/api/agent-activity/route-d4762cc48529e566.js +0 -1
  688. package/_standalone/.next/static/chunks/app/api/ask/route-d4762cc48529e566.js +0 -1
  689. package/_standalone/.next/static/chunks/app/api/ask-sessions/route-d4762cc48529e566.js +0 -1
  690. package/_standalone/.next/static/chunks/app/api/auth/route-d4762cc48529e566.js +0 -1
  691. package/_standalone/.next/static/chunks/app/api/backlinks/route-d4762cc48529e566.js +0 -1
  692. package/_standalone/.next/static/chunks/app/api/bootstrap/route-d4762cc48529e566.js +0 -1
  693. package/_standalone/.next/static/chunks/app/api/changes/route-d4762cc48529e566.js +0 -1
  694. package/_standalone/.next/static/chunks/app/api/export/route-d4762cc48529e566.js +0 -1
  695. package/_standalone/.next/static/chunks/app/api/extract-pdf/route-d4762cc48529e566.js +0 -1
  696. package/_standalone/.next/static/chunks/app/api/file/import/route-d4762cc48529e566.js +0 -1
  697. package/_standalone/.next/static/chunks/app/api/file/route-d4762cc48529e566.js +0 -1
  698. package/_standalone/.next/static/chunks/app/api/files/route-d4762cc48529e566.js +0 -1
  699. package/_standalone/.next/static/chunks/app/api/git/route-d4762cc48529e566.js +0 -1
  700. package/_standalone/.next/static/chunks/app/api/graph/route-d4762cc48529e566.js +0 -1
  701. package/_standalone/.next/static/chunks/app/api/health/route-d4762cc48529e566.js +0 -1
  702. package/_standalone/.next/static/chunks/app/api/init/route-d4762cc48529e566.js +0 -1
  703. package/_standalone/.next/static/chunks/app/api/mcp/agents/route-d4762cc48529e566.js +0 -1
  704. package/_standalone/.next/static/chunks/app/api/mcp/install/route-d4762cc48529e566.js +0 -1
  705. package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-d4762cc48529e566.js +0 -1
  706. package/_standalone/.next/static/chunks/app/api/mcp/restart/route-d4762cc48529e566.js +0 -1
  707. package/_standalone/.next/static/chunks/app/api/mcp/status/route-d4762cc48529e566.js +0 -1
  708. package/_standalone/.next/static/chunks/app/api/monitoring/route-d4762cc48529e566.js +0 -1
  709. package/_standalone/.next/static/chunks/app/api/recent-files/route-d4762cc48529e566.js +0 -1
  710. package/_standalone/.next/static/chunks/app/api/restart/route-d4762cc48529e566.js +0 -1
  711. package/_standalone/.next/static/chunks/app/api/search/route-d4762cc48529e566.js +0 -1
  712. package/_standalone/.next/static/chunks/app/api/settings/list-models/route-d4762cc48529e566.js +0 -1
  713. package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-d4762cc48529e566.js +0 -1
  714. package/_standalone/.next/static/chunks/app/api/settings/route-d4762cc48529e566.js +0 -1
  715. package/_standalone/.next/static/chunks/app/api/settings/test-key/route-d4762cc48529e566.js +0 -1
  716. package/_standalone/.next/static/chunks/app/api/setup/check-path/route-d4762cc48529e566.js +0 -1
  717. package/_standalone/.next/static/chunks/app/api/setup/check-port/route-d4762cc48529e566.js +0 -1
  718. package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-d4762cc48529e566.js +0 -1
  719. package/_standalone/.next/static/chunks/app/api/setup/ls/route-d4762cc48529e566.js +0 -1
  720. package/_standalone/.next/static/chunks/app/api/setup/route-d4762cc48529e566.js +0 -1
  721. package/_standalone/.next/static/chunks/app/api/skills/route-d4762cc48529e566.js +0 -1
  722. package/_standalone/.next/static/chunks/app/api/sync/route-d4762cc48529e566.js +0 -1
  723. package/_standalone/.next/static/chunks/app/api/tree-version/route-d4762cc48529e566.js +0 -1
  724. package/_standalone/.next/static/chunks/app/api/uninstall/route-d4762cc48529e566.js +0 -1
  725. package/_standalone/.next/static/chunks/app/api/update/route-d4762cc48529e566.js +0 -1
  726. package/_standalone/.next/static/chunks/app/api/update-check/route-d4762cc48529e566.js +0 -1
  727. package/_standalone/.next/static/chunks/app/api/update-status/route-d4762cc48529e566.js +0 -1
  728. package/_standalone/.next/static/chunks/app/api/workflows/route-d4762cc48529e566.js +0 -1
  729. package/_standalone/.next/static/chunks/app/changes/page-def5210095f8698d.js +0 -1
  730. package/_standalone/.next/static/chunks/app/echo/[segment]/page-be28eff31b1a186e.js +0 -11
  731. package/_standalone/.next/static/chunks/app/echo/page-d4762cc48529e566.js +0 -1
  732. package/_standalone/.next/static/chunks/app/explore/page-e4b8098dca200389.js +0 -4
  733. package/_standalone/.next/static/chunks/app/help/page-d5e57d73d94bad19.js +0 -1
  734. package/_standalone/.next/static/chunks/app/layout-d91cdbe2ecf135e1.js +0 -173
  735. package/_standalone/.next/static/chunks/app/login/page-321875768b70938a.js +0 -1
  736. package/_standalone/.next/static/chunks/app/page-718fdf170428b43c.js +0 -7
  737. package/_standalone/.next/static/chunks/app/setup/page-01ab1f549d636057.js +0 -1
  738. package/_standalone/.next/static/chunks/app/trash/page-89b1430cc8a16f18.js +0 -1
  739. package/_standalone/.next/static/chunks/app/view/[...path]/loading-d4762cc48529e566.js +0 -1
  740. package/_standalone/.next/static/chunks/app/view/[...path]/not-found-f22c513bbc348cc8.js +0 -1
  741. package/_standalone/.next/static/chunks/app/view/[...path]/page-6e3dc47699a01de1.js +0 -12
  742. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d4762cc48529e566.js +0 -1
  743. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d4762cc48529e566.js +0 -1
  744. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d4762cc48529e566.js +0 -1
  745. package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d4762cc48529e566.js +0 -1
  746. package/_standalone/.next/static/chunks/webpack-3489a2b6c2882b0c.js +0 -1
  747. package/_standalone/.next/static/css/f16595bc58a16d5d.css +0 -1
  748. package/_standalone/.next/static/ushZ_NJ8rE3rG5hZfaYOX/_buildManifest.js +0 -1
  749. package/_standalone/components/walkthrough/WalkthroughProvider.tsx +0 -133
  750. package/_standalone/hooks/useMcpData.tsx +0 -169
  751. package/_standalone/lib/i18n-en.ts +0 -2
  752. package/_standalone/lib/i18n-zh.ts +0 -2
  753. package/_standalone/lib/types.ts +0 -70
  754. package/app/components/walkthrough/WalkthroughProvider.tsx +0 -133
  755. package/app/hooks/useMcpData.tsx +0 -169
  756. package/app/lib/LocaleContext.tsx +0 -60
  757. package/app/lib/i18n-en.ts +0 -2
  758. package/app/lib/i18n-zh.ts +0 -2
  759. /package/_standalone/.next/static/{ushZ_NJ8rE3rG5hZfaYOX → Ij3PFh-a0zi5K_ANoSAW0}/_ssgManifest.js +0 -0
@@ -1,21 +1,263 @@
1
1
  'use client';
2
2
 
3
- import { useState, useEffect, useCallback } from 'react';
4
- import { RefreshCw, AlertCircle, CheckCircle2, Loader2, GitBranch, ExternalLink, Eye, EyeOff } from 'lucide-react';
5
- import { SectionLabel, PrimaryButton, Input } from './Primitives';
3
+ import { useState, useEffect, useCallback, useRef } from 'react';
4
+ import { RefreshCw, AlertCircle, CheckCircle2, Loader2, GitBranch, ExternalLink, Eye, EyeOff, Check, ChevronRight, FileX2 } from 'lucide-react';
5
+ import { SectionLabel, PrimaryButton, Input, Field, SettingCard } from './Primitives';
6
6
  import { apiFetch } from '@/lib/api';
7
7
  import type { SyncStatus, SyncTabProps } from './types';
8
8
  import type { Messages } from '@/lib/i18n';
9
9
 
10
- export { SyncStatus }; // Re-export for backward compatibility
11
-
12
- export function timeAgo(iso: string | null | undefined): string {
13
- if (!iso) return 'never';
10
+ export function timeAgo(iso: string | null | undefined, syncT?: Record<string, unknown>): string {
11
+ if (!iso) return (syncT?.timeNever as string) ?? 'never';
14
12
  const diff = Date.now() - new Date(iso).getTime();
15
- if (diff < 60000) return 'just now';
16
- if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
17
- if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;
18
- return `${Math.floor(diff / 86400000)}d ago`;
13
+ if (diff < 60000) return (syncT?.timeJustNow as string) ?? 'just now';
14
+ const m = Math.floor(diff / 60000);
15
+ if (diff < 3600000) return (syncT?.timeMinAgo as ((n: number) => string))?.(m) ?? `${m}m ago`;
16
+ const h = Math.floor(diff / 3600000);
17
+ if (diff < 86400000) return (syncT?.timeHourAgo as ((n: number) => string))?.(h) ?? `${h}h ago`;
18
+ const d = Math.floor(diff / 86400000);
19
+ return (syncT?.timeDayAgo as ((n: number) => string))?.(d) ?? `${d}d ago`;
20
+ }
21
+
22
+ /** Classify a raw sync error and return a user-friendly message with action hint. */
23
+ function formatSyncError(raw: string, syncT?: Record<string, unknown>): string {
24
+ const hint = getSyncErrorHint(raw, undefined, syncT);
25
+ return hint ? `${raw}\n${hint}` : raw;
26
+ }
27
+
28
+ /** Return an actionable hint for common sync errors. */
29
+ function getSyncErrorHint(error: string, remote?: string | null, syncT?: Record<string, unknown>): string {
30
+ const lower = error.toLowerCase();
31
+
32
+ // SSH authentication failures
33
+ if (lower.includes('permission denied') || lower.includes('publickey')) {
34
+ return (syncT?.hintSshAuth as string) ?? 'SSH key may not be configured. Run: ssh-keygen -t ed25519 && ssh -T git@github.com';
35
+ }
36
+ // SSH host key / connection
37
+ if (lower.includes('host key') || lower.includes('known_hosts') || lower.includes('fingerprint')) {
38
+ return (syncT?.hintSshHost as string) ?? 'Run: ssh-keyscan github.com >> ~/.ssh/known_hosts';
39
+ }
40
+ // HTTPS auth failures
41
+ if (lower.includes('authentication failed') || lower.includes('invalid credentials') || lower.includes('401') || lower.includes('403')) {
42
+ return (syncT?.hintHttpsAuth as string) ?? 'Access token may be expired or missing. Check Settings → Developer settings → Personal access tokens.';
43
+ }
44
+ // Network / timeout
45
+ if (lower.includes('timed out') || lower.includes('timeout') || lower.includes('could not resolve')) {
46
+ return (syncT?.hintNetwork as string) ?? 'Check your network connection and try again.';
47
+ }
48
+ // Remote not found
49
+ if (lower.includes('not found') || lower.includes('does not exist') || lower.includes('repository not found')) {
50
+ return (syncT?.hintNotFound as string) ?? 'Repository not found. Check the URL and ensure the repo exists.';
51
+ }
52
+ // Push rejected (non-fast-forward)
53
+ if (lower.includes('non-fast-forward') || lower.includes('rejected') || lower.includes('fetch first')) {
54
+ return (syncT?.hintPushRejected as string) ?? 'Remote has changes. Click "Sync Now" to pull and retry.';
55
+ }
56
+ // Merge conflicts
57
+ if (lower.includes('conflict') || lower.includes('merge')) {
58
+ return (syncT?.hintConflict as string) ?? 'Merge conflict detected. Check the Conflicts section below.';
59
+ }
60
+
61
+ return '';
62
+ }
63
+
64
+ /* ── Conflict Row ──────────────────────────────────────────────── */
65
+
66
+ function ConflictRow({ file, time, syncT, onResolved }: {
67
+ file: string; time: string; syncT?: Record<string, unknown>; onResolved: () => void;
68
+ }) {
69
+ const [resolving, setResolving] = useState<string | null>(null);
70
+ const [expanded, setExpanded] = useState(false);
71
+ const [preview, setPreview] = useState<{ local: string; remote: string } | null>(null);
72
+ const [loadingPreview, setLoadingPreview] = useState(false);
73
+
74
+ const togglePreview = async () => {
75
+ if (expanded) { setExpanded(false); return; }
76
+ if (!preview) {
77
+ setLoadingPreview(true);
78
+ try {
79
+ const data = await apiFetch<{ local: string; remote: string }>('/api/sync', {
80
+ method: 'POST',
81
+ headers: { 'Content-Type': 'application/json' },
82
+ body: JSON.stringify({ action: 'conflict-preview', remote: file }),
83
+ });
84
+ setPreview(data);
85
+ } catch { /* ignore */ }
86
+ setLoadingPreview(false);
87
+ }
88
+ setExpanded(true);
89
+ };
90
+
91
+ const handleResolve = async (strategy: 'keep-local' | 'keep-remote') => {
92
+ setResolving(strategy === 'keep-local' ? 'local' : 'remote');
93
+ try {
94
+ await apiFetch('/api/sync', {
95
+ method: 'POST',
96
+ headers: { 'Content-Type': 'application/json' },
97
+ body: JSON.stringify({ action: 'resolve-conflict', remote: file, branch: strategy }),
98
+ });
99
+ onResolved();
100
+ } catch {
101
+ setResolving(null);
102
+ }
103
+ };
104
+
105
+ return (
106
+ <div className="rounded-lg border border-border/50 overflow-hidden">
107
+ {/* Header row */}
108
+ <div className="flex items-center gap-2 p-2 text-xs bg-muted/20">
109
+ <AlertCircle size={12} className="text-error shrink-0" />
110
+ <button
111
+ type="button"
112
+ onClick={togglePreview}
113
+ className="font-mono truncate hover:text-foreground hover:underline transition-colors flex-1 min-w-0 text-left"
114
+ title={(syncT?.viewDiff as string) ?? 'View differences'}
115
+ >
116
+ <ChevronRight size={11} className={`inline mr-1 transition-transform ${expanded ? 'rotate-90' : ''}`} />
117
+ {file}
118
+ </button>
119
+ <span className="text-muted-foreground shrink-0">{timeAgo(time, syncT)}</span>
120
+ <div className="flex items-center gap-1 shrink-0">
121
+ <button
122
+ type="button"
123
+ onClick={() => handleResolve('keep-local')}
124
+ disabled={!!resolving}
125
+ className="px-2 py-0.5 rounded border border-border text-2xs hover:bg-muted transition-colors disabled:opacity-40"
126
+ title={(syncT?.keepLocalHint as string) ?? 'Keep this device\'s version'}
127
+ >
128
+ {resolving === 'local' ? <Loader2 size={10} className="animate-spin" /> : ((syncT?.keepLocal as string) ?? 'Keep local')}
129
+ </button>
130
+ <button
131
+ type="button"
132
+ onClick={() => handleResolve('keep-remote')}
133
+ disabled={!!resolving}
134
+ className="px-2 py-0.5 rounded border border-border text-2xs hover:bg-muted transition-colors disabled:opacity-40"
135
+ title={(syncT?.keepRemoteHint as string) ?? 'Replace with remote version'}
136
+ >
137
+ {resolving === 'remote' ? <Loader2 size={10} className="animate-spin" /> : ((syncT?.keepRemote as string) ?? 'Keep remote')}
138
+ </button>
139
+ </div>
140
+ </div>
141
+
142
+ {/* Diff preview */}
143
+ {expanded && (
144
+ <div className="border-t border-border/50">
145
+ {loadingPreview ? (
146
+ <div className="flex justify-center py-3">
147
+ <Loader2 size={13} className="animate-spin text-muted-foreground" />
148
+ </div>
149
+ ) : preview ? (
150
+ <div className="grid grid-cols-2 divide-x divide-border/50 text-2xs font-mono max-h-60 overflow-auto">
151
+ <div className="p-2">
152
+ <div className="text-muted-foreground mb-1 font-sans text-xs font-medium">
153
+ {(syncT?.localVersion as string) ?? 'Local (this device)'}
154
+ </div>
155
+ <pre className="whitespace-pre-wrap text-foreground/80 leading-relaxed">{preview.local || ((syncT?.emptyFile as string) ?? '(empty)')}</pre>
156
+ </div>
157
+ <div className="p-2">
158
+ <div className="text-muted-foreground mb-1 font-sans text-xs font-medium">
159
+ {(syncT?.remoteVersion as string) ?? 'Remote'}
160
+ </div>
161
+ <pre className="whitespace-pre-wrap text-foreground/80 leading-relaxed">{preview.remote || ((syncT?.emptyFile as string) ?? '(empty)')}</pre>
162
+ </div>
163
+ </div>
164
+ ) : null}
165
+ </div>
166
+ )}
167
+ </div>
168
+ );
169
+ }
170
+
171
+ /* ── Gitignore Editor ──────────────────────────────────────────── */
172
+
173
+ function GitignoreEditor({ syncT }: { syncT?: Record<string, unknown> }) {
174
+ const [open, setOpen] = useState(false);
175
+ const [content, setContent] = useState('');
176
+ const [saved, setSaved] = useState('');
177
+ const [loading, setLoading] = useState(false);
178
+ const [saveOk, setSaveOk] = useState(false);
179
+ const loaded = useRef(false);
180
+
181
+ const dirty = content !== saved;
182
+
183
+ useEffect(() => {
184
+ if (!open || loaded.current) return;
185
+ loaded.current = true;
186
+ setLoading(true);
187
+ apiFetch<{ content: string }>('/api/sync', {
188
+ method: 'POST',
189
+ headers: { 'Content-Type': 'application/json' },
190
+ body: JSON.stringify({ action: 'gitignore-get' }),
191
+ }).then(data => {
192
+ setContent(data.content);
193
+ setSaved(data.content);
194
+ }).catch(() => {}).finally(() => setLoading(false));
195
+ }, [open]);
196
+
197
+ const handleSave = async () => {
198
+ try {
199
+ await apiFetch('/api/sync', {
200
+ method: 'POST',
201
+ headers: { 'Content-Type': 'application/json' },
202
+ body: JSON.stringify({ action: 'gitignore-save', content }),
203
+ });
204
+ setSaved(content);
205
+ setSaveOk(true);
206
+ setTimeout(() => setSaveOk(false), 2000);
207
+ } catch {}
208
+ };
209
+
210
+ return (
211
+ <div className="pt-2 border-t border-border/50">
212
+ <button
213
+ type="button"
214
+ onClick={() => setOpen(!open)}
215
+ className="flex items-center gap-2 w-full text-left text-sm text-muted-foreground hover:text-foreground transition-colors py-1"
216
+ >
217
+ <ChevronRight size={14} className={`shrink-0 transition-transform ${open ? 'rotate-90' : ''}`} />
218
+ <FileX2 size={13} className="shrink-0" />
219
+ <span>{(syncT?.gitignoreTitle as string) ?? 'Excluded files'}</span>
220
+ <span className="text-2xs opacity-50">.gitignore</span>
221
+ </button>
222
+
223
+ {open && (
224
+ <div className="mt-2 space-y-2">
225
+ {loading ? (
226
+ <div className="flex justify-center py-4">
227
+ <Loader2 size={14} className="animate-spin text-muted-foreground" />
228
+ </div>
229
+ ) : (
230
+ <>
231
+ <textarea
232
+ value={content}
233
+ onChange={e => setContent(e.target.value)}
234
+ rows={8}
235
+ className="w-full rounded-lg border border-border bg-background px-3 py-2 text-xs font-mono leading-relaxed text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring resize-y"
236
+ placeholder={(syncT?.gitignorePlaceholder as string) ?? '# Files to exclude from sync\n*.tmp\nsecret/'}
237
+ spellCheck={false}
238
+ />
239
+ <div className="flex items-center gap-2">
240
+ {dirty && (
241
+ <button
242
+ type="button"
243
+ onClick={handleSave}
244
+ className="flex items-center gap-1.5 px-3 py-1 text-xs rounded-lg bg-[var(--amber)] text-[var(--amber-foreground)] hover:opacity-90 transition-opacity"
245
+ >
246
+ {(syncT?.gitignoreSave as string) ?? 'Save'}
247
+ </button>
248
+ )}
249
+ {saveOk && (
250
+ <span className="flex items-center gap-1 text-xs text-success">
251
+ <Check size={12} /> {(syncT?.gitignoreSaved as string) ?? 'Saved'}
252
+ </span>
253
+ )}
254
+ </div>
255
+ </>
256
+ )}
257
+ </div>
258
+ )}
259
+ </div>
260
+ );
19
261
  }
20
262
 
21
263
  /* ── Empty state — GUI sync init form ─────────────────────────── */
@@ -27,22 +269,32 @@ function isValidGitUrl(url: string): 'https' | 'ssh' | false {
27
269
  }
28
270
 
29
271
  function SyncEmptyState({ t, onInitComplete }: { t: Messages; onInitComplete: () => void }) {
30
- const syncT = t.settings?.sync;
272
+ const syncT = t.settings?.sync as Record<string, unknown> | undefined;
31
273
 
32
274
  const [remoteUrl, setRemoteUrl] = useState('');
33
275
  const [token, setToken] = useState('');
34
276
  const [branch, setBranch] = useState('main');
35
277
  const [showToken, setShowToken] = useState(false);
36
- const [connecting, setConnecting] = useState(false);
278
+ const [connectStep, setConnectStep] = useState<number>(-1); // -1=idle, 0..3=steps, 4=done
37
279
  const [error, setError] = useState('');
280
+ const stepTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
281
+
282
+ const connecting = connectStep >= 0 && connectStep < 4;
38
283
 
39
284
  const urlType = remoteUrl.trim() ? isValidGitUrl(remoteUrl.trim()) : null;
40
285
  const isValid = urlType === 'https' || urlType === 'ssh';
41
286
  const showTokenField = urlType === 'https';
42
287
 
43
288
  const handleConnect = async () => {
44
- setConnecting(true);
289
+ setConnectStep(0);
45
290
  setError('');
291
+
292
+ // Progress steps on a timer (visual only — actual work is one API call)
293
+ const advanceStep = (step: number, delayMs: number) =>
294
+ setTimeout(() => setConnectStep(s => s >= 0 && s < 4 ? step : s), delayMs);
295
+ stepTimerRef.current = advanceStep(1, 2000); // "Authenticating..." → "Syncing data..."
296
+ const t2 = advanceStep(2, 5000); // → "Almost done..."
297
+
46
298
  try {
47
299
  await apiFetch('/api/sync', {
48
300
  method: 'POST',
@@ -53,128 +305,171 @@ function SyncEmptyState({ t, onInitComplete }: { t: Messages; onInitComplete: ()
53
305
  token: token.trim() || undefined,
54
306
  branch: branch.trim() || 'main',
55
307
  }),
308
+ timeout: 120_000,
56
309
  });
57
- onInitComplete();
310
+ setConnectStep(4); // success
311
+ setTimeout(() => onInitComplete(), 600);
58
312
  } catch (err: unknown) {
59
- const msg = err instanceof Error ? err.message : 'Connection failed';
60
- setError(msg);
313
+ let msg = err instanceof Error ? err.message : 'Connection failed';
314
+ if (msg.includes('timed out')) {
315
+ msg = (syncT?.timeoutError as string) ?? 'Connection timed out. The remote repository may be large or the network is slow. Please try again.';
316
+ }
317
+ const hint = getSyncErrorHint(msg, remoteUrl, syncT);
318
+ setError(hint ? `${msg}\n${hint}` : msg);
319
+ setConnectStep(-1);
61
320
  } finally {
62
- setConnecting(false);
321
+ if (stepTimerRef.current) clearTimeout(stepTimerRef.current);
322
+ clearTimeout(t2);
63
323
  }
64
324
  };
65
325
 
326
+ const connectSteps = [
327
+ (syncT?.stepConnecting as string) ?? 'Connecting to remote...',
328
+ (syncT?.stepAuthenticating as string) ?? 'Authenticating...',
329
+ (syncT?.stepSyncing as string) ?? 'Syncing data...',
330
+ (syncT?.stepAlmostDone as string) ?? 'Almost done...',
331
+ ];
332
+
66
333
  return (
67
- <div className="space-y-6">
68
- {/* Header */}
69
- <div className="flex items-center gap-3">
70
- <div className="w-9 h-9 rounded-lg bg-muted flex items-center justify-center shrink-0">
71
- <GitBranch size={18} className="text-muted-foreground" />
72
- </div>
73
- <div>
74
- <h3 className="text-sm font-medium text-foreground">
75
- {syncT?.emptyTitle ?? 'Cross-device Sync'}
76
- </h3>
77
- <p className="text-xs text-muted-foreground mt-0.5">
78
- {syncT?.emptyDesc ?? 'Automatically sync your knowledge base across devices via Git.'}
79
- </p>
80
- </div>
81
- </div>
334
+ <div className="space-y-4">
335
+ <SettingCard
336
+ icon={<GitBranch size={15} />}
337
+ title={(syncT?.emptyTitle as string) ?? 'Cross-device Sync'}
338
+ description={(syncT?.emptyDesc as string) ?? 'Automatically sync your knowledge base across devices via Git.'}
339
+ >
340
+ {/* Git Remote URL */}
341
+ <Field
342
+ label={(syncT?.remoteUrl as string) ?? 'Git Remote URL'}
343
+ hint={urlType === 'ssh'
344
+ ? ((syncT?.sshHint as string) ?? 'Requires SSH key on this machine. Verify with: ssh -T git@github.com')
345
+ : undefined
346
+ }
347
+ >
348
+ <Input
349
+ type="text"
350
+ value={remoteUrl}
351
+ onChange={e => { setRemoteUrl(e.target.value); setError(''); }}
352
+ placeholder="git@github.com:user/repo.git"
353
+ className={`font-mono ${remoteUrl.trim() && !isValid ? 'border-destructive' : ''}`}
354
+ />
355
+ {!remoteUrl.trim() && (
356
+ <div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground mt-1.5">
357
+ <span><code className="text-foreground/60 bg-muted/60 px-1 py-0.5 rounded text-2xs">SSH</code> {(syncT?.sshBrief as string) ?? 'one-time key setup, no token needed'}</span>
358
+ <span><code className="text-foreground/60 bg-muted/60 px-1 py-0.5 rounded text-2xs">HTTPS</code> {(syncT?.httpsBrief as string) ?? 'works anywhere, token recommended'}</span>
359
+ </div>
360
+ )}
361
+ {remoteUrl.trim() && !isValid && (
362
+ <p className="text-xs text-destructive mt-1">
363
+ {(syncT?.invalidUrl as string) ?? 'Invalid Git URL — use HTTPS (https://...) or SSH (git@...)'}
364
+ </p>
365
+ )}
366
+ </Field>
82
367
 
83
- {/* Git Remote URL */}
84
- <div className="space-y-1.5">
85
- <label className="text-sm font-medium text-foreground block">
86
- {syncT?.remoteUrl ?? 'Git Remote URL'}
87
- </label>
88
- <Input
89
- type="text"
90
- value={remoteUrl}
91
- onChange={e => { setRemoteUrl(e.target.value); setError(''); }}
92
- placeholder="https://github.com/user/my-mind.git"
93
- className={`font-mono ${remoteUrl.trim() && !isValid ? 'border-destructive' : ''}`}
94
- />
95
- {remoteUrl.trim() && !isValid && (
96
- <p className="text-xs text-destructive">
97
- {syncT?.invalidUrl ?? 'Invalid Git URL — use HTTPS (https://...) or SSH (git@...)'}
98
- </p>
368
+ {/* Access Token (HTTPS only) */}
369
+ {showTokenField && (
370
+ <Field
371
+ label={<>{(syncT?.accessToken as string) ?? 'Access Token'} <span className="text-muted-foreground font-normal">{(syncT?.optional as string) ?? '(optional, for private repos)'}</span></>}
372
+ hint={undefined}
373
+ >
374
+ <div className="relative">
375
+ <Input
376
+ type={showToken ? 'text' : 'password'}
377
+ value={token}
378
+ onChange={e => setToken(e.target.value)}
379
+ placeholder="ghp_xxxxxxxxxxxx"
380
+ className="pr-9 font-mono"
381
+ />
382
+ <button
383
+ type="button"
384
+ onClick={() => setShowToken(!showToken)}
385
+ className="absolute right-2 top-1/2 -translate-y-1/2 p-0.5 rounded hover:bg-muted text-muted-foreground transition-colors"
386
+ >
387
+ {showToken ? <EyeOff size={14} /> : <Eye size={14} />}
388
+ </button>
389
+ </div>
390
+ <p className="text-xs text-muted-foreground mt-1">
391
+ {(syncT?.tokenHint as string) ?? 'GitHub:'}{' '}
392
+ <a
393
+ href="https://github.com/settings/tokens/new?scopes=repo&description=MindOS+Sync"
394
+ target="_blank"
395
+ rel="noopener noreferrer"
396
+ className="underline hover:text-foreground transition-colors"
397
+ >
398
+ {(syncT?.tokenLink as string) ?? 'Create a token (repo scope)'}
399
+ </a>
400
+ </p>
401
+ </Field>
99
402
  )}
100
- {urlType === 'ssh' && (
101
- <p className="text-xs text-muted-foreground flex items-center gap-1">
102
- <AlertCircle size={11} className="shrink-0" />
103
- {syncT?.sshHint ?? 'SSH URLs require SSH key configured on this machine. HTTPS with token recommended.'}
104
- </p>
403
+
404
+ {/* Branch */}
405
+ <Field label={(syncT?.branchLabel as string) ?? 'Branch'}>
406
+ <Input
407
+ type="text"
408
+ value={branch}
409
+ onChange={e => setBranch(e.target.value)}
410
+ placeholder="main"
411
+ className="max-w-[200px] font-mono"
412
+ />
413
+ </Field>
414
+
415
+ {/* Connect button + progress */}
416
+ {!connecting && connectStep !== 4 && (
417
+ <PrimaryButton
418
+ onClick={handleConnect}
419
+ disabled={!isValid}
420
+ className="flex items-center gap-2"
421
+ >
422
+ {(syncT?.connectButton as string) ?? 'Connect & Start Sync'}
423
+ </PrimaryButton>
105
424
  )}
106
- </div>
107
425
 
108
- {/* Access Token (HTTPS only) */}
109
- {showTokenField && (
110
- <div className="space-y-1.5">
111
- <label className="text-sm font-medium text-foreground block">
112
- {syncT?.accessToken ?? 'Access Token'}{' '}
113
- <span className="text-muted-foreground font-normal">{syncT?.optional ?? '(optional, for private repos)'}</span>
114
- </label>
115
- <div className="relative">
116
- <Input
117
- type={showToken ? 'text' : 'password'}
118
- value={token}
119
- onChange={e => setToken(e.target.value)}
120
- placeholder="ghp_xxxxxxxxxxxx"
121
- className="pr-9 font-mono"
122
- />
123
- <button
124
- type="button"
125
- onClick={() => setShowToken(!showToken)}
126
- className="absolute right-2 top-1/2 -translate-y-1/2 p-0.5 rounded hover:bg-muted text-muted-foreground transition-colors"
127
- >
128
- {showToken ? <EyeOff size={14} /> : <Eye size={14} />}
129
- </button>
426
+ {(connecting || connectStep === 4) && (
427
+ <div className="space-y-2 py-1">
428
+ {connectSteps.map((label, i) => {
429
+ const isDone = connectStep > i || connectStep === 4;
430
+ const isActive = connectStep === i && connectStep < 4;
431
+ if (connectStep < i && connectStep < 4) return null; // not yet
432
+ return (
433
+ <div key={i} className="flex items-center gap-2 text-xs">
434
+ {isDone
435
+ ? <Check size={13} className="text-success shrink-0" />
436
+ : <Loader2 size={13} className="animate-spin text-muted-foreground shrink-0" />
437
+ }
438
+ <span className={isDone ? 'text-success' : isActive ? 'text-foreground' : 'text-muted-foreground'}>
439
+ {label}
440
+ </span>
441
+ </div>
442
+ );
443
+ })}
444
+ {connectStep === 4 && (
445
+ <div className="flex items-center gap-2 text-xs">
446
+ <CheckCircle2 size={13} className="text-success shrink-0" />
447
+ <span className="text-success font-medium">{(syncT?.stepDone as string) ?? 'Sync configured successfully!'}</span>
448
+ </div>
449
+ )}
130
450
  </div>
131
- <p className="text-xs text-muted-foreground">
132
- {syncT?.tokenHint ?? 'GitHub: Settings → Developer settings → Personal access tokens → repo scope'}
133
- </p>
134
- </div>
135
- )}
136
-
137
- {/* Branch */}
138
- <div className="space-y-1.5">
139
- <label className="text-sm font-medium text-foreground block">
140
- {syncT?.branchLabel ?? 'Branch'}
141
- </label>
142
- <Input
143
- type="text"
144
- value={branch}
145
- onChange={e => setBranch(e.target.value)}
146
- placeholder="main"
147
- className="max-w-[200px] font-mono"
148
- />
149
- </div>
451
+ )}
150
452
 
151
- {/* Connect button */}
152
- <PrimaryButton
153
- onClick={handleConnect}
154
- disabled={!isValid || connecting}
155
- className="flex items-center gap-2"
156
- >
157
- {connecting && <Loader2 size={14} className="animate-spin" />}
158
- {connecting
159
- ? (syncT?.connecting ?? 'Connecting...')
160
- : (syncT?.connectButton ?? 'Connect & Start Sync')}
161
- </PrimaryButton>
162
-
163
- {/* Error */}
164
- {error && (
165
- <div className="flex items-start gap-2 text-xs p-3 rounded-lg bg-destructive/10 text-destructive" role="alert" aria-live="polite">
166
- <AlertCircle size={13} className="shrink-0 mt-0.5" />
167
- <span>{error}</span>
168
- </div>
169
- )}
453
+ {/* Error */}
454
+ {error && (
455
+ <div className="flex items-start gap-2 text-xs p-3 rounded-lg bg-destructive/10 text-destructive" role="alert" aria-live="polite">
456
+ <AlertCircle size={13} className="shrink-0 mt-0.5" />
457
+ <div className="space-y-1">
458
+ {error.split('\n').map((line, i) => (
459
+ <span key={i} className={`block ${i > 0 ? 'text-destructive/70' : ''}`}>{line}</span>
460
+ ))}
461
+ </div>
462
+ </div>
463
+ )}
464
+ </SettingCard>
170
465
 
171
466
  {/* Features */}
172
- <div className="grid grid-cols-2 gap-2 text-xs text-muted-foreground pt-2">
467
+ <div className="grid grid-cols-2 gap-2 text-xs text-muted-foreground px-5">
173
468
  {[
174
- syncT?.featureAutoCommit ?? 'Auto-commit on save',
175
- syncT?.featureAutoPull ?? 'Auto-pull from remote',
176
- syncT?.featureConflict ?? 'Conflict detection',
177
- syncT?.featureMultiDevice ?? 'Works across devices',
469
+ (syncT?.featureAutoCommit as string) ?? 'Auto-commit on save',
470
+ (syncT?.featureAutoPull as string) ?? 'Auto-pull from remote',
471
+ (syncT?.featureConflict as string) ?? 'Conflict detection',
472
+ (syncT?.featureMultiDevice as string) ?? 'Works across devices',
178
473
  ].map((f, i) => (
179
474
  <div key={i} className="flex items-center gap-1.5">
180
475
  <CheckCircle2 size={11} className="text-success/60 shrink-0" />
@@ -189,6 +484,7 @@ function SyncEmptyState({ t, onInitComplete }: { t: Messages; onInitComplete: ()
189
484
  /* ── Main SyncTab ──────────────────────────────────────────────── */
190
485
 
191
486
  export function SyncTab({ t }: SyncTabProps) {
487
+ const syncT = t.settings?.sync as Record<string, unknown> | undefined;
192
488
  const [status, setStatus] = useState<SyncStatus | null>(null);
193
489
  const [loading, setLoading] = useState(true);
194
490
  const [syncing, setSyncing] = useState(false);
@@ -197,10 +493,12 @@ export function SyncTab({ t }: SyncTabProps) {
197
493
 
198
494
  const fetchStatus = useCallback(async () => {
199
495
  try {
200
- const data = await apiFetch<SyncStatus>('/api/sync');
496
+ const data = await apiFetch<SyncStatus>('/api/sync', { timeout: 10000 });
201
497
  setStatus(data);
202
498
  } catch {
203
- setStatus(null);
499
+ // Keep existing status on refresh failure (don't flash init form during recompile)
500
+ // Only set null if we never had a status (first load)
501
+ setStatus(prev => prev ?? null);
204
502
  } finally {
205
503
  setLoading(false);
206
504
  }
@@ -216,11 +514,13 @@ export function SyncTab({ t }: SyncTabProps) {
216
514
  method: 'POST',
217
515
  headers: { 'Content-Type': 'application/json' },
218
516
  body: JSON.stringify({ action: 'now' }),
517
+ timeout: 120_000, // sync can take 60s+ for large repos
219
518
  });
220
- setMessage({ type: 'success', text: 'Sync complete' });
519
+ setMessage({ type: 'success', text: (syncT?.syncComplete as string) ?? 'Sync complete' });
221
520
  await fetchStatus();
222
- } catch {
223
- setMessage({ type: 'error', text: 'Sync failed' });
521
+ } catch (err: unknown) {
522
+ const raw = err instanceof Error ? err.message : 'Sync failed';
523
+ setMessage({ type: 'error', text: formatSyncError(raw, syncT) });
224
524
  } finally {
225
525
  setSyncing(false);
226
526
  setTimeout(() => setMessage(null), 3000);
@@ -239,9 +539,26 @@ export function SyncTab({ t }: SyncTabProps) {
239
539
  body: JSON.stringify({ action }),
240
540
  });
241
541
  await fetchStatus();
242
- setMessage({ type: 'success', text: status.enabled ? 'Auto-sync disabled' : 'Auto-sync enabled' });
542
+ setMessage({ type: 'success', text: status.enabled ? ((syncT?.autoSyncDisabled as string) ?? 'Auto-sync disabled') : ((syncT?.autoSyncEnabled as string) ?? 'Auto-sync enabled') });
243
543
  } catch {
244
- setMessage({ type: 'error', text: 'Failed to toggle sync' });
544
+ setMessage({ type: 'error', text: (syncT?.toggleFailed as string) ?? 'Failed to toggle sync' });
545
+ } finally {
546
+ setToggling(false);
547
+ setTimeout(() => setMessage(null), 3000);
548
+ }
549
+ };
550
+
551
+ const handleReset = async () => {
552
+ setToggling(true);
553
+ try {
554
+ await apiFetch('/api/sync', {
555
+ method: 'POST',
556
+ headers: { 'Content-Type': 'application/json' },
557
+ body: JSON.stringify({ action: 'reset' }),
558
+ });
559
+ await fetchStatus();
560
+ } catch {
561
+ setMessage({ type: 'error', text: (syncT?.resetFailed as string) ?? 'Failed to reset sync configuration' });
245
562
  } finally {
246
563
  setToggling(false);
247
564
  setTimeout(() => setMessage(null), 3000);
@@ -260,121 +577,189 @@ export function SyncTab({ t }: SyncTabProps) {
260
577
  return <SyncEmptyState t={t} onInitComplete={fetchStatus} />;
261
578
  }
262
579
 
580
+ // Broken state: config says enabled but repo/remote is missing
581
+ if (status.needsSetup) {
582
+ return (
583
+ <div className="space-y-6">
584
+ <div className="flex items-start gap-3 p-4 rounded-lg bg-destructive/10">
585
+ <AlertCircle size={18} className="text-destructive shrink-0 mt-0.5" />
586
+ <div className="space-y-2">
587
+ <h3 className="text-sm font-medium text-destructive">
588
+ {(syncT?.brokenTitle as string) ?? 'Sync configuration is broken'}
589
+ </h3>
590
+ <p className="text-xs text-destructive/80">
591
+ {status.lastError || ((syncT?.brokenDesc as string) ?? 'The git repository or remote is missing. Reset to re-configure.')}
592
+ </p>
593
+ <PrimaryButton
594
+ onClick={handleReset}
595
+ disabled={toggling}
596
+ className="flex items-center gap-2 mt-2"
597
+ >
598
+ {toggling && <Loader2 size={14} className="animate-spin" />}
599
+ {(syncT?.resetButton as string) ?? 'Reset & Re-configure'}
600
+ </PrimaryButton>
601
+ </div>
602
+ </div>
603
+ </div>
604
+ );
605
+ }
606
+
263
607
  const conflicts = status.conflicts || [];
264
608
 
265
609
  return (
266
- <div className="space-y-6">
267
- <SectionLabel>Sync</SectionLabel>
268
-
269
- {/* Status overview */}
270
- <div className="space-y-2.5 text-sm">
271
- <div className="flex items-center gap-2">
272
- <span className="text-muted-foreground w-24 shrink-0">Provider</span>
273
- <span className="font-mono text-sm">{status.provider}</span>
274
- </div>
275
- <div className="flex items-center gap-2">
276
- <span className="text-muted-foreground w-24 shrink-0">Remote</span>
277
- <span className="font-mono text-sm truncate" title={status.remote}>{status.remote}</span>
278
- </div>
279
- <div className="flex items-center gap-2">
280
- <span className="text-muted-foreground w-24 shrink-0">Branch</span>
281
- <span className="font-mono text-sm">{status.branch}</span>
282
- </div>
283
- <div className="flex items-center gap-2">
284
- <span className="text-muted-foreground w-24 shrink-0">Last sync</span>
285
- <span className="text-sm">{timeAgo(status.lastSync)}</span>
286
- </div>
287
- <div className="flex items-center gap-2">
288
- <span className="text-muted-foreground w-24 shrink-0">Unpushed</span>
289
- <span className="text-sm">{status.unpushed} commits</span>
290
- </div>
291
- <div className="flex items-center gap-2">
292
- <span className="text-muted-foreground w-24 shrink-0">Auto-sync</span>
293
- <span className="text-sm">
294
- commit: {status.autoCommitInterval}s, pull: {Math.floor((status.autoPullInterval || 300) / 60)}min
610
+ <div className="space-y-4">
611
+ <SettingCard
612
+ icon={<GitBranch size={15} />}
613
+ title={(syncT?.sectionTitle as string) ?? 'Sync'}
614
+ description={status.remote}
615
+ badge={
616
+ <span className="text-2xs px-1.5 py-0.5 rounded bg-success/15 text-success font-medium">
617
+ {(syncT?.labelEnabled as string) ?? 'Active'}
295
618
  </span>
619
+ }
620
+ >
621
+ {/* Status rows */}
622
+ <div className="space-y-2 text-sm">
623
+ <div className="flex items-center justify-between">
624
+ <span className="text-muted-foreground">{(syncT?.labelBranch as string) ?? 'Branch'}</span>
625
+ <span className="font-mono text-xs">{status.branch}</span>
626
+ </div>
627
+ <div className="flex items-center justify-between">
628
+ <span className="text-muted-foreground">{(syncT?.labelLastSync as string) ?? 'Last sync'}</span>
629
+ <span className="text-xs">{timeAgo(status.lastSync, syncT)}</span>
630
+ </div>
631
+ <div className="flex items-center justify-between">
632
+ <span className="text-muted-foreground">{(syncT?.labelUnpushed as string) ?? 'Unpushed'}</span>
633
+ <span className="text-xs">
634
+ {typeof status.unpushed === 'string' && /^\d+$/.test(status.unpushed)
635
+ ? ((syncT?.unpushedCommits as ((n: number) => string))?.(parseInt(status.unpushed, 10)) ?? `${status.unpushed} commits`)
636
+ : `${status.unpushed ?? '?'} commits`}
637
+ </span>
638
+ </div>
639
+ <div className="flex items-center justify-between">
640
+ <span className="text-muted-foreground">{(syncT?.labelAutoSync as string) ?? 'Auto-sync'}</span>
641
+ <span className="flex items-center gap-1 text-xs">
642
+ commit{' '}
643
+ <select
644
+ className="bg-muted rounded px-1.5 py-0.5 text-xs border border-border cursor-pointer"
645
+ value={status.autoCommitInterval}
646
+ onChange={async (e) => {
647
+ const val = parseInt(e.target.value, 10);
648
+ try {
649
+ const res = await fetch('/api/sync', {
650
+ method: 'POST',
651
+ headers: { 'Content-Type': 'application/json' },
652
+ body: JSON.stringify({ action: 'update-intervals', autoCommitInterval: val }),
653
+ });
654
+ if (res.ok) fetchStatus();
655
+ } catch {}
656
+ }}
657
+ >
658
+ <option value={10}>10s</option>
659
+ <option value={15}>15s</option>
660
+ <option value={30}>30s</option>
661
+ <option value={60}>60s</option>
662
+ <option value={120}>120s</option>
663
+ </select>
664
+ {' · pull '}
665
+ <select
666
+ className="bg-muted rounded px-1.5 py-0.5 text-xs border border-border cursor-pointer"
667
+ value={status.autoPullInterval}
668
+ onChange={async (e) => {
669
+ const val = parseInt(e.target.value, 10);
670
+ try {
671
+ const res = await fetch('/api/sync', {
672
+ method: 'POST',
673
+ headers: { 'Content-Type': 'application/json' },
674
+ body: JSON.stringify({ action: 'update-intervals', autoPullInterval: val }),
675
+ });
676
+ if (res.ok) fetchStatus();
677
+ } catch {}
678
+ }}
679
+ >
680
+ <option value={60}>1min</option>
681
+ <option value={120}>2min</option>
682
+ <option value={300}>5min</option>
683
+ <option value={600}>10min</option>
684
+ <option value={1800}>30min</option>
685
+ <option value={3600}>60min</option>
686
+ </select>
687
+ </span>
688
+ </div>
296
689
  </div>
297
- </div>
298
-
299
- {/* Actions */}
300
- <div className="flex items-center gap-2 pt-2">
301
- <button
302
- type="button"
303
- onClick={handleSyncNow}
304
- disabled={syncing}
305
- title={syncing ? t.hints.syncInProgress : undefined}
306
- className="flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
307
- >
308
- <RefreshCw size={12} className={syncing ? 'animate-spin' : ''} />
309
- Sync Now
310
- </button>
311
- <button
312
- type="button"
313
- onClick={handleToggle}
314
- disabled={toggling}
315
- title={toggling ? t.hints.toggleInProgress : undefined}
316
- className={`flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-lg border transition-colors disabled:opacity-40 disabled:cursor-not-allowed ${
317
- status.enabled
318
- ? 'border-border text-muted-foreground hover:text-destructive hover:border-destructive/50'
319
- : 'border-success/30 text-success hover:bg-success/10'
320
- }`}
321
- >
322
- {status.enabled ? 'Disable Auto-sync' : 'Enable Auto-sync'}
323
- </button>
324
- </div>
325
690
 
326
- {/* Message */}
327
- {message && (
328
- <div className="flex items-center gap-1.5 text-xs" role="status" aria-live="polite">
329
- {message.type === 'success' ? (
330
- <><CheckCircle2 size={13} className="text-success" /><span className="text-success">{message.text}</span></>
331
- ) : (
332
- <><AlertCircle size={13} className="text-destructive" /><span className="text-destructive">{message.text}</span></>
333
- )}
691
+ {/* Actions */}
692
+ <div className="flex items-center gap-2 pt-1">
693
+ <button
694
+ type="button"
695
+ onClick={handleSyncNow}
696
+ disabled={syncing}
697
+ className="flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
698
+ >
699
+ <RefreshCw size={12} className={syncing ? 'animate-spin' : ''} />
700
+ {(syncT?.syncNow as string) ?? 'Sync Now'}
701
+ </button>
702
+ <button
703
+ type="button"
704
+ onClick={handleToggle}
705
+ disabled={toggling}
706
+ className="flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-lg border border-border text-muted-foreground hover:text-destructive hover:border-destructive/50 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
707
+ >
708
+ {(syncT?.disableAutoSync as string) ?? 'Disable Auto-sync'}
709
+ </button>
334
710
  </div>
335
- )}
336
711
 
337
- {/* Conflicts (Task H — enhanced with links) */}
338
- {conflicts.length > 0 && (
339
- <div className="pt-2 border-t border-border">
340
- <SectionLabel>Conflicts ({conflicts.length})</SectionLabel>
341
- <div className="space-y-1.5">
342
- {conflicts.map((c, i) => (
343
- <div key={i} className="flex items-center gap-2 text-xs group">
344
- <AlertCircle size={12} className="text-error shrink-0" />
345
- <a
346
- href={`/view/${encodeURIComponent(c.file)}`}
347
- className="font-mono truncate hover:text-foreground hover:underline transition-colors"
348
- title={`Open ${c.file}`}
349
- >
350
- {c.file}
351
- </a>
352
- <a
353
- href={`/view/${encodeURIComponent(c.file + '.sync-conflict')}`}
354
- className="opacity-0 group-hover:opacity-100 transition-opacity shrink-0 text-muted-foreground hover:text-foreground"
355
- title="View remote version (.sync-conflict)"
356
- >
357
- <ExternalLink size={11} />
358
- </a>
359
- <span className="text-muted-foreground shrink-0 ml-auto">{timeAgo(c.time)}</span>
360
- </div>
361
- ))}
712
+ {/* Message */}
713
+ {message && (
714
+ <div className="flex items-start gap-1.5 text-xs" role="status" aria-live="polite">
715
+ {message.type === 'success' ? (
716
+ <><CheckCircle2 size={13} className="text-success shrink-0 mt-0.5" /><span className="text-success">{message.text}</span></>
717
+ ) : (
718
+ <>
719
+ <AlertCircle size={13} className="text-destructive shrink-0 mt-0.5" />
720
+ <div className="space-y-0.5">
721
+ {message.text.split('\n').map((line, i) => (
722
+ <span key={i} className={`block ${i > 0 ? 'text-destructive/70' : 'text-destructive'}`}>{line}</span>
723
+ ))}
724
+ </div>
725
+ </>
726
+ )}
362
727
  </div>
363
- <p className="text-xs text-muted-foreground mt-2">
364
- Click a file to view your version. Hover and click <ExternalLink size={10} className="inline" /> to see the remote version.
365
- </p>
366
- </div>
367
- )}
728
+ )}
729
+
730
+ {/* Conflicts */}
731
+ {conflicts.length > 0 && (
732
+ <div className="pt-2 border-t border-border/50 space-y-3">
733
+ <p className="text-xs font-medium text-foreground">
734
+ {(syncT?.conflictsTitle as ((n: number) => string))?.(conflicts.length) ?? `Conflicts (${conflicts.length})`}
735
+ </p>
736
+ <p className="text-2xs text-muted-foreground">
737
+ {(syncT?.conflictExplain as string) ?? 'These files were changed on both this device and the remote. Choose which version to keep for each file.'}
738
+ </p>
739
+ <div className="space-y-2">
740
+ {conflicts.map((c, i) => (
741
+ <ConflictRow key={i} file={c.file} time={c.time} syncT={syncT} onResolved={fetchStatus} />
742
+ ))}
743
+ </div>
744
+ </div>
745
+ )}
368
746
 
369
- {/* Error */}
370
- {status.lastError && (
371
- <div className="pt-2 border-t border-border">
372
- <div className="flex items-start gap-2 text-xs text-destructive">
747
+ {/* Error — hide if conflicts section already explains the issue */}
748
+ {status.lastError && conflicts.length === 0 && (
749
+ <div className="flex items-start gap-2 text-xs p-2.5 rounded-lg bg-destructive/10 text-destructive">
373
750
  <AlertCircle size={12} className="shrink-0 mt-0.5" />
374
- <span>{status.lastError}</span>
751
+ <div className="space-y-1">
752
+ <span className="block">{status.lastError}</span>
753
+ {getSyncErrorHint(status.lastError, status.remote, syncT) && (
754
+ <span className="block text-destructive/70">{getSyncErrorHint(status.lastError, status.remote, syncT)}</span>
755
+ )}
756
+ </div>
375
757
  </div>
376
- </div>
377
- )}
758
+ )}
759
+
760
+ {/* Gitignore editor */}
761
+ <GitignoreEditor syncT={syncT} />
762
+ </SettingCard>
378
763
  </div>
379
764
  );
380
765
  }