tower-studio 0.1.3 → 0.1.6

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 (872) hide show
  1. package/.next/BUILD_ID +1 -0
  2. package/.next/app-path-routes-manifest.json +41 -0
  3. package/.next/build/chunks/0kjx__pnpm_05m.mc_._.js +6681 -0
  4. package/.next/build/chunks/[root-of-the-server]__0a5dngl._.js +206 -0
  5. package/.next/build/chunks/[root-of-the-server]__13e2v6w._.js +500 -0
  6. package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_0y_r.ay._.js +13 -0
  7. package/.next/build/chunks/[turbopack]_runtime.js +890 -0
  8. package/.next/build/package.json +1 -0
  9. package/.next/build/postcss.js +6 -0
  10. package/.next/build-manifest.json +22 -0
  11. package/.next/cache/.previewinfo +1 -0
  12. package/.next/cache/.rscinfo +1 -0
  13. package/.next/cache/.tsbuildinfo +1 -0
  14. package/.next/diagnostics/build-diagnostics.json +6 -0
  15. package/.next/diagnostics/framework.json +1 -0
  16. package/.next/diagnostics/route-bundle-stats.json +299 -0
  17. package/.next/export-marker.json +6 -0
  18. package/.next/fallback-build-manifest.json +13 -0
  19. package/.next/images-manifest.json +68 -0
  20. package/.next/next-minimal-server.js.nft.json +1 -0
  21. package/.next/next-server.js.nft.json +1 -0
  22. package/.next/package.json +1 -0
  23. package/.next/prerender-manifest.json +278 -0
  24. package/.next/required-server-files.js +339 -0
  25. package/.next/required-server-files.json +339 -0
  26. package/.next/routes-manifest.json +312 -0
  27. package/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
  28. package/.next/server/app/_global-error/page/build-manifest.json +18 -0
  29. package/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
  30. package/.next/server/app/_global-error/page/react-loadable-manifest.json +1 -0
  31. package/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
  32. package/.next/server/app/_global-error/page.js +12 -0
  33. package/.next/server/app/_global-error/page.js.nft.json +1 -0
  34. package/.next/server/app/_global-error/page_client-reference-manifest.js +3 -0
  35. package/.next/server/app/_global-error.html +1 -0
  36. package/.next/server/app/_global-error.meta +15 -0
  37. package/.next/server/app/_global-error.rsc +15 -0
  38. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +5 -0
  39. package/.next/server/app/_global-error.segments/_full.segment.rsc +15 -0
  40. package/.next/server/app/_global-error.segments/_head.segment.rsc +6 -0
  41. package/.next/server/app/_global-error.segments/_index.segment.rsc +5 -0
  42. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  43. package/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
  44. package/.next/server/app/_not-found/page/build-manifest.json +18 -0
  45. package/.next/server/app/_not-found/page/next-font-manifest.json +11 -0
  46. package/.next/server/app/_not-found/page/react-loadable-manifest.json +16 -0
  47. package/.next/server/app/_not-found/page/server-reference-manifest.json +233 -0
  48. package/.next/server/app/_not-found/page.js +20 -0
  49. package/.next/server/app/_not-found/page.js.nft.json +1 -0
  50. package/.next/server/app/_not-found/page_client-reference-manifest.js +3 -0
  51. package/.next/server/app/_not-found.html +1 -0
  52. package/.next/server/app/_not-found.meta +16 -0
  53. package/.next/server/app/_not-found.rsc +24 -0
  54. package/.next/server/app/_not-found.segments/_full.segment.rsc +24 -0
  55. package/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
  56. package/.next/server/app/_not-found.segments/_index.segment.rsc +12 -0
  57. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
  58. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +5 -0
  59. package/.next/server/app/_not-found.segments/_tree.segment.rsc +4 -0
  60. package/.next/server/app/api/adapters/test/route/app-paths-manifest.json +3 -0
  61. package/.next/server/app/api/adapters/test/route/build-manifest.json +9 -0
  62. package/.next/server/app/api/adapters/test/route/server-reference-manifest.json +4 -0
  63. package/.next/server/app/api/adapters/test/route.js +9 -0
  64. package/.next/server/app/api/adapters/test/route.js.nft.json +1 -0
  65. package/.next/server/app/api/adapters/test/route_client-reference-manifest.js +3 -0
  66. package/.next/server/app/api/browse-fs/route/app-paths-manifest.json +3 -0
  67. package/.next/server/app/api/browse-fs/route/build-manifest.json +9 -0
  68. package/.next/server/app/api/browse-fs/route/server-reference-manifest.json +4 -0
  69. package/.next/server/app/api/browse-fs/route.js +7 -0
  70. package/.next/server/app/api/browse-fs/route.js.nft.json +1 -0
  71. package/.next/server/app/api/browse-fs/route_client-reference-manifest.js +3 -0
  72. package/.next/server/app/api/files/assets/[projectId]/[filename]/route/app-paths-manifest.json +3 -0
  73. package/.next/server/app/api/files/assets/[projectId]/[filename]/route/build-manifest.json +9 -0
  74. package/.next/server/app/api/files/assets/[projectId]/[filename]/route/server-reference-manifest.json +4 -0
  75. package/.next/server/app/api/files/assets/[projectId]/[filename]/route.js +7 -0
  76. package/.next/server/app/api/files/assets/[projectId]/[filename]/route.js.nft.json +1 -0
  77. package/.next/server/app/api/files/assets/[projectId]/[filename]/route_client-reference-manifest.js +3 -0
  78. package/.next/server/app/api/git/route/app-paths-manifest.json +3 -0
  79. package/.next/server/app/api/git/route/build-manifest.json +9 -0
  80. package/.next/server/app/api/git/route/server-reference-manifest.json +4 -0
  81. package/.next/server/app/api/git/route.js +8 -0
  82. package/.next/server/app/api/git/route.js.nft.json +1 -0
  83. package/.next/server/app/api/git/route_client-reference-manifest.js +3 -0
  84. package/.next/server/app/api/internal/assets/[projectId]/[filename]/route/app-paths-manifest.json +3 -0
  85. package/.next/server/app/api/internal/assets/[projectId]/[filename]/route/build-manifest.json +9 -0
  86. package/.next/server/app/api/internal/assets/[projectId]/[filename]/route/server-reference-manifest.json +4 -0
  87. package/.next/server/app/api/internal/assets/[projectId]/[filename]/route.js +7 -0
  88. package/.next/server/app/api/internal/assets/[projectId]/[filename]/route.js.nft.json +1 -0
  89. package/.next/server/app/api/internal/assets/[projectId]/[filename]/route_client-reference-manifest.js +3 -0
  90. package/.next/server/app/api/internal/assets/reveal/route/app-paths-manifest.json +3 -0
  91. package/.next/server/app/api/internal/assets/reveal/route/build-manifest.json +9 -0
  92. package/.next/server/app/api/internal/assets/reveal/route/server-reference-manifest.json +4 -0
  93. package/.next/server/app/api/internal/assets/reveal/route.js +7 -0
  94. package/.next/server/app/api/internal/assets/reveal/route.js.nft.json +1 -0
  95. package/.next/server/app/api/internal/assets/reveal/route_client-reference-manifest.js +3 -0
  96. package/.next/server/app/api/internal/assistant/chat/route/app-paths-manifest.json +3 -0
  97. package/.next/server/app/api/internal/assistant/chat/route/build-manifest.json +9 -0
  98. package/.next/server/app/api/internal/assistant/chat/route/server-reference-manifest.json +4 -0
  99. package/.next/server/app/api/internal/assistant/chat/route.js +7 -0
  100. package/.next/server/app/api/internal/assistant/chat/route.js.nft.json +1 -0
  101. package/.next/server/app/api/internal/assistant/chat/route_client-reference-manifest.js +3 -0
  102. package/.next/server/app/api/internal/assistant/images/route/app-paths-manifest.json +3 -0
  103. package/.next/server/app/api/internal/assistant/images/route/build-manifest.json +9 -0
  104. package/.next/server/app/api/internal/assistant/images/route/server-reference-manifest.json +4 -0
  105. package/.next/server/app/api/internal/assistant/images/route.js +9 -0
  106. package/.next/server/app/api/internal/assistant/images/route.js.nft.json +1 -0
  107. package/.next/server/app/api/internal/assistant/images/route_client-reference-manifest.js +3 -0
  108. package/.next/server/app/api/internal/assistant/route/app-paths-manifest.json +3 -0
  109. package/.next/server/app/api/internal/assistant/route/build-manifest.json +9 -0
  110. package/.next/server/app/api/internal/assistant/route/server-reference-manifest.json +4 -0
  111. package/.next/server/app/api/internal/assistant/route.js +7 -0
  112. package/.next/server/app/api/internal/assistant/route.js.nft.json +1 -0
  113. package/.next/server/app/api/internal/assistant/route_client-reference-manifest.js +3 -0
  114. package/.next/server/app/api/internal/assistant/sessions/route/app-paths-manifest.json +3 -0
  115. package/.next/server/app/api/internal/assistant/sessions/route/build-manifest.json +9 -0
  116. package/.next/server/app/api/internal/assistant/sessions/route/server-reference-manifest.json +4 -0
  117. package/.next/server/app/api/internal/assistant/sessions/route.js +7 -0
  118. package/.next/server/app/api/internal/assistant/sessions/route.js.nft.json +1 -0
  119. package/.next/server/app/api/internal/assistant/sessions/route_client-reference-manifest.js +3 -0
  120. package/.next/server/app/api/internal/cache/[...segments]/route/app-paths-manifest.json +3 -0
  121. package/.next/server/app/api/internal/cache/[...segments]/route/build-manifest.json +9 -0
  122. package/.next/server/app/api/internal/cache/[...segments]/route/server-reference-manifest.json +4 -0
  123. package/.next/server/app/api/internal/cache/[...segments]/route.js +7 -0
  124. package/.next/server/app/api/internal/cache/[...segments]/route.js.nft.json +1 -0
  125. package/.next/server/app/api/internal/cache/[...segments]/route_client-reference-manifest.js +3 -0
  126. package/.next/server/app/api/internal/hooks/install/route/app-paths-manifest.json +3 -0
  127. package/.next/server/app/api/internal/hooks/install/route/build-manifest.json +9 -0
  128. package/.next/server/app/api/internal/hooks/install/route/server-reference-manifest.json +4 -0
  129. package/.next/server/app/api/internal/hooks/install/route.js +7 -0
  130. package/.next/server/app/api/internal/hooks/install/route.js.nft.json +1 -0
  131. package/.next/server/app/api/internal/hooks/install/route_client-reference-manifest.js +3 -0
  132. package/.next/server/app/api/internal/hooks/session/route/app-paths-manifest.json +3 -0
  133. package/.next/server/app/api/internal/hooks/session/route/build-manifest.json +9 -0
  134. package/.next/server/app/api/internal/hooks/session/route/server-reference-manifest.json +4 -0
  135. package/.next/server/app/api/internal/hooks/session/route.js +7 -0
  136. package/.next/server/app/api/internal/hooks/session/route.js.nft.json +1 -0
  137. package/.next/server/app/api/internal/hooks/session/route_client-reference-manifest.js +3 -0
  138. package/.next/server/app/api/internal/hooks/stop/route/app-paths-manifest.json +3 -0
  139. package/.next/server/app/api/internal/hooks/stop/route/build-manifest.json +9 -0
  140. package/.next/server/app/api/internal/hooks/stop/route/server-reference-manifest.json +4 -0
  141. package/.next/server/app/api/internal/hooks/stop/route.js +8 -0
  142. package/.next/server/app/api/internal/hooks/stop/route.js.nft.json +1 -0
  143. package/.next/server/app/api/internal/hooks/stop/route_client-reference-manifest.js +3 -0
  144. package/.next/server/app/api/internal/hooks/upload/route/app-paths-manifest.json +3 -0
  145. package/.next/server/app/api/internal/hooks/upload/route/build-manifest.json +9 -0
  146. package/.next/server/app/api/internal/hooks/upload/route/server-reference-manifest.json +4 -0
  147. package/.next/server/app/api/internal/hooks/upload/route.js +7 -0
  148. package/.next/server/app/api/internal/hooks/upload/route.js.nft.json +1 -0
  149. package/.next/server/app/api/internal/hooks/upload/route_client-reference-manifest.js +3 -0
  150. package/.next/server/app/api/internal/notifications/pending/route/app-paths-manifest.json +3 -0
  151. package/.next/server/app/api/internal/notifications/pending/route/build-manifest.json +9 -0
  152. package/.next/server/app/api/internal/notifications/pending/route/server-reference-manifest.json +4 -0
  153. package/.next/server/app/api/internal/notifications/pending/route.js +7 -0
  154. package/.next/server/app/api/internal/notifications/pending/route.js.nft.json +1 -0
  155. package/.next/server/app/api/internal/notifications/pending/route_client-reference-manifest.js +3 -0
  156. package/.next/server/app/api/internal/terminal/[taskId]/buffer/route/app-paths-manifest.json +3 -0
  157. package/.next/server/app/api/internal/terminal/[taskId]/buffer/route/build-manifest.json +9 -0
  158. package/.next/server/app/api/internal/terminal/[taskId]/buffer/route/server-reference-manifest.json +4 -0
  159. package/.next/server/app/api/internal/terminal/[taskId]/buffer/route.js +8 -0
  160. package/.next/server/app/api/internal/terminal/[taskId]/buffer/route.js.nft.json +1 -0
  161. package/.next/server/app/api/internal/terminal/[taskId]/buffer/route_client-reference-manifest.js +3 -0
  162. package/.next/server/app/api/internal/terminal/[taskId]/input/route/app-paths-manifest.json +3 -0
  163. package/.next/server/app/api/internal/terminal/[taskId]/input/route/build-manifest.json +9 -0
  164. package/.next/server/app/api/internal/terminal/[taskId]/input/route/server-reference-manifest.json +4 -0
  165. package/.next/server/app/api/internal/terminal/[taskId]/input/route.js +8 -0
  166. package/.next/server/app/api/internal/terminal/[taskId]/input/route.js.nft.json +1 -0
  167. package/.next/server/app/api/internal/terminal/[taskId]/input/route_client-reference-manifest.js +3 -0
  168. package/.next/server/app/api/internal/terminal/[taskId]/start/route/app-paths-manifest.json +3 -0
  169. package/.next/server/app/api/internal/terminal/[taskId]/start/route/build-manifest.json +9 -0
  170. package/.next/server/app/api/internal/terminal/[taskId]/start/route/server-reference-manifest.json +4 -0
  171. package/.next/server/app/api/internal/terminal/[taskId]/start/route.js +10 -0
  172. package/.next/server/app/api/internal/terminal/[taskId]/start/route.js.nft.json +1 -0
  173. package/.next/server/app/api/internal/terminal/[taskId]/start/route_client-reference-manifest.js +3 -0
  174. package/.next/server/app/api/tasks/[taskId]/diff/route/app-paths-manifest.json +3 -0
  175. package/.next/server/app/api/tasks/[taskId]/diff/route/build-manifest.json +9 -0
  176. package/.next/server/app/api/tasks/[taskId]/diff/route/server-reference-manifest.json +4 -0
  177. package/.next/server/app/api/tasks/[taskId]/diff/route.js +8 -0
  178. package/.next/server/app/api/tasks/[taskId]/diff/route.js.nft.json +1 -0
  179. package/.next/server/app/api/tasks/[taskId]/diff/route_client-reference-manifest.js +3 -0
  180. package/.next/server/app/api/tasks/[taskId]/merge/route/app-paths-manifest.json +3 -0
  181. package/.next/server/app/api/tasks/[taskId]/merge/route/build-manifest.json +9 -0
  182. package/.next/server/app/api/tasks/[taskId]/merge/route/server-reference-manifest.json +4 -0
  183. package/.next/server/app/api/tasks/[taskId]/merge/route.js +9 -0
  184. package/.next/server/app/api/tasks/[taskId]/merge/route.js.nft.json +1 -0
  185. package/.next/server/app/api/tasks/[taskId]/merge/route_client-reference-manifest.js +3 -0
  186. package/.next/server/app/apple-icon.png/route/app-paths-manifest.json +3 -0
  187. package/.next/server/app/apple-icon.png/route/build-manifest.json +9 -0
  188. package/.next/server/app/apple-icon.png/route.js +8 -0
  189. package/.next/server/app/apple-icon.png/route.js.nft.json +1 -0
  190. package/.next/server/app/apple-icon.png.meta +1 -0
  191. package/.next/server/app/favicon.ico/route/app-paths-manifest.json +3 -0
  192. package/.next/server/app/favicon.ico/route/build-manifest.json +9 -0
  193. package/.next/server/app/favicon.ico/route.js +8 -0
  194. package/.next/server/app/favicon.ico/route.js.nft.json +1 -0
  195. package/.next/server/app/favicon.ico.meta +1 -0
  196. package/.next/server/app/icon0.svg/route/app-paths-manifest.json +3 -0
  197. package/.next/server/app/icon0.svg/route/build-manifest.json +9 -0
  198. package/.next/server/app/icon0.svg/route.js +8 -0
  199. package/.next/server/app/icon0.svg/route.js.nft.json +1 -0
  200. package/.next/server/app/icon0.svg.meta +1 -0
  201. package/.next/server/app/icon1.png/route/app-paths-manifest.json +3 -0
  202. package/.next/server/app/icon1.png/route/build-manifest.json +9 -0
  203. package/.next/server/app/icon1.png/route.js +8 -0
  204. package/.next/server/app/icon1.png/route.js.nft.json +1 -0
  205. package/.next/server/app/icon1.png.meta +1 -0
  206. package/.next/server/app/index.html +1 -0
  207. package/.next/server/app/index.meta +16 -0
  208. package/.next/server/app/index.rsc +25 -0
  209. package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -0
  210. package/.next/server/app/index.segments/_full.segment.rsc +25 -0
  211. package/.next/server/app/index.segments/_head.segment.rsc +6 -0
  212. package/.next/server/app/index.segments/_index.segment.rsc +12 -0
  213. package/.next/server/app/index.segments/_tree.segment.rsc +6 -0
  214. package/.next/server/app/manifest.json/route/app-paths-manifest.json +3 -0
  215. package/.next/server/app/manifest.json/route/build-manifest.json +9 -0
  216. package/.next/server/app/manifest.json/route.js +7 -0
  217. package/.next/server/app/manifest.json/route.js.nft.json +1 -0
  218. package/.next/server/app/manifest.json.meta +1 -0
  219. package/.next/server/app/missions/page/app-paths-manifest.json +3 -0
  220. package/.next/server/app/missions/page/build-manifest.json +18 -0
  221. package/.next/server/app/missions/page/next-font-manifest.json +11 -0
  222. package/.next/server/app/missions/page/react-loadable-manifest.json +16 -0
  223. package/.next/server/app/missions/page/server-reference-manifest.json +401 -0
  224. package/.next/server/app/missions/page.js +22 -0
  225. package/.next/server/app/missions/page.js.nft.json +1 -0
  226. package/.next/server/app/missions/page_client-reference-manifest.js +3 -0
  227. package/.next/server/app/onboarding/page/app-paths-manifest.json +3 -0
  228. package/.next/server/app/onboarding/page/build-manifest.json +18 -0
  229. package/.next/server/app/onboarding/page/next-font-manifest.json +11 -0
  230. package/.next/server/app/onboarding/page/react-loadable-manifest.json +16 -0
  231. package/.next/server/app/onboarding/page/server-reference-manifest.json +233 -0
  232. package/.next/server/app/onboarding/page.js +21 -0
  233. package/.next/server/app/onboarding/page.js.nft.json +1 -0
  234. package/.next/server/app/onboarding/page_client-reference-manifest.js +3 -0
  235. package/.next/server/app/onboarding.html +1 -0
  236. package/.next/server/app/onboarding.meta +15 -0
  237. package/.next/server/app/onboarding.rsc +30 -0
  238. package/.next/server/app/onboarding.segments/_full.segment.rsc +30 -0
  239. package/.next/server/app/onboarding.segments/_head.segment.rsc +6 -0
  240. package/.next/server/app/onboarding.segments/_index.segment.rsc +12 -0
  241. package/.next/server/app/onboarding.segments/_tree.segment.rsc +6 -0
  242. package/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +9 -0
  243. package/.next/server/app/onboarding.segments/onboarding.segment.rsc +5 -0
  244. package/.next/server/app/page/app-paths-manifest.json +3 -0
  245. package/.next/server/app/page/build-manifest.json +18 -0
  246. package/.next/server/app/page/next-font-manifest.json +11 -0
  247. package/.next/server/app/page/react-loadable-manifest.json +16 -0
  248. package/.next/server/app/page/server-reference-manifest.json +233 -0
  249. package/.next/server/app/page.js +21 -0
  250. package/.next/server/app/page.js.nft.json +1 -0
  251. package/.next/server/app/page_client-reference-manifest.js +3 -0
  252. package/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  253. package/.next/server/app/settings/page/build-manifest.json +18 -0
  254. package/.next/server/app/settings/page/next-font-manifest.json +11 -0
  255. package/.next/server/app/settings/page/react-loadable-manifest.json +16 -0
  256. package/.next/server/app/settings/page/server-reference-manifest.json +341 -0
  257. package/.next/server/app/settings/page.js +21 -0
  258. package/.next/server/app/settings/page.js.nft.json +1 -0
  259. package/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  260. package/.next/server/app/settings.html +1 -0
  261. package/.next/server/app/settings.meta +15 -0
  262. package/.next/server/app/settings.rsc +30 -0
  263. package/.next/server/app/settings.segments/_full.segment.rsc +30 -0
  264. package/.next/server/app/settings.segments/_head.segment.rsc +6 -0
  265. package/.next/server/app/settings.segments/_index.segment.rsc +12 -0
  266. package/.next/server/app/settings.segments/_tree.segment.rsc +6 -0
  267. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +9 -0
  268. package/.next/server/app/settings.segments/settings.segment.rsc +5 -0
  269. package/.next/server/app/workspaces/[workspaceId]/archive/page/app-paths-manifest.json +3 -0
  270. package/.next/server/app/workspaces/[workspaceId]/archive/page/build-manifest.json +18 -0
  271. package/.next/server/app/workspaces/[workspaceId]/archive/page/next-font-manifest.json +11 -0
  272. package/.next/server/app/workspaces/[workspaceId]/archive/page/react-loadable-manifest.json +16 -0
  273. package/.next/server/app/workspaces/[workspaceId]/archive/page/server-reference-manifest.json +497 -0
  274. package/.next/server/app/workspaces/[workspaceId]/archive/page.js +21 -0
  275. package/.next/server/app/workspaces/[workspaceId]/archive/page.js.nft.json +1 -0
  276. package/.next/server/app/workspaces/[workspaceId]/archive/page_client-reference-manifest.js +3 -0
  277. package/.next/server/app/workspaces/[workspaceId]/assets/page/app-paths-manifest.json +3 -0
  278. package/.next/server/app/workspaces/[workspaceId]/assets/page/build-manifest.json +18 -0
  279. package/.next/server/app/workspaces/[workspaceId]/assets/page/next-font-manifest.json +11 -0
  280. package/.next/server/app/workspaces/[workspaceId]/assets/page/react-loadable-manifest.json +16 -0
  281. package/.next/server/app/workspaces/[workspaceId]/assets/page/server-reference-manifest.json +461 -0
  282. package/.next/server/app/workspaces/[workspaceId]/assets/page.js +21 -0
  283. package/.next/server/app/workspaces/[workspaceId]/assets/page.js.nft.json +1 -0
  284. package/.next/server/app/workspaces/[workspaceId]/assets/page_client-reference-manifest.js +3 -0
  285. package/.next/server/app/workspaces/[workspaceId]/notes/page/app-paths-manifest.json +3 -0
  286. package/.next/server/app/workspaces/[workspaceId]/notes/page/build-manifest.json +18 -0
  287. package/.next/server/app/workspaces/[workspaceId]/notes/page/next-font-manifest.json +11 -0
  288. package/.next/server/app/workspaces/[workspaceId]/notes/page/react-loadable-manifest.json +16 -0
  289. package/.next/server/app/workspaces/[workspaceId]/notes/page/server-reference-manifest.json +401 -0
  290. package/.next/server/app/workspaces/[workspaceId]/notes/page.js +21 -0
  291. package/.next/server/app/workspaces/[workspaceId]/notes/page.js.nft.json +1 -0
  292. package/.next/server/app/workspaces/[workspaceId]/notes/page_client-reference-manifest.js +3 -0
  293. package/.next/server/app/workspaces/[workspaceId]/page/app-paths-manifest.json +3 -0
  294. package/.next/server/app/workspaces/[workspaceId]/page/build-manifest.json +18 -0
  295. package/.next/server/app/workspaces/[workspaceId]/page/next-font-manifest.json +11 -0
  296. package/.next/server/app/workspaces/[workspaceId]/page/react-loadable-manifest.json +16 -0
  297. package/.next/server/app/workspaces/[workspaceId]/page/server-reference-manifest.json +569 -0
  298. package/.next/server/app/workspaces/[workspaceId]/page.js +22 -0
  299. package/.next/server/app/workspaces/[workspaceId]/page.js.nft.json +1 -0
  300. package/.next/server/app/workspaces/[workspaceId]/page_client-reference-manifest.js +3 -0
  301. package/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page/app-paths-manifest.json +3 -0
  302. package/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page/build-manifest.json +18 -0
  303. package/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page/next-font-manifest.json +11 -0
  304. package/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page/react-loadable-manifest.json +16 -0
  305. package/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page/server-reference-manifest.json +233 -0
  306. package/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page.js +21 -0
  307. package/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page.js.nft.json +1 -0
  308. package/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page_client-reference-manifest.js +3 -0
  309. package/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page/app-paths-manifest.json +3 -0
  310. package/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page/build-manifest.json +18 -0
  311. package/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page/next-font-manifest.json +11 -0
  312. package/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page/react-loadable-manifest.json +22 -0
  313. package/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page/server-reference-manifest.json +581 -0
  314. package/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page.js +23 -0
  315. package/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page.js.nft.json +1 -0
  316. package/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page_client-reference-manifest.js +3 -0
  317. package/.next/server/app/workspaces/page/app-paths-manifest.json +3 -0
  318. package/.next/server/app/workspaces/page/build-manifest.json +18 -0
  319. package/.next/server/app/workspaces/page/next-font-manifest.json +11 -0
  320. package/.next/server/app/workspaces/page/react-loadable-manifest.json +16 -0
  321. package/.next/server/app/workspaces/page/server-reference-manifest.json +329 -0
  322. package/.next/server/app/workspaces/page.js +21 -0
  323. package/.next/server/app/workspaces/page.js.nft.json +1 -0
  324. package/.next/server/app/workspaces/page_client-reference-manifest.js +3 -0
  325. package/.next/server/app-paths-manifest.json +41 -0
  326. package/.next/server/chunks/03j-_@anthropic-ai_claude-agent-sdk_sdk_mjs_04597t~._.js +85 -0
  327. package/.next/server/chunks/0cve_next-internal_server_app_api_internal_cache_[___segments]_route_actions_09n1sa3.js +3 -0
  328. package/.next/server/chunks/0tp-_server_app_api_files_assets_[projectId]_[filename]_route_actions_02i2urs.js +3 -0
  329. package/.next/server/chunks/0tp-_server_app_api_internal_assets_[projectId]_[filename]_route_actions_0kjz576.js +3 -0
  330. package/.next/server/chunks/0tp-_server_app_api_internal_notifications_pending_route_actions_08bx38r.js +3 -0
  331. package/.next/server/chunks/0tp-_server_app_api_internal_terminal_[taskId]_buffer_route_actions_0bpyf5x.js +3 -0
  332. package/.next/server/chunks/0tp-_server_app_api_internal_terminal_[taskId]_input_route_actions_0alu32r.js +3 -0
  333. package/.next/server/chunks/0tp-_server_app_api_internal_terminal_[taskId]_start_route_actions_0swqog2.js +3 -0
  334. package/.next/server/chunks/0w1v_zod_v4_classic_external_0m-7hz_.js +39 -0
  335. package/.next/server/chunks/0~.g__next-internal_server_app_api_internal_assistant_chat_route_actions_0x-qbrh.js +3 -0
  336. package/.next/server/chunks/0~.g__next-internal_server_app_api_internal_assistant_images_route_actions_0vws40t.js +3 -0
  337. package/.next/server/chunks/0~.g__next-internal_server_app_api_internal_assistant_sessions_route_actions_0p09rcp.js +3 -0
  338. package/.next/server/chunks/10ge_next_dist_08.3req._.js +13 -0
  339. package/.next/server/chunks/10ge_next_dist_esm_build_templates_app-route_00gmiw_.js +3 -0
  340. package/.next/server/chunks/10ge_next_dist_esm_build_templates_app-route_0jwpolf.js +3 -0
  341. package/.next/server/chunks/10ge_next_dist_esm_build_templates_app-route_0liabcf.js +3 -0
  342. package/.next/server/chunks/10ge_next_dist_esm_build_templates_app-route_0z9_0_i.js +3 -0
  343. package/.next/server/chunks/10ge_next_dist_esm_build_templates_app-route_13w3ubu.js +3 -0
  344. package/.next/server/chunks/10ge_next_dist_esm_build_templates_app-route_13~vb_i.js +4 -0
  345. package/.next/server/chunks/[externals]__02xkqim._.js +3 -0
  346. package/.next/server/chunks/[externals]__09oeovy._.js +3 -0
  347. package/.next/server/chunks/[externals]__0~rg.xo._.js +3 -0
  348. package/.next/server/chunks/[externals]__11rejr-._.js +3 -0
  349. package/.next/server/chunks/[externals]_child_process_0pwkpv9._.js +3 -0
  350. package/.next/server/chunks/[externals]_next_dist_0g2nsos._.js +3 -0
  351. package/.next/server/chunks/[externals]_util_0wtvqkc._.js +3 -0
  352. package/.next/server/chunks/[root-of-the-server]__02p-gd5._.js +3 -0
  353. package/.next/server/chunks/[root-of-the-server]__0319djr._.js +3 -0
  354. package/.next/server/chunks/[root-of-the-server]__043lk8~._.js +4 -0
  355. package/.next/server/chunks/[root-of-the-server]__053y9tf._.js +3 -0
  356. package/.next/server/chunks/[root-of-the-server]__05pxb~w._.js +20 -0
  357. package/.next/server/chunks/[root-of-the-server]__07-am_7._.js +20 -0
  358. package/.next/server/chunks/[root-of-the-server]__09gjz6h._.js +3 -0
  359. package/.next/server/chunks/[root-of-the-server]__0_irb2s._.js +3 -0
  360. package/.next/server/chunks/[root-of-the-server]__0c4edwt._.js +3 -0
  361. package/.next/server/chunks/[root-of-the-server]__0c7y1r0._.js +3 -0
  362. package/.next/server/chunks/[root-of-the-server]__0dj34zn._.js +3 -0
  363. package/.next/server/chunks/[root-of-the-server]__0dqta7g._.js +3 -0
  364. package/.next/server/chunks/[root-of-the-server]__0j3gbp7._.js +3 -0
  365. package/.next/server/chunks/[root-of-the-server]__0ko_rm_._.js +3 -0
  366. package/.next/server/chunks/[root-of-the-server]__0miy2g.._.js +3 -0
  367. package/.next/server/chunks/[root-of-the-server]__0mt-eeb._.js +3 -0
  368. package/.next/server/chunks/[root-of-the-server]__0n-6-hc._.js +3 -0
  369. package/.next/server/chunks/[root-of-the-server]__0nur_ir._.js +3 -0
  370. package/.next/server/chunks/[root-of-the-server]__0pz60q-._.js +20 -0
  371. package/.next/server/chunks/[root-of-the-server]__0q~5ya5._.js +3 -0
  372. package/.next/server/chunks/[root-of-the-server]__0rpqx55._.js +3 -0
  373. package/.next/server/chunks/[root-of-the-server]__0sjsc63._.js +4 -0
  374. package/.next/server/chunks/[root-of-the-server]__0th.w7w._.js +3 -0
  375. package/.next/server/chunks/[root-of-the-server]__0u..agy._.js +11 -0
  376. package/.next/server/chunks/[root-of-the-server]__0umzekq._.js +3 -0
  377. package/.next/server/chunks/[root-of-the-server]__0wu61w.._.js +3 -0
  378. package/.next/server/chunks/[root-of-the-server]__11v.yk_._.js +4 -0
  379. package/.next/server/chunks/[root-of-the-server]__12._zd-._.js +3 -0
  380. package/.next/server/chunks/[root-of-the-server]__130shf~._.js +3 -0
  381. package/.next/server/chunks/[turbopack]_runtime.js +903 -0
  382. package/.next/server/chunks/ssr/03j-_@anthropic-ai_claude-agent-sdk_sdk_mjs_0kr2_y.._.js +84 -0
  383. package/.next/server/chunks/ssr/040e_@monaco-editor_react_dist_index_mjs_0t4i-ho._.js +3 -0
  384. package/.next/server/chunks/ssr/040e_@monaco-editor_react_dist_index_mjs_0z6t1fr._.js +3 -0
  385. package/.next/server/chunks/ssr/0kjx__pnpm_0g9g8h6._.js +3 -0
  386. package/.next/server/chunks/ssr/0kjx__pnpm_0l.5ii.._.js +3 -0
  387. package/.next/server/chunks/ssr/0kjx__pnpm_0wrn.h9._.js +14 -0
  388. package/.next/server/chunks/ssr/0rik_@dnd-kit_core_dist_core_esm_11giptg.js +3 -0
  389. package/.next/server/chunks/ssr/0~.g_src_app_workspaces_[workspaceId]_tasks_[taskId]_task-page-client_tsx_0bbseig._.js +3 -0
  390. package/.next/server/chunks/ssr/10ge_next_00.-vj.._.js +18 -0
  391. package/.next/server/chunks/ssr/10ge_next_dist_01n~t8z._.js +6 -0
  392. package/.next/server/chunks/ssr/10ge_next_dist_06_-w96._.js +19 -0
  393. package/.next/server/chunks/ssr/10ge_next_dist_0pw4my6._.js +6 -0
  394. package/.next/server/chunks/ssr/10ge_next_dist_0wjbiu9._.js +3 -0
  395. package/.next/server/chunks/ssr/10ge_next_dist_0~ti7jc._.js +3 -0
  396. package/.next/server/chunks/ssr/10ge_next_dist_10.ihny._.js +3 -0
  397. package/.next/server/chunks/ssr/10ge_next_dist_client_components_0--gzcy._.js +3 -0
  398. package/.next/server/chunks/ssr/10ge_next_dist_client_components_0eil7-a._.js +33 -0
  399. package/.next/server/chunks/ssr/10ge_next_dist_client_components_builtin_forbidden_0nzsnb2.js +3 -0
  400. package/.next/server/chunks/ssr/10ge_next_dist_client_components_builtin_global-error_125sopd.js +3 -0
  401. package/.next/server/chunks/ssr/10ge_next_dist_client_components_builtin_unauthorized_0z93cpe.js +3 -0
  402. package/.next/server/chunks/ssr/10ge_next_dist_compiled_0g45ze2._.js +3 -0
  403. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_080g02v.js +4 -0
  404. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_08khzah.js +4 -0
  405. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_09~o5q0.js +4 -0
  406. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_0_rj_f4.js +4 -0
  407. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_0c-wmj1.js +4 -0
  408. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_0fjd2ua.js +4 -0
  409. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_0hpuyf0.js +4 -0
  410. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_0knnyic.js +4 -0
  411. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_0oi86k6.js +4 -0
  412. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_0rmwdra.js +4 -0
  413. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_0zgisbd.js +4 -0
  414. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_11pz1fw.js +4 -0
  415. package/.next/server/chunks/ssr/10ge_next_dist_esm_build_templates_app-page_12reczc.js +4 -0
  416. package/.next/server/chunks/ssr/119e_lucide-react_dist_esm_icons_0636jyq._.js +3 -0
  417. package/.next/server/chunks/ssr/[externals]__0of4r_r._.js +3 -0
  418. package/.next/server/chunks/ssr/[externals]__0z1ffhu._.js +3 -0
  419. package/.next/server/chunks/ssr/[externals]_child_process_0pwkpv9._.js +3 -0
  420. package/.next/server/chunks/ssr/[root-of-the-server]__0-0j_z3._.js +3 -0
  421. package/.next/server/chunks/ssr/[root-of-the-server]__0.8y0n9._.js +3 -0
  422. package/.next/server/chunks/ssr/[root-of-the-server]__0.uoh7q._.js +3 -0
  423. package/.next/server/chunks/ssr/[root-of-the-server]__01ws4-7._.js +3 -0
  424. package/.next/server/chunks/ssr/[root-of-the-server]__024-5kd._.js +3 -0
  425. package/.next/server/chunks/ssr/[root-of-the-server]__02ipahf._.js +3 -0
  426. package/.next/server/chunks/ssr/[root-of-the-server]__03.14vw._.js +3 -0
  427. package/.next/server/chunks/ssr/[root-of-the-server]__04xn50b._.js +30 -0
  428. package/.next/server/chunks/ssr/[root-of-the-server]__05452ke._.js +30 -0
  429. package/.next/server/chunks/ssr/[root-of-the-server]__06o5v8i._.js +30 -0
  430. package/.next/server/chunks/ssr/[root-of-the-server]__06sm5cw._.js +3 -0
  431. package/.next/server/chunks/ssr/[root-of-the-server]__09m32ch._.js +3 -0
  432. package/.next/server/chunks/ssr/[root-of-the-server]__0_0kxz4._.js +3 -0
  433. package/.next/server/chunks/ssr/[root-of-the-server]__0adx8p4._.js +30 -0
  434. package/.next/server/chunks/ssr/[root-of-the-server]__0bk3s4l._.js +3 -0
  435. package/.next/server/chunks/ssr/[root-of-the-server]__0d5p5d.._.js +30 -0
  436. package/.next/server/chunks/ssr/[root-of-the-server]__0d7u1lw._.js +3 -0
  437. package/.next/server/chunks/ssr/[root-of-the-server]__0fg8.hp._.js +3 -0
  438. package/.next/server/chunks/ssr/[root-of-the-server]__0gsj3~.._.js +30 -0
  439. package/.next/server/chunks/ssr/[root-of-the-server]__0hvz_0c._.js +3 -0
  440. package/.next/server/chunks/ssr/[root-of-the-server]__0i6glcp._.js +30 -0
  441. package/.next/server/chunks/ssr/[root-of-the-server]__0ibsor_._.js +3 -0
  442. package/.next/server/chunks/ssr/[root-of-the-server]__0j5~a_o._.js +3 -0
  443. package/.next/server/chunks/ssr/[root-of-the-server]__0jgbj6l._.js +3 -0
  444. package/.next/server/chunks/ssr/[root-of-the-server]__0jux8~h._.js +33 -0
  445. package/.next/server/chunks/ssr/[root-of-the-server]__0l~dc3x._.js +3 -0
  446. package/.next/server/chunks/ssr/[root-of-the-server]__0mab0km._.js +3 -0
  447. package/.next/server/chunks/ssr/[root-of-the-server]__0n32nv5._.js +30 -0
  448. package/.next/server/chunks/ssr/[root-of-the-server]__0n8qufu._.js +3 -0
  449. package/.next/server/chunks/ssr/[root-of-the-server]__0ndt9h3._.js +3 -0
  450. package/.next/server/chunks/ssr/[root-of-the-server]__0p~u4y6._.js +3 -0
  451. package/.next/server/chunks/ssr/[root-of-the-server]__0q.du4s._.js +3 -0
  452. package/.next/server/chunks/ssr/[root-of-the-server]__0rs7pkn._.js +3 -0
  453. package/.next/server/chunks/ssr/[root-of-the-server]__0sysz2q._.js +47 -0
  454. package/.next/server/chunks/ssr/[root-of-the-server]__0t25~v8._.js +3 -0
  455. package/.next/server/chunks/ssr/[root-of-the-server]__0ti70do._.js +3 -0
  456. package/.next/server/chunks/ssr/[root-of-the-server]__0uevudp._.js +30 -0
  457. package/.next/server/chunks/ssr/[root-of-the-server]__0wwqzmm._.js +3 -0
  458. package/.next/server/chunks/ssr/[root-of-the-server]__0xt3-qb._.js +3 -0
  459. package/.next/server/chunks/ssr/[root-of-the-server]__0y-lkvf._.js +3 -0
  460. package/.next/server/chunks/ssr/[root-of-the-server]__0zvf.ro._.js +3 -0
  461. package/.next/server/chunks/ssr/[root-of-the-server]__0~jc3l5._.js +3 -0
  462. package/.next/server/chunks/ssr/[root-of-the-server]__11m7m-q._.js +3 -0
  463. package/.next/server/chunks/ssr/[root-of-the-server]__1223b0_._.js +30 -0
  464. package/.next/server/chunks/ssr/[root-of-the-server]__12f810l._.js +3 -0
  465. package/.next/server/chunks/ssr/[root-of-the-server]__13-by9r._.js +33 -0
  466. package/.next/server/chunks/ssr/[root-of-the-server]__13-egel._.js +3 -0
  467. package/.next/server/chunks/ssr/[turbopack]_runtime.js +903 -0
  468. package/.next/server/chunks/ssr/tower_0-nwtka._.js +3 -0
  469. package/.next/server/chunks/ssr/tower_0-omr_b._.js +30 -0
  470. package/.next/server/chunks/ssr/tower_00.hg6u._.js +3 -0
  471. package/.next/server/chunks/ssr/tower_01szasw._.js +3 -0
  472. package/.next/server/chunks/ssr/tower_02he7d6._.js +3 -0
  473. package/.next/server/chunks/ssr/tower_035l~qv._.js +3 -0
  474. package/.next/server/chunks/ssr/tower_03jazku._.js +3 -0
  475. package/.next/server/chunks/ssr/tower_09~lpto._.js +3 -0
  476. package/.next/server/chunks/ssr/tower_0d.car1._.js +30 -0
  477. package/.next/server/chunks/ssr/tower_0egtw-7._.js +30 -0
  478. package/.next/server/chunks/ssr/tower_0gzwyem._.js +3 -0
  479. package/.next/server/chunks/ssr/tower_0h3r32m._.js +30 -0
  480. package/.next/server/chunks/ssr/tower_0kl_bfy._.js +7 -0
  481. package/.next/server/chunks/ssr/tower_0mz4ut.._.js +3 -0
  482. package/.next/server/chunks/ssr/tower_0nuj.0p._.js +39 -0
  483. package/.next/server/chunks/ssr/tower_0pcqezm._.js +3 -0
  484. package/.next/server/chunks/ssr/tower_0r7uuim._.js +30 -0
  485. package/.next/server/chunks/ssr/tower_0sojjnu._.js +3 -0
  486. package/.next/server/chunks/ssr/tower_0tc~.xl._.js +30 -0
  487. package/.next/server/chunks/ssr/tower_0tuq2iz._.js +30 -0
  488. package/.next/server/chunks/ssr/tower_0vo6u9i._.js +3 -0
  489. package/.next/server/chunks/ssr/tower_0wvk~r.._.js +3 -0
  490. package/.next/server/chunks/ssr/tower_10p15te._.js +3 -0
  491. package/.next/server/chunks/ssr/tower_10t13p4._.js +6 -0
  492. package/.next/server/chunks/ssr/tower_117pzh8._.js +3 -0
  493. package/.next/server/chunks/ssr/tower_11q5_.m._.js +3 -0
  494. package/.next/server/chunks/ssr/tower_12sld1c._.js +3 -0
  495. package/.next/server/chunks/ssr/tower_138qlx5._.js +3 -0
  496. package/.next/server/chunks/ssr/tower__next-internal_server_app__global-error_page_actions_13t5~qk.js +3 -0
  497. package/.next/server/chunks/ssr/tower_src_08t.wy-._.js +3 -0
  498. package/.next/server/chunks/ssr/tower_src_actions_agent-actions_ts_0j.e1tn._.js +4 -0
  499. package/.next/server/chunks/ssr/tower_src_actions_file-actions_ts_0424lna._.js +3 -0
  500. package/.next/server/chunks/ssr/tower_src_app_missions_missions-client_tsx_0a9vjyr._.js +3 -0
  501. package/.next/server/chunks/ssr/tower_src_app_onboarding_page_tsx_0_3krz1._.js +3 -0
  502. package/.next/server/chunks/ssr/tower_src_app_settings_page_tsx_0vo5e-o._.js +3 -0
  503. package/.next/server/chunks/ssr/tower_src_app_workspaces_[workspaceId]_assets_assets-page-client_tsx_0zfgzhi._.js +3 -0
  504. package/.next/server/chunks/ssr/tower_src_app_workspaces_[workspaceId]_board-page-client_tsx_0kjp1u0._.js +7 -0
  505. package/.next/server/chunks/ssr/tower_src_components_ui_select_tsx_10ajx~2._.js +3 -0
  506. package/.next/server/chunks/ssr/tower_src_lib_01420_4._.js +3 -0
  507. package/.next/server/chunks/ssr/tower_src_lib_0i-zjpa._.js +3 -0
  508. package/.next/server/chunks/ssr/tower_src_lib_0ja~kdb._.js +3 -0
  509. package/.next/server/chunks/ssr/tower_src_lib_0obw2r8._.js +3 -0
  510. package/.next/server/chunks/ssr/tower_src_lib_0rgfsuf._.js +3 -0
  511. package/.next/server/chunks/ssr/tower_src_lib_constants_ts_0o218_c._.js +3 -0
  512. package/.next/server/chunks/tower_03g~ktv._.js +7 -0
  513. package/.next/server/chunks/tower_05du07.._.js +10 -0
  514. package/.next/server/chunks/tower_0a-x6m.._.js +3 -0
  515. package/.next/server/chunks/tower__next-internal_server_app_api_adapters_test_route_actions_13jw~9b.js +3 -0
  516. package/.next/server/chunks/tower__next-internal_server_app_api_browse-fs_route_actions_0k5p2xy.js +3 -0
  517. package/.next/server/chunks/tower__next-internal_server_app_api_git_route_actions_0rvpodb.js +3 -0
  518. package/.next/server/chunks/tower__next-internal_server_app_api_internal_assets_reveal_route_actions_0idwm6j.js +3 -0
  519. package/.next/server/chunks/tower__next-internal_server_app_api_internal_assistant_route_actions_0rdz1d..js +3 -0
  520. package/.next/server/chunks/tower__next-internal_server_app_api_internal_hooks_install_route_actions_06dxleu.js +3 -0
  521. package/.next/server/chunks/tower__next-internal_server_app_api_internal_hooks_session_route_actions_0wlv4lf.js +3 -0
  522. package/.next/server/chunks/tower__next-internal_server_app_api_internal_hooks_stop_route_actions_101_oub.js +3 -0
  523. package/.next/server/chunks/tower__next-internal_server_app_api_internal_hooks_upload_route_actions_0439qz_.js +3 -0
  524. package/.next/server/chunks/tower__next-internal_server_app_api_tasks_[taskId]_diff_route_actions_0nthc84.js +3 -0
  525. package/.next/server/chunks/tower__next-internal_server_app_api_tasks_[taskId]_merge_route_actions_0g.x0nb.js +3 -0
  526. package/.next/server/chunks/tower__next-internal_server_app_apple-icon_png_route_actions_0bni-sb.js +3 -0
  527. package/.next/server/chunks/tower__next-internal_server_app_favicon_ico_route_actions_0kw~xj2.js +3 -0
  528. package/.next/server/chunks/tower__next-internal_server_app_icon0_svg_route_actions_0nww9-e.js +3 -0
  529. package/.next/server/chunks/tower__next-internal_server_app_icon1_png_route_actions_09h.ywu.js +3 -0
  530. package/.next/server/chunks/tower__next-internal_server_app_manifest_json_route_actions_080ob~r.js +3 -0
  531. package/.next/server/chunks/tower_src_0..vg-t._.js +3 -0
  532. package/.next/server/chunks/tower_src_05rqj.1._.js +3 -0
  533. package/.next/server/chunks/tower_src_lib_0uok6j3._.js +3 -0
  534. package/.next/server/chunks/tower_src_lib_0w8qt4s._.js +3 -0
  535. package/.next/server/chunks/tower_src_lib_constants_ts_0cxd4.p._.js +3 -0
  536. package/.next/server/edge/chunks/0y9m_next_dist_esm_build_templates_edge-wrapper_0cx_eo..js +3 -0
  537. package/.next/server/edge/chunks/tower_0wvfs38._.js +3 -0
  538. package/.next/server/functions-config-manifest.json +22 -0
  539. package/.next/server/instrumentation/middleware-manifest.json +12 -0
  540. package/.next/server/instrumentation.js +4 -0
  541. package/.next/server/instrumentation.js.nft.json +1 -0
  542. package/.next/server/interception-route-rewrite-manifest.js +1 -0
  543. package/.next/server/middleware-build-manifest.js +22 -0
  544. package/.next/server/middleware-manifest.json +6 -0
  545. package/.next/server/next-font-manifest.js +1 -0
  546. package/.next/server/next-font-manifest.json +55 -0
  547. package/.next/server/pages/404.html +1 -0
  548. package/.next/server/pages/500.html +1 -0
  549. package/.next/server/pages-manifest.json +4 -0
  550. package/.next/server/prefetch-hints.json +1 -0
  551. package/.next/server/server-reference-manifest.js +1 -0
  552. package/.next/server/server-reference-manifest.json +2778 -0
  553. package/.next/static/6AW1vTU7iJEkEhqIH0txT/_buildManifest.js +11 -0
  554. package/.next/static/6AW1vTU7iJEkEhqIH0txT/_clientMiddlewareManifest.js +1 -0
  555. package/.next/static/6AW1vTU7iJEkEhqIH0txT/_ssgManifest.js +1 -0
  556. package/.next/static/chunks/0-64z7pmj57~d.js +1 -0
  557. package/.next/static/chunks/00xbbu.nlx92z.js +1 -0
  558. package/.next/static/chunks/00z-g3x93ngvn.js +1 -0
  559. package/.next/static/chunks/03e.4ymu.j5wl.js +1 -0
  560. package/.next/static/chunks/03~yq9q893hmn.js +1 -0
  561. package/.next/static/chunks/049.9ha2n6os5.js +1 -0
  562. package/.next/static/chunks/05-b9qqm3av9~.js +1 -0
  563. package/.next/static/chunks/05j6t69jmpqju.js +1 -0
  564. package/.next/static/chunks/05~v02mkan5z..js +1 -0
  565. package/.next/static/chunks/07a_xadb-3w1a.js +1 -0
  566. package/.next/static/chunks/0_.pyr2jhdqa2.js +5 -0
  567. package/.next/static/chunks/0_c8duf92i~xg.js +1 -0
  568. package/.next/static/chunks/0a2blrvqw8t5y.js +5 -0
  569. package/.next/static/chunks/0abtpeymj-58i.js +1 -0
  570. package/.next/static/chunks/0drgc-oztq6o-.css +1 -0
  571. package/.next/static/chunks/0eaa2lmymh2fx.js +1 -0
  572. package/.next/static/chunks/0j9qriqni_r1..js +2 -0
  573. package/.next/static/chunks/0k.u8sxy~e469.js +4 -0
  574. package/.next/static/chunks/0kc-95qs2~eid.js +1 -0
  575. package/.next/static/chunks/0kojsk~4uroqj.js +1 -0
  576. package/.next/static/chunks/0kt2vohpgb7h6.js +1 -0
  577. package/.next/static/chunks/0kubr70r_r2f2.js +1 -0
  578. package/.next/static/chunks/0lvd52mjiit6s.js +1 -0
  579. package/.next/static/chunks/0mq0uqbbbb1~2.js +1 -0
  580. package/.next/static/chunks/0neevhl_o1ozu.css +2 -0
  581. package/.next/static/chunks/0omj~p3uxkic-.js +1 -0
  582. package/.next/static/chunks/0t-gr6j-c65qb.js +1 -0
  583. package/.next/static/chunks/0tcl81ybuob5i.js +1 -0
  584. package/.next/static/chunks/0ttrpz.l-v-yv.js +1 -0
  585. package/.next/static/chunks/0uqimvsni_op~.js +1 -0
  586. package/.next/static/chunks/0wt3kws~_yr8z.js +1 -0
  587. package/.next/static/chunks/0z-ecklemrfx-.js +1 -0
  588. package/.next/static/chunks/0z2bzovqhl2f5.js +1 -0
  589. package/.next/static/chunks/0z61ts2ro9_k3.js +83 -0
  590. package/.next/static/chunks/0z7bwntvfhxzi.js +12 -0
  591. package/.next/static/chunks/10n23t.1hpb-1.js +1 -0
  592. package/.next/static/chunks/14xzmrt5ly6gq.js +31 -0
  593. package/.next/static/chunks/151wr~6x8aclx.js +1 -0
  594. package/.next/static/chunks/16w-ap~msrwpj.js +1 -0
  595. package/.next/static/chunks/17oc2l.ekcs8b.css +1 -0
  596. package/.next/static/chunks/turbopack-0wjmrsi.z32s0.js +1 -0
  597. package/.next/static/media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2 +0 -0
  598. package/.next/static/media/7178b3e590c64307-s.11.cyxs5p-0z~.woff2 +0 -0
  599. package/.next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2 +0 -0
  600. package/.next/static/media/8a480f0b521d4e75-s.06d3mdzz5bre_.woff2 +0 -0
  601. package/.next/static/media/apple-icon.16aocl-s-v2qz.png +0 -0
  602. package/.next/static/media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2 +0 -0
  603. package/.next/static/media/caa3a2e1cccd8315-s.p.16t1db8_9y2o~.woff2 +0 -0
  604. package/.next/static/media/favicon.0y2d6j9cou~8p.ico +0 -0
  605. package/.next/static/media/icon0.0a6mkq6meyird.svg +1 -0
  606. package/.next/static/media/icon1.04ux133882seb.png +0 -0
  607. package/.next/trace +2 -0
  608. package/.next/trace-build +1 -0
  609. package/.next/turbopack +0 -0
  610. package/.next/types/routes.d.ts +103 -0
  611. package/.next/types/validator.ts +349 -0
  612. package/package.json +14 -11
  613. package/components.json +0 -25
  614. package/postcss.config.mjs +0 -7
  615. package/prisma/dev.db +0 -0
  616. package/prisma/prisma/dev.db +0 -0
  617. package/prisma/seed.ts +0 -50
  618. package/scripts/init-tower.ts +0 -10
  619. package/scripts/post-tool-hook.js +0 -188
  620. package/scripts/session-start-hook.js +0 -79
  621. package/scripts/stop-hook.js +0 -78
  622. package/skills/tower/SKILL.md +0 -375
  623. package/src/actions/__tests__/agent-actions-username.test.ts +0 -30
  624. package/src/actions/__tests__/asset-actions.test.ts +0 -251
  625. package/src/actions/__tests__/assistant-actions.test.ts +0 -20
  626. package/src/actions/__tests__/cli-profile-actions.test.ts +0 -243
  627. package/src/actions/__tests__/label-actions.test.ts +0 -187
  628. package/src/actions/__tests__/note-actions.test.ts +0 -237
  629. package/src/actions/__tests__/onboarding-actions.test.ts +0 -265
  630. package/src/actions/__tests__/project-actions.test.ts +0 -179
  631. package/src/actions/__tests__/prompt-actions.test.ts +0 -213
  632. package/src/actions/__tests__/report-actions.test.ts +0 -246
  633. package/src/actions/__tests__/search-code-actions.test.ts +0 -308
  634. package/src/actions/__tests__/task-actions-overview.test.ts +0 -58
  635. package/src/actions/__tests__/task-actions-pin.test.ts +0 -79
  636. package/src/actions/__tests__/workspace-actions.test.ts +0 -256
  637. package/src/actions/agent-actions.ts +0 -741
  638. package/src/actions/agent-config-actions.ts +0 -44
  639. package/src/actions/ai-config-actions.ts +0 -51
  640. package/src/actions/asset-actions.ts +0 -131
  641. package/src/actions/assistant-actions.ts +0 -107
  642. package/src/actions/cli-profile-actions.ts +0 -98
  643. package/src/actions/config-actions.ts +0 -84
  644. package/src/actions/file-actions.ts +0 -262
  645. package/src/actions/git-actions.ts +0 -90
  646. package/src/actions/label-actions.ts +0 -67
  647. package/src/actions/note-actions.ts +0 -87
  648. package/src/actions/onboarding-actions.ts +0 -103
  649. package/src/actions/preview-actions.ts +0 -76
  650. package/src/actions/project-actions.ts +0 -222
  651. package/src/actions/prompt-actions.ts +0 -73
  652. package/src/actions/report-actions.ts +0 -141
  653. package/src/actions/search-actions.ts +0 -21
  654. package/src/actions/search-code-actions.ts +0 -185
  655. package/src/actions/task-actions.ts +0 -350
  656. package/src/actions/workspace-actions.ts +0 -224
  657. package/src/app/api/adapters/test/route.ts +0 -52
  658. package/src/app/api/browse-fs/route.ts +0 -90
  659. package/src/app/api/files/assets/[projectId]/[filename]/route.ts +0 -38
  660. package/src/app/api/git/route.ts +0 -367
  661. package/src/app/api/internal/assets/[projectId]/[filename]/route.ts +0 -51
  662. package/src/app/api/internal/assets/reveal/route.ts +0 -71
  663. package/src/app/api/internal/assistant/chat/route.ts +0 -217
  664. package/src/app/api/internal/assistant/images/route.ts +0 -51
  665. package/src/app/api/internal/assistant/route.ts +0 -50
  666. package/src/app/api/internal/assistant/sessions/route.ts +0 -44
  667. package/src/app/api/internal/cache/[...segments]/route.ts +0 -59
  668. package/src/app/api/internal/hooks/install/route.ts +0 -41
  669. package/src/app/api/internal/hooks/session/route.ts +0 -60
  670. package/src/app/api/internal/hooks/stop/route.ts +0 -61
  671. package/src/app/api/internal/hooks/upload/route.ts +0 -173
  672. package/src/app/api/internal/notifications/pending/route.ts +0 -20
  673. package/src/app/api/internal/terminal/[taskId]/buffer/route.ts +0 -48
  674. package/src/app/api/internal/terminal/[taskId]/input/route.ts +0 -64
  675. package/src/app/api/internal/terminal/[taskId]/start/route.ts +0 -37
  676. package/src/app/api/tasks/[taskId]/diff/route.ts +0 -224
  677. package/src/app/api/tasks/[taskId]/merge/route.ts +0 -159
  678. package/src/app/globals.css +0 -247
  679. package/src/app/layout.tsx +0 -63
  680. package/src/app/missions/missions-client.tsx +0 -338
  681. package/src/app/missions/page.tsx +0 -10
  682. package/src/app/onboarding/page.tsx +0 -619
  683. package/src/app/page.tsx +0 -5
  684. package/src/app/settings/page.tsx +0 -7
  685. package/src/app/workspaces/[workspaceId]/archive/archive-page-client.tsx +0 -258
  686. package/src/app/workspaces/[workspaceId]/archive/page.tsx +0 -36
  687. package/src/app/workspaces/[workspaceId]/assets/assets-page-client.tsx +0 -232
  688. package/src/app/workspaces/[workspaceId]/assets/page.tsx +0 -36
  689. package/src/app/workspaces/[workspaceId]/board-page-client.tsx +0 -257
  690. package/src/app/workspaces/[workspaceId]/notes/notes-page-client.tsx +0 -337
  691. package/src/app/workspaces/[workspaceId]/notes/page.tsx +0 -39
  692. package/src/app/workspaces/[workspaceId]/page.tsx +0 -81
  693. package/src/app/workspaces/[workspaceId]/projects/[projectId]/page.tsx +0 -30
  694. package/src/app/workspaces/[workspaceId]/tasks/[taskId]/page.tsx +0 -97
  695. package/src/app/workspaces/[workspaceId]/tasks/[taskId]/task-page-client.tsx +0 -601
  696. package/src/app/workspaces/page.tsx +0 -13
  697. package/src/components/assets/asset-item.tsx +0 -128
  698. package/src/components/assets/asset-list.tsx +0 -31
  699. package/src/components/assets/asset-upload.tsx +0 -216
  700. package/src/components/assets/image-lightbox.tsx +0 -72
  701. package/src/components/assets/text-preview-dialog.tsx +0 -135
  702. package/src/components/assistant/assistant-chat-bubble.tsx +0 -308
  703. package/src/components/assistant/assistant-chat.tsx +0 -215
  704. package/src/components/assistant/assistant-panel.tsx +0 -149
  705. package/src/components/assistant/assistant-provider.tsx +0 -512
  706. package/src/components/assistant/image-preview-modal.tsx +0 -60
  707. package/src/components/assistant/image-thumbnail-strip.tsx +0 -94
  708. package/src/components/board/board-column.tsx +0 -115
  709. package/src/components/board/board-filters.tsx +0 -42
  710. package/src/components/board/board-stats.tsx +0 -52
  711. package/src/components/board/column-tasks-dialog.tsx +0 -100
  712. package/src/components/board/create-task-dialog.tsx +0 -362
  713. package/src/components/board/kanban-board.tsx +0 -169
  714. package/src/components/board/project-tabs.tsx +0 -93
  715. package/src/components/board/task-card-context-menu.tsx +0 -121
  716. package/src/components/board/task-card.tsx +0 -135
  717. package/src/components/layout/__tests__/top-bar-username.test.tsx +0 -24
  718. package/src/components/layout/app-sidebar.tsx +0 -662
  719. package/src/components/layout/folder-browser-dialog.tsx +0 -273
  720. package/src/components/layout/layout-client.tsx +0 -198
  721. package/src/components/layout/search-dialog.tsx +0 -196
  722. package/src/components/layout/sub-page-nav.tsx +0 -54
  723. package/src/components/layout/top-bar.tsx +0 -265
  724. package/src/components/missions/grid-layout-presets.ts +0 -19
  725. package/src/components/missions/grid-preset-picker.tsx +0 -209
  726. package/src/components/missions/merge-missions.ts +0 -30
  727. package/src/components/missions/mission-card.tsx +0 -203
  728. package/src/components/missions/task-picker-dialog.tsx +0 -415
  729. package/src/components/notes/category-filter.tsx +0 -44
  730. package/src/components/notes/note-card.tsx +0 -67
  731. package/src/components/notes/note-editor.tsx +0 -28
  732. package/src/components/notes/note-list.tsx +0 -30
  733. package/src/components/notifications/notification-permission-banner.tsx +0 -49
  734. package/src/components/notifications/use-notification-listener.ts +0 -114
  735. package/src/components/onboarding/__tests__/onboarding-wizard.test.tsx +0 -185
  736. package/src/components/onboarding/guided-tour.tsx +0 -255
  737. package/src/components/onboarding/onboarding-wizard.tsx +0 -84
  738. package/src/components/onboarding/wizard-step-cli.tsx +0 -53
  739. package/src/components/onboarding/wizard-step-username.tsx +0 -59
  740. package/src/components/project/create-project-dialog.tsx +0 -310
  741. package/src/components/project/import-project-dialog.tsx +0 -414
  742. package/src/components/providers/theme-provider.tsx +0 -8
  743. package/src/components/repository/create-branch-dialog.tsx +0 -165
  744. package/src/components/repository/git-changes-panel.tsx +0 -294
  745. package/src/components/repository/git-log-panel.tsx +0 -83
  746. package/src/components/repository/git-stash-panel.tsx +0 -158
  747. package/src/components/repository/repo-sidebar.tsx +0 -855
  748. package/src/components/settings/cli-adapter-tester.tsx +0 -144
  749. package/src/components/settings/settings-page.tsx +0 -2111
  750. package/src/components/task/code-editor.tsx +0 -376
  751. package/src/components/task/code-search.tsx +0 -219
  752. package/src/components/task/diff-editor.tsx +0 -97
  753. package/src/components/task/editor-git-panel.tsx +0 -792
  754. package/src/components/task/editor-tabs.tsx +0 -68
  755. package/src/components/task/execution-timeline.tsx +0 -258
  756. package/src/components/task/file-tree-context-menu.tsx +0 -113
  757. package/src/components/task/file-tree-node.tsx +0 -269
  758. package/src/components/task/file-tree.tsx +0 -575
  759. package/src/components/task/preview-panel.tsx +0 -281
  760. package/src/components/task/task-detail-panel.tsx +0 -455
  761. package/src/components/task/task-diff-view.tsx +0 -207
  762. package/src/components/task/task-file-changes.tsx +0 -19
  763. package/src/components/task/task-merge-confirm-dialog.tsx +0 -152
  764. package/src/components/task/task-metadata.tsx +0 -74
  765. package/src/components/task/task-notes-panel.tsx +0 -219
  766. package/src/components/task/task-overview-drawer.tsx +0 -172
  767. package/src/components/task/task-terminal.tsx +0 -294
  768. package/src/components/task/terminal-portal.tsx +0 -156
  769. package/src/components/task/types.ts +0 -6
  770. package/src/components/ui/avatar.tsx +0 -109
  771. package/src/components/ui/badge.tsx +0 -52
  772. package/src/components/ui/button.tsx +0 -58
  773. package/src/components/ui/card.tsx +0 -103
  774. package/src/components/ui/command.tsx +0 -196
  775. package/src/components/ui/dialog.tsx +0 -160
  776. package/src/components/ui/dropdown-menu.tsx +0 -268
  777. package/src/components/ui/empty-state.tsx +0 -26
  778. package/src/components/ui/error-boundary.tsx +0 -58
  779. package/src/components/ui/input-group.tsx +0 -158
  780. package/src/components/ui/input.tsx +0 -20
  781. package/src/components/ui/label.tsx +0 -20
  782. package/src/components/ui/popover.tsx +0 -90
  783. package/src/components/ui/scroll-area.tsx +0 -55
  784. package/src/components/ui/segmented-control.tsx +0 -42
  785. package/src/components/ui/select.tsx +0 -207
  786. package/src/components/ui/separator.tsx +0 -25
  787. package/src/components/ui/sheet.tsx +0 -138
  788. package/src/components/ui/sonner.tsx +0 -49
  789. package/src/components/ui/switch.tsx +0 -32
  790. package/src/components/ui/tabs.tsx +0 -82
  791. package/src/components/ui/textarea.tsx +0 -18
  792. package/src/components/ui/toast.tsx +0 -86
  793. package/src/components/ui/tooltip.tsx +0 -66
  794. package/src/hooks/__tests__/sse-event-reducer.test.ts +0 -263
  795. package/src/hooks/__tests__/use-assistant-chat.test.ts +0 -34
  796. package/src/hooks/__tests__/use-image-upload.test.ts +0 -443
  797. package/src/hooks/sse-event-reducer.ts +0 -144
  798. package/src/hooks/use-assistant-chat.ts +0 -190
  799. package/src/hooks/use-image-upload.ts +0 -140
  800. package/src/instrumentation.ts +0 -18
  801. package/src/lib/__tests__/assistant-message-converter.test.ts +0 -162
  802. package/src/lib/__tests__/assistant-sessions.test.ts +0 -253
  803. package/src/lib/__tests__/build-multimodal-prompt.test.ts +0 -173
  804. package/src/lib/__tests__/config-reader.test.ts +0 -75
  805. package/src/lib/__tests__/diff-parser.test.ts +0 -212
  806. package/src/lib/__tests__/execution-summary.test.ts +0 -237
  807. package/src/lib/__tests__/file-serve.test.ts +0 -178
  808. package/src/lib/__tests__/file-utils.test.ts +0 -177
  809. package/src/lib/__tests__/internal-api-guard.test.ts +0 -151
  810. package/src/lib/__tests__/logger.test.ts +0 -181
  811. package/src/lib/__tests__/platform.test.ts +0 -566
  812. package/src/lib/__tests__/reveal-route-security.test.ts +0 -65
  813. package/src/lib/__tests__/schemas.test.ts +0 -377
  814. package/src/lib/__tests__/terminal-link-provider.test.ts +0 -160
  815. package/src/lib/__tests__/upload-route-security.test.ts +0 -120
  816. package/src/lib/ai/__tests__/capability-resolver.test.ts +0 -71
  817. package/src/lib/ai/__tests__/claude-cli-adapter.test.ts +0 -103
  818. package/src/lib/ai/__tests__/provider-registry.test.ts +0 -74
  819. package/src/lib/ai/adapters/cli/claude-cli-adapter.ts +0 -166
  820. package/src/lib/ai/capability-resolver.ts +0 -81
  821. package/src/lib/ai/provider-registry.ts +0 -54
  822. package/src/lib/ai/providers/claude.ts +0 -19
  823. package/src/lib/ai/providers/index.ts +0 -12
  824. package/src/lib/ai/types.ts +0 -151
  825. package/src/lib/assistant-constants.ts +0 -2
  826. package/src/lib/assistant-message-converter.ts +0 -131
  827. package/src/lib/assistant-sessions.ts +0 -75
  828. package/src/lib/build-multimodal-prompt.ts +0 -53
  829. package/src/lib/claude-session.ts +0 -156
  830. package/src/lib/cli-test.ts +0 -476
  831. package/src/lib/config-defaults.ts +0 -121
  832. package/src/lib/config-reader.ts +0 -16
  833. package/src/lib/constants.ts +0 -26
  834. package/src/lib/db.ts +0 -28
  835. package/src/lib/diff-parser.ts +0 -132
  836. package/src/lib/execution-summary.ts +0 -287
  837. package/src/lib/file-serve-client.ts +0 -13
  838. package/src/lib/file-serve.ts +0 -32
  839. package/src/lib/file-utils.ts +0 -108
  840. package/src/lib/fs-security.ts +0 -22
  841. package/src/lib/fts.ts +0 -83
  842. package/src/lib/git-api.ts +0 -19
  843. package/src/lib/git-url.ts +0 -244
  844. package/src/lib/i18n/en.ts +0 -754
  845. package/src/lib/i18n/types.ts +0 -4
  846. package/src/lib/i18n/zh.ts +0 -769
  847. package/src/lib/i18n.tsx +0 -64
  848. package/src/lib/init-tower.ts +0 -129
  849. package/src/lib/instrumentation-tasks.ts +0 -116
  850. package/src/lib/internal-api-guard.ts +0 -63
  851. package/src/lib/logger.ts +0 -46
  852. package/src/lib/mime-magic.ts +0 -67
  853. package/src/lib/platform.ts +0 -518
  854. package/src/lib/preview-process.ts +0 -40
  855. package/src/lib/pty/__tests__/ws-server-assistant.test.ts +0 -7
  856. package/src/lib/pty/pty-session.ts +0 -157
  857. package/src/lib/pty/session-store.ts +0 -67
  858. package/src/lib/pty/ws-server.ts +0 -335
  859. package/src/lib/schemas.ts +0 -67
  860. package/src/lib/search.ts +0 -225
  861. package/src/lib/terminal-link-provider.ts +0 -90
  862. package/src/lib/tower-dir.ts +0 -69
  863. package/src/lib/utils.ts +0 -20
  864. package/src/lib/worktree.ts +0 -184
  865. package/src/stores/board-store.ts +0 -46
  866. package/src/stores/task-execution-store.ts +0 -41
  867. package/src/types/index.ts +0 -36
  868. /package/{src/app/apple-icon.png → .next/server/app/apple-icon.png.body} +0 -0
  869. /package/{src/app/favicon.ico → .next/server/app/favicon.ico.body} +0 -0
  870. /package/{src/app/icon0.svg → .next/server/app/icon0.svg.body} +0 -0
  871. /package/{src/app/icon1.png → .next/server/app/icon1.png.body} +0 -0
  872. /package/{src/app/manifest.json → .next/server/app/manifest.json.body} +0 -0
@@ -1,2111 +0,0 @@
1
- "use client";
2
-
3
- import { useState, useEffect, useCallback, useRef } from "react";
4
- import { useRouter } from "next/navigation";
5
- import { useTheme } from "next-themes";
6
- import { useI18n } from "@/lib/i18n";
7
- import type { Locale } from "@/lib/i18n";
8
- import { Button } from "@/components/ui/button";
9
- import { Input } from "@/components/ui/input";
10
- import { Textarea } from "@/components/ui/textarea";
11
- import { Label } from "@/components/ui/label";
12
- import { Badge } from "@/components/ui/badge";
13
- import { Switch } from "@/components/ui/switch";
14
- import {
15
- Dialog,
16
- DialogContent,
17
- DialogHeader,
18
- DialogTitle,
19
- DialogFooter,
20
- DialogDescription,
21
- } from "@/components/ui/dialog";
22
- import { cn } from "@/lib/utils";
23
- import {
24
- Settings,
25
- Cpu,
26
- FileText,
27
- SlidersHorizontal,
28
- Terminal,
29
- Bell,
30
- X,
31
- Plus,
32
- Star,
33
- Trash2,
34
- Edit,
35
- Save,
36
- Loader2,
37
- Check,
38
- CheckCircle2,
39
- XCircle,
40
- } from "lucide-react";
41
- import {
42
- getConfigValue,
43
- setConfigValue,
44
- getConfigValues,
45
- getAvailableTerminalApps,
46
- } from "@/actions/config-actions";
47
- import {
48
- getPrompts,
49
- createPrompt,
50
- updatePrompt,
51
- deletePrompt,
52
- setDefaultPrompt,
53
- } from "@/actions/prompt-actions";
54
- import {
55
- getDefaultCliProfile,
56
- updateCliProfile,
57
- } from "@/actions/cli-profile-actions";
58
- import type { TestResult } from "@/lib/cli-test";
59
- import type { AgentPrompt } from "@prisma/client";
60
- import type { DetectedTerminalApp } from "@/lib/platform";
61
- import type { GitPathRule } from "@/lib/git-url";
62
-
63
- // ---------------------------------------------------------------------------
64
- // Inline SegmentedToggle
65
- // ---------------------------------------------------------------------------
66
- function SegmentedToggle<T extends string>({
67
- options,
68
- value,
69
- onChange,
70
- }: {
71
- options: { value: T; label: React.ReactNode }[];
72
- value: T;
73
- onChange: (v: T) => void;
74
- }) {
75
- return (
76
- <div className="inline-flex rounded-lg border border-border/50 bg-muted/30 p-1 gap-0.5">
77
- {options.map((opt) => (
78
- <button
79
- key={opt.value}
80
- type="button"
81
- onClick={() => onChange(opt.value)}
82
- className={cn(
83
- "rounded-md px-3.5 py-1.5 text-sm font-medium transition-all duration-200 cursor-pointer",
84
- value === opt.value
85
- ? "bg-background text-foreground shadow-sm"
86
- : "text-muted-foreground hover:text-foreground"
87
- )}
88
- >
89
- {opt.label}
90
- </button>
91
- ))}
92
- </div>
93
- );
94
- }
95
-
96
- // ---------------------------------------------------------------------------
97
- // Setting row helper
98
- // ---------------------------------------------------------------------------
99
- function SettingRow({
100
- label,
101
- description,
102
- children,
103
- className,
104
- }: {
105
- label: React.ReactNode;
106
- description?: React.ReactNode;
107
- children: React.ReactNode;
108
- className?: string;
109
- }) {
110
- return (
111
- <div
112
- className={cn(
113
- "flex items-center justify-between py-4 border-b border-border/50 last:border-0",
114
- className
115
- )}
116
- >
117
- <div className="min-w-0 flex-1 pr-4">
118
- <div className="text-sm font-medium">{label}</div>
119
- {description && (
120
- <div className="text-xs text-muted-foreground mt-0.5">
121
- {description}
122
- </div>
123
- )}
124
- </div>
125
- <div className="shrink-0">{children}</div>
126
- </div>
127
- );
128
- }
129
-
130
- // ---------------------------------------------------------------------------
131
- // Constants
132
- // ---------------------------------------------------------------------------
133
- const SECTIONS = [
134
- {
135
- id: "general",
136
- labelKey: "settings.general" as const,
137
- descKey: "settings.generalDesc" as const,
138
- icon: Settings,
139
- accent: "blue",
140
- },
141
- {
142
- id: "ai-tools",
143
- labelKey: "settings.aiTools.title" as const,
144
- descKey: "settings.aiTools.cliVerificationDesc" as const,
145
- icon: Cpu,
146
- accent: "emerald",
147
- },
148
- {
149
- id: "prompts",
150
- labelKey: "settings.prompts" as const,
151
- descKey: "settings.promptsDesc" as const,
152
- icon: FileText,
153
- accent: "violet",
154
- },
155
- {
156
- id: "config",
157
- labelKey: "settings.config" as const,
158
- descKey: "settings.configDesc" as const,
159
- icon: SlidersHorizontal,
160
- accent: "amber",
161
- },
162
- {
163
- id: "cli-profile",
164
- labelKey: "settings.cliProfile.title" as const,
165
- descKey: "settings.cliProfile.navDesc" as const,
166
- icon: Terminal,
167
- accent: "cyan",
168
- },
169
- {
170
- id: "notifications",
171
- labelKey: "settings.notifications.title" as const,
172
- descKey: "settings.notifications.navDesc" as const,
173
- icon: Bell,
174
- accent: "rose",
175
- },
176
- ] as const;
177
-
178
- type SectionId = (typeof SECTIONS)[number]["id"];
179
-
180
- const ACCENT_STYLES: Record<
181
- string,
182
- { bg: string; text: string; ring: string; indicator: string }
183
- > = {
184
- blue: {
185
- bg: "bg-accent",
186
- text: "text-foreground",
187
- ring: "ring-border",
188
- indicator: "bg-foreground",
189
- },
190
- emerald: {
191
- bg: "bg-accent",
192
- text: "text-foreground",
193
- ring: "ring-border",
194
- indicator: "bg-foreground",
195
- },
196
- violet: {
197
- bg: "bg-accent",
198
- text: "text-foreground",
199
- ring: "ring-border",
200
- indicator: "bg-foreground",
201
- },
202
- amber: {
203
- bg: "bg-accent",
204
- text: "text-foreground",
205
- ring: "ring-border",
206
- indicator: "bg-foreground",
207
- },
208
- cyan: {
209
- bg: "bg-accent",
210
- text: "text-foreground",
211
- ring: "ring-border",
212
- indicator: "bg-foreground",
213
- },
214
- rose: {
215
- bg: "bg-accent",
216
- text: "text-foreground",
217
- ring: "ring-border",
218
- indicator: "bg-foreground",
219
- },
220
- };
221
-
222
- // ---------------------------------------------------------------------------
223
- // CLI Adapters (AI Tools)
224
- // ---------------------------------------------------------------------------
225
- const DEFAULT_CLI_ADAPTER_KEY = "ai-manager:default-cli-adapter";
226
-
227
- interface CLIAdapter {
228
- type: string;
229
- label: string;
230
- source: "builtin" | "external";
231
- }
232
-
233
- const CLI_ADAPTERS: CLIAdapter[] = [
234
- { type: "claude_local", label: "Claude Code", source: "builtin" },
235
- ];
236
-
237
- // ---------------------------------------------------------------------------
238
- // CLI Profile helpers
239
- // ---------------------------------------------------------------------------
240
- type CliProfile = {
241
- id: string;
242
- name: string;
243
- command: string;
244
- baseArgs: string;
245
- envVars: string;
246
- };
247
-
248
- function parseBaseArgsToText(baseArgs: string): string {
249
- try {
250
- const arr: string[] = JSON.parse(baseArgs);
251
- return Array.isArray(arr) ? arr.join("\n") : "";
252
- } catch {
253
- return "";
254
- }
255
- }
256
-
257
- function parseEnvVarsToText(envVars: string): string {
258
- try {
259
- const obj: Record<string, string> = JSON.parse(envVars);
260
- if (typeof obj !== "object" || Array.isArray(obj) || obj === null) return "";
261
- return Object.entries(obj)
262
- .map(([k, v]) => `${k}=${v}`)
263
- .join("\n");
264
- } catch {
265
- return "";
266
- }
267
- }
268
-
269
- // ---------------------------------------------------------------------------
270
- // System Config types
271
- // ---------------------------------------------------------------------------
272
- type RuleEditState = {
273
- host: string;
274
- ownerMatch: string;
275
- localPathTemplate: string;
276
- priority: number;
277
- };
278
-
279
- const EMPTY_FORM: RuleEditState = {
280
- host: "",
281
- ownerMatch: "*",
282
- localPathTemplate: "",
283
- priority: 0,
284
- };
285
-
286
- type SystemForm = { maxUploadMb: number; maxConcurrent: number };
287
- type GitParamsForm = { timeoutSec: number };
288
- type SearchForm = {
289
- resultLimit: number;
290
- allModeCap: number;
291
- debounceMs: number;
292
- snippetLength: number;
293
- };
294
- type MissionsGridForm = {
295
- minCols: number;
296
- maxCols: number;
297
- minRows: number;
298
- maxRows: number;
299
- };
300
- type HookStatus = { installed: boolean; hookPath: string };
301
-
302
- // ===========================================================================
303
- // MAIN COMPONENT
304
- // ===========================================================================
305
- export function SettingsPage() {
306
- const router = useRouter();
307
- const { t } = useI18n();
308
- const { theme, setTheme } = useTheme();
309
- const { locale, setLocale } = useI18n();
310
-
311
- const [activeSection, setActiveSection] = useState<SectionId>("general");
312
- const tabsRef = useRef<HTMLDivElement>(null);
313
- const [indicatorStyle, setIndicatorStyle] = useState({ left: 0, width: 0 });
314
-
315
- // ── General state ──────────────────────────────────────────────
316
- const [mounted, setMounted] = useState(false);
317
- const [terminalApp, setTerminalApp] = useState("Terminal");
318
- const [detectedApps, setDetectedApps] = useState<DetectedTerminalApp[]>([]);
319
- const [idleTimeout, setIdleTimeout] = useState(180);
320
-
321
- // ── AI Tools state ─────────────────────────────────────────────
322
- const [defaultAdapter, setDefaultAdapter] = useState("claude_local");
323
- const [testingAdapter, setTestingAdapter] = useState<string | null>(null);
324
- const [testResults, setTestResults] = useState<Record<string, TestResult>>(
325
- {}
326
- );
327
-
328
- // ── Prompts state ──────────────────────────────────────────────
329
- const [prompts, setPrompts] = useState<AgentPrompt[]>([]);
330
- const [promptDialogOpen, setPromptDialogOpen] = useState(false);
331
- const [editingPrompt, setEditingPrompt] = useState<AgentPrompt | null>(null);
332
- const [deletePromptId, setDeletePromptId] = useState<string | null>(null);
333
- const [promptName, setPromptName] = useState("");
334
- const [promptDescription, setPromptDescription] = useState("");
335
- const [promptContent, setPromptContent] = useState("");
336
-
337
- // ── System Config state ────────────────────────────────────────
338
- const [rules, setRules] = useState<GitPathRule[]>([]);
339
- const [editingRuleId, setEditingRuleId] = useState<string | null>(null);
340
- const [editRuleForm, setEditRuleForm] = useState<RuleEditState>({
341
- ...EMPTY_FORM,
342
- });
343
- const [showAddRuleForm, setShowAddRuleForm] = useState(false);
344
- const [addRuleForm, setAddRuleForm] = useState<RuleEditState>({
345
- ...EMPTY_FORM,
346
- });
347
- const [useFullPath, setUseFullPath] = useState(false);
348
- const [previewIdx, setPreviewIdx] = useState(0);
349
- const [deleteRuleConfirmId, setDeleteRuleConfirmId] = useState<string | null>(
350
- null
351
- );
352
- const [systemForm, setSystemForm] = useState<SystemForm>({
353
- maxUploadMb: 50,
354
- maxConcurrent: 3,
355
- });
356
- const [gitParamsForm, setGitParamsForm] = useState<GitParamsForm>({
357
- timeoutSec: 30,
358
- });
359
- const [searchForm, setSearchForm] = useState<SearchForm>({
360
- resultLimit: 20,
361
- allModeCap: 5,
362
- debounceMs: 250,
363
- snippetLength: 80,
364
- });
365
- const [missionsGridForm, setMissionsGridForm] = useState<MissionsGridForm>({
366
- minCols: 1,
367
- maxCols: 5,
368
- minRows: 1,
369
- maxRows: 5,
370
- });
371
- const [hookStatus, setHookStatus] = useState<HookStatus | null>(null);
372
- const [hookLoading, setHookLoading] = useState(false);
373
- const [autoUploadTypes, setAutoUploadTypes] = useState("");
374
-
375
- // ── CLI Profile state ──────────────────────────────────────────
376
- const [cliProfile, setCliProfile] = useState<CliProfile | null>(null);
377
- const [cliCommand, setCliCommand] = useState("");
378
- const [cliBaseArgsText, setCliBaseArgsText] = useState("");
379
- const [cliEnvVarsText, setCliEnvVarsText] = useState("");
380
- const [cliSaveStatus, setCliSaveStatus] = useState<"" | "saved" | "error">(
381
- ""
382
- );
383
- const [cliLoading, setCliLoading] = useState(true);
384
-
385
- // ── Notifications state ────────────────────────────────────────
386
- const [notifEnabled, setNotifEnabled] = useState(true);
387
-
388
- // =========================================================================
389
- // EFFECTS — mirror every original component
390
- // =========================================================================
391
-
392
- // Mount
393
- useEffect(() => setMounted(true), []);
394
-
395
- // General config load
396
- useEffect(() => {
397
- getConfigValue<string>("terminal.app", "Terminal").then(setTerminalApp);
398
- getConfigValue<number>("terminal.idleTimeoutSec", 180).then(setIdleTimeout);
399
- getAvailableTerminalApps().then(setDetectedApps);
400
- }, []);
401
-
402
- // AI Tools — default adapter from localStorage
403
- useEffect(() => {
404
- const stored = localStorage.getItem(DEFAULT_CLI_ADAPTER_KEY);
405
- if (stored) setDefaultAdapter(stored);
406
- }, []);
407
-
408
- // Prompts load
409
- useEffect(() => {
410
- getPrompts().then(setPrompts);
411
- }, []);
412
-
413
- // System config load
414
- const fetchHookStatus = async () => {
415
- try {
416
- const res = await fetch("/api/internal/hooks/install");
417
- if (res.ok) {
418
- const data = (await res.json()) as HookStatus;
419
- setHookStatus(data);
420
- }
421
- } catch {
422
- // ignore
423
- }
424
- };
425
-
426
- useEffect(() => {
427
- getConfigValue<GitPathRule[]>("git.pathMappingRules", []).then(setRules);
428
- getConfigValue<string[]>(
429
- "hooks.autoUploadTypes",
430
- [
431
- "png",
432
- "jpg",
433
- "jpeg",
434
- "gif",
435
- "webp",
436
- "svg",
437
- "pdf",
438
- "md",
439
- "txt",
440
- "json",
441
- ]
442
- ).then((types) => {
443
- setAutoUploadTypes(types.join(", "));
444
- });
445
- fetchHookStatus();
446
- getConfigValues([
447
- "system.maxUploadBytes",
448
- "system.maxConcurrentExecutions",
449
- "git.timeoutSec",
450
- "search.resultLimit",
451
- "search.allModeCap",
452
- "search.debounceMs",
453
- "search.snippetLength",
454
- "missions.grid.minCols",
455
- "missions.grid.maxCols",
456
- "missions.grid.minRows",
457
- "missions.grid.maxRows",
458
- ]).then((cfg) => {
459
- const maxBytes = (cfg["system.maxUploadBytes"] as number) ?? 52428800;
460
- setSystemForm({
461
- maxUploadMb: Math.round(maxBytes / 1024 / 1024),
462
- maxConcurrent:
463
- (cfg["system.maxConcurrentExecutions"] as number) ?? 3,
464
- });
465
- setGitParamsForm({
466
- timeoutSec: (cfg["git.timeoutSec"] as number) ?? 30,
467
- });
468
- setSearchForm({
469
- resultLimit: (cfg["search.resultLimit"] as number) ?? 20,
470
- allModeCap: (cfg["search.allModeCap"] as number) ?? 5,
471
- debounceMs: (cfg["search.debounceMs"] as number) ?? 250,
472
- snippetLength: (cfg["search.snippetLength"] as number) ?? 80,
473
- });
474
- setMissionsGridForm({
475
- minCols: (cfg["missions.grid.minCols"] as number) ?? 1,
476
- maxCols: (cfg["missions.grid.maxCols"] as number) ?? 5,
477
- minRows: (cfg["missions.grid.minRows"] as number) ?? 1,
478
- maxRows: (cfg["missions.grid.maxRows"] as number) ?? 5,
479
- });
480
- });
481
- }, []);
482
-
483
- // CLI Profile load
484
- useEffect(() => {
485
- getDefaultCliProfile().then((p) => {
486
- if (p) {
487
- setCliProfile(p);
488
- setCliCommand(p.command);
489
- setCliBaseArgsText(parseBaseArgsToText(p.baseArgs));
490
- setCliEnvVarsText(parseEnvVarsToText(p.envVars));
491
- }
492
- setCliLoading(false);
493
- });
494
- }, []);
495
-
496
- // Notifications load
497
- useEffect(() => {
498
- getConfigValue<boolean>("notification.enabled", true).then(setNotifEnabled);
499
- }, []);
500
-
501
- // =========================================================================
502
- // HANDLERS — General
503
- // =========================================================================
504
- async function handleSaveTerminalApp() {
505
- await setConfigValue("terminal.app", terminalApp);
506
- }
507
-
508
- async function handleSaveIdleTimeout() {
509
- const sec = Math.max(180, idleTimeout);
510
- setIdleTimeout(sec);
511
- await setConfigValue("terminal.idleTimeoutSec", sec);
512
- }
513
-
514
- // =========================================================================
515
- // HANDLERS — AI Tools
516
- // =========================================================================
517
- function handleSetAdapterDefault(adapterType: string) {
518
- setDefaultAdapter(adapterType);
519
- localStorage.setItem(DEFAULT_CLI_ADAPTER_KEY, adapterType);
520
- }
521
-
522
- async function handleTestAdapter(adapterType: string) {
523
- if (testingAdapter) return;
524
- setTestingAdapter(adapterType);
525
- setTestResults((prev) => {
526
- const next = { ...prev };
527
- delete next[adapterType];
528
- return next;
529
- });
530
- try {
531
- const res = await fetch("/api/adapters/test", {
532
- method: "POST",
533
- headers: { "Content-Type": "application/json" },
534
- body: JSON.stringify({ adapterType }),
535
- });
536
- const data: TestResult = await res.json();
537
- setTestResults((prev) => ({ ...prev, [adapterType]: data }));
538
- } catch {
539
- setTestResults((prev) => ({
540
- ...prev,
541
- [adapterType]: {
542
- ok: false,
543
- checks: [
544
- {
545
- name: "network_error",
546
- passed: false,
547
- message: "Network request failed",
548
- },
549
- ],
550
- },
551
- }));
552
- } finally {
553
- setTestingAdapter(null);
554
- }
555
- }
556
-
557
- // =========================================================================
558
- // HANDLERS — Prompts
559
- // =========================================================================
560
- const openCreatePromptDialog = useCallback(() => {
561
- setEditingPrompt(null);
562
- setPromptName("");
563
- setPromptDescription("");
564
- setPromptContent("");
565
- setPromptDialogOpen(true);
566
- }, []);
567
-
568
- const openEditPromptDialog = useCallback((prompt: AgentPrompt) => {
569
- setEditingPrompt(prompt);
570
- setPromptName(prompt.name);
571
- setPromptDescription(prompt.description ?? "");
572
- setPromptContent(prompt.content);
573
- setPromptDialogOpen(true);
574
- }, []);
575
-
576
- const handleSavePrompt = useCallback(async () => {
577
- if (!promptName.trim() || !promptContent.trim()) return;
578
- if (editingPrompt) {
579
- await updatePrompt(editingPrompt.id, {
580
- name: promptName.trim(),
581
- description: promptDescription.trim() || undefined,
582
- content: promptContent.trim(),
583
- });
584
- } else {
585
- await createPrompt({
586
- name: promptName.trim(),
587
- description: promptDescription.trim() || undefined,
588
- content: promptContent.trim(),
589
- });
590
- }
591
- setPromptDialogOpen(false);
592
- const updated = await getPrompts();
593
- setPrompts(updated);
594
- router.refresh();
595
- }, [promptName, promptDescription, promptContent, editingPrompt, router]);
596
-
597
- const handleDeletePrompt = useCallback(async () => {
598
- if (!deletePromptId) return;
599
- await deletePrompt(deletePromptId);
600
- setDeletePromptId(null);
601
- const updated = await getPrompts();
602
- setPrompts(updated);
603
- router.refresh();
604
- }, [deletePromptId, router]);
605
-
606
- const handleSetDefaultPrompt = useCallback(
607
- async (promptId: string) => {
608
- await setDefaultPrompt(promptId);
609
- const updated = await getPrompts();
610
- setPrompts(updated);
611
- router.refresh();
612
- },
613
- [router]
614
- );
615
-
616
- // =========================================================================
617
- // HANDLERS — System Config
618
- // =========================================================================
619
- const handleSaveSystem = async () => {
620
- await setConfigValue(
621
- "system.maxUploadBytes",
622
- systemForm.maxUploadMb * 1024 * 1024
623
- );
624
- await setConfigValue(
625
- "system.maxConcurrentExecutions",
626
- systemForm.maxConcurrent
627
- );
628
- };
629
-
630
- const handleSaveGitParams = async () => {
631
- await setConfigValue("git.timeoutSec", gitParamsForm.timeoutSec);
632
- };
633
-
634
- const handleSaveSearch = async () => {
635
- await setConfigValue("search.resultLimit", searchForm.resultLimit);
636
- await setConfigValue("search.allModeCap", searchForm.allModeCap);
637
- await setConfigValue("search.debounceMs", searchForm.debounceMs);
638
- await setConfigValue("search.snippetLength", searchForm.snippetLength);
639
- };
640
-
641
- const handleSaveMissionsGrid = async () => {
642
- const minCols = Math.min(
643
- missionsGridForm.minCols,
644
- missionsGridForm.maxCols
645
- );
646
- const maxCols = Math.max(
647
- missionsGridForm.minCols,
648
- missionsGridForm.maxCols
649
- );
650
- const minRows = Math.min(
651
- missionsGridForm.minRows,
652
- missionsGridForm.maxRows
653
- );
654
- const maxRows = Math.max(
655
- missionsGridForm.minRows,
656
- missionsGridForm.maxRows
657
- );
658
- setMissionsGridForm({ minCols, maxCols, minRows, maxRows });
659
- await setConfigValue("missions.grid.minCols", minCols);
660
- await setConfigValue("missions.grid.maxCols", maxCols);
661
- await setConfigValue("missions.grid.minRows", minRows);
662
- await setConfigValue("missions.grid.maxRows", maxRows);
663
- };
664
-
665
- const handleSaveAutoUploadTypes = async () => {
666
- const types = autoUploadTypes
667
- .split(",")
668
- .map((s) => s.trim())
669
- .filter(Boolean);
670
- await setConfigValue("hooks.autoUploadTypes", types);
671
- };
672
-
673
- const handleToggleHook = async () => {
674
- if (!hookStatus) return;
675
- setHookLoading(true);
676
- try {
677
- const method = hookStatus.installed ? "DELETE" : "POST";
678
- await fetch("/api/internal/hooks/install", { method });
679
- await fetchHookStatus();
680
- } finally {
681
- setHookLoading(false);
682
- }
683
- };
684
-
685
- /** Preview what a Git URL would resolve to with a given template */
686
- function previewPath(tpl: string, sampleUrl: string): string {
687
- if (!tpl || !sampleUrl) return "";
688
- const trimmed = sampleUrl.trim();
689
- let segments: string[] = [];
690
- const sshShort = trimmed.match(/^git@[^:]+:(.+)$/);
691
- if (sshShort) {
692
- segments = sshShort[1].replace(/\.git\/?$/, "").split("/").filter(Boolean);
693
- } else {
694
- try {
695
- const url = new URL(trimmed);
696
- segments = decodeURIComponent(url.pathname).replace(/\.git\/?$/, "").split("/").filter(Boolean);
697
- } catch { return ""; }
698
- }
699
- if (!segments.length) return "";
700
- const owner = segments[0];
701
- const repo = segments[segments.length - 1];
702
- const fullPath = segments.join("/");
703
- if (tpl.includes("{path}")) {
704
- return tpl.replace("{path}", fullPath).replace("{owner}", owner).replace("{repo}", repo).replace(/\/+$/, "");
705
- }
706
- const base = tpl.replace("{owner}", owner).replace("{repo}", "").replace(/\/+$/, "");
707
- return `${base}/${repo}`;
708
- }
709
-
710
- const handleAddRule = async () => {
711
- if (!addRuleForm.host.trim() || !addRuleForm.localPathTemplate.trim())
712
- return;
713
- const basePath = addRuleForm.localPathTemplate.trim().replace(/\/+$/, "");
714
- const template = useFullPath ? `${basePath}/{path}` : basePath;
715
- const newRule: GitPathRule = {
716
- id: crypto.randomUUID(),
717
- host: addRuleForm.host.trim(),
718
- ownerMatch: addRuleForm.ownerMatch.trim() || "*",
719
- localPathTemplate: template,
720
- priority: addRuleForm.priority,
721
- };
722
- const updated = [...rules, newRule];
723
- await setConfigValue("git.pathMappingRules", updated);
724
- setRules(updated);
725
- setAddRuleForm({ ...EMPTY_FORM });
726
- setUseFullPath(false);
727
- setShowAddRuleForm(false);
728
- };
729
-
730
- const handleEditRuleStart = (rule: GitPathRule) => {
731
- setEditingRuleId(rule.id);
732
- setEditRuleForm({
733
- host: rule.host,
734
- ownerMatch: rule.ownerMatch,
735
- localPathTemplate: rule.localPathTemplate,
736
- priority: rule.priority,
737
- });
738
- };
739
-
740
- const handleEditRuleSave = async (ruleId: string) => {
741
- if (!editRuleForm.host.trim() || !editRuleForm.localPathTemplate.trim())
742
- return;
743
- const updated = rules.map((r) =>
744
- r.id === ruleId
745
- ? {
746
- ...r,
747
- host: editRuleForm.host.trim(),
748
- ownerMatch: editRuleForm.ownerMatch.trim() || "*",
749
- localPathTemplate: editRuleForm.localPathTemplate.trim(),
750
- priority: editRuleForm.priority,
751
- }
752
- : r
753
- );
754
- await setConfigValue("git.pathMappingRules", updated);
755
- setRules(updated);
756
- setEditingRuleId(null);
757
- };
758
-
759
- const handleDeleteRule = async (ruleId: string) => {
760
- const updated = rules.filter((r) => r.id !== ruleId);
761
- await setConfigValue("git.pathMappingRules", updated);
762
- setRules(updated);
763
- setDeleteRuleConfirmId(null);
764
- };
765
-
766
- // =========================================================================
767
- // HANDLERS — CLI Profile
768
- // =========================================================================
769
- const handleSaveCliProfile = useCallback(async () => {
770
- if (!cliProfile) return;
771
- try {
772
- const baseArgs = JSON.stringify(
773
- cliBaseArgsText
774
- .split("\n")
775
- .map((s) => s.trim())
776
- .filter(Boolean)
777
- );
778
- const envVarsObj: Record<string, string> = {};
779
- cliEnvVarsText
780
- .split("\n")
781
- .map((line) => line.trim())
782
- .filter(Boolean)
783
- .forEach((line) => {
784
- const idx = line.indexOf("=");
785
- if (idx > 0) {
786
- const key = line.slice(0, idx).trim();
787
- const val = line.slice(idx + 1).trim();
788
- envVarsObj[key] = val;
789
- }
790
- });
791
- const envVars = JSON.stringify(envVarsObj);
792
- await updateCliProfile(cliProfile.id, {
793
- command: cliCommand,
794
- baseArgs,
795
- envVars,
796
- });
797
- setCliSaveStatus("saved");
798
- } catch {
799
- setCliSaveStatus("error");
800
- }
801
- setTimeout(() => setCliSaveStatus(""), 2000);
802
- }, [cliProfile, cliCommand, cliBaseArgsText, cliEnvVarsText]);
803
-
804
- // =========================================================================
805
- // HANDLERS — Notifications
806
- // =========================================================================
807
- async function handleToggleNotif() {
808
- const next = !notifEnabled;
809
- setNotifEnabled(next);
810
- await setConfigValue("notification.enabled", next);
811
- }
812
-
813
- // =========================================================================
814
- // Tab indicator
815
- // =========================================================================
816
- const handleClose = useCallback(() => {
817
- router.back();
818
- }, [router]);
819
-
820
- useEffect(() => {
821
- const container = tabsRef.current;
822
- if (!container) return;
823
- const activeTab = container.querySelector<HTMLButtonElement>(
824
- `[data-section="${activeSection}"]`
825
- );
826
- if (!activeTab) return;
827
- const containerRect = container.getBoundingClientRect();
828
- const tabRect = activeTab.getBoundingClientRect();
829
- setIndicatorStyle({
830
- left: tabRect.left - containerRect.left,
831
- width: tabRect.width,
832
- });
833
- }, [activeSection]);
834
-
835
- const activeConfig = SECTIONS.find((s) => s.id === activeSection);
836
- const accentStyle = activeConfig
837
- ? ACCENT_STYLES[activeConfig.accent]
838
- : ACCENT_STYLES.blue;
839
-
840
- // =========================================================================
841
- // RENDER — Section content
842
- // =========================================================================
843
-
844
- function renderGeneral() {
845
- const themeOptions = [
846
- { value: "light" as const, label: t("settings.themeLight") },
847
- { value: "dark" as const, label: t("settings.themeDark") },
848
- { value: "system" as const, label: t("settings.themeSystem") },
849
- ];
850
- const langOptions = [
851
- { value: "zh" as Locale, label: "中文" },
852
- { value: "en" as Locale, label: "English" },
853
- ];
854
-
855
- return (
856
- <div className="divide-y divide-border/50">
857
- {/* Theme */}
858
- <SettingRow
859
- label={t("settings.theme")}
860
- description={t("settings.themeDesc")}
861
- >
862
- {!mounted ? (
863
- <div className="inline-flex h-9 rounded-lg border border-border/50 bg-muted/30 p-1 w-[200px]" />
864
- ) : (
865
- <SegmentedToggle
866
- options={themeOptions}
867
- value={(theme ?? "system") as "light" | "dark" | "system"}
868
- onChange={(v) => setTheme(v)}
869
- />
870
- )}
871
- </SettingRow>
872
-
873
- {/* Language */}
874
- <SettingRow
875
- label={t("settings.language")}
876
- description={t("settings.languageDesc")}
877
- >
878
- <SegmentedToggle
879
- options={langOptions}
880
- value={locale}
881
- onChange={(v) => setLocale(v as typeof locale)}
882
- />
883
- </SettingRow>
884
-
885
- {/* Terminal App */}
886
- <div className="py-4 border-b border-border/50">
887
- <div className="flex items-center justify-between">
888
- <div className="min-w-0 flex-1 pr-4">
889
- <div className="text-sm font-medium">
890
- {t("settings.terminal.label")}
891
- </div>
892
- <div className="text-xs text-muted-foreground mt-0.5">
893
- {t("settings.terminal.desc")}
894
- </div>
895
- </div>
896
- </div>
897
- <div className="mt-3 flex flex-col gap-2">
898
- {detectedApps.length > 0 && (
899
- <div className="flex flex-wrap gap-2">
900
- {detectedApps.map((app) => (
901
- <button
902
- key={app.value}
903
- type="button"
904
- onClick={() => {
905
- setTerminalApp(app.value);
906
- void setConfigValue("terminal.app", app.value);
907
- }}
908
- className={cn(
909
- "rounded-lg border px-3.5 py-1.5 text-xs font-medium transition-all duration-200 cursor-pointer",
910
- terminalApp === app.value
911
- ? "border-foreground bg-accent text-foreground font-medium"
912
- : "border-border text-muted-foreground hover:bg-accent/50 hover:text-foreground"
913
- )}
914
- >
915
- {app.name}
916
- </button>
917
- ))}
918
- </div>
919
- )}
920
- <input
921
- type="text"
922
- value={terminalApp}
923
- onChange={(e) => setTerminalApp(e.target.value)}
924
- onBlur={handleSaveTerminalApp}
925
- placeholder={t("settings.terminal.placeholder")}
926
- className="h-9 w-64 rounded-lg border border-border/50 bg-muted/30 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/30"
927
- />
928
- </div>
929
- </div>
930
-
931
- {/* Idle timeout */}
932
- <SettingRow
933
- label={t("settings.terminal.idleTimeout")}
934
- description={t("settings.terminal.idleTimeoutDesc")}
935
- >
936
- <input
937
- type="number"
938
- value={idleTimeout}
939
- onChange={(e) => setIdleTimeout(Number(e.target.value))}
940
- onBlur={handleSaveIdleTimeout}
941
- min={180}
942
- className="h-9 w-28 rounded-lg border border-border/50 bg-muted/30 px-3 text-sm text-right focus:outline-none focus:ring-2 focus:ring-blue-500/30"
943
- />
944
- </SettingRow>
945
- </div>
946
- );
947
- }
948
-
949
- function renderAiTools() {
950
- return (
951
- <ul className="divide-y rounded-xl border border-border bg-card">
952
- {CLI_ADAPTERS.map((adapter) => {
953
- const isDefault = defaultAdapter === adapter.type;
954
- const isTesting = testingAdapter === adapter.type;
955
- const result = testResults[adapter.type];
956
-
957
- return (
958
- <li key={adapter.type}>
959
- <div className="px-5 py-4">
960
- {/* Row: info left, actions right */}
961
- <div className="flex items-center gap-4">
962
- <div className="min-w-0 flex-1">
963
- <div className="flex flex-wrap items-center gap-2">
964
- <span className="font-medium">{adapter.label}</span>
965
- <Badge variant="outline">{t("label.builtin")}</Badge>
966
- {isDefault && (
967
- <Badge variant="secondary" className="shrink-0">
968
- <Star className="h-3 w-3 mr-1 fill-yellow-400 text-yellow-400" />
969
- {t("settings.prompts.default")}
970
- </Badge>
971
- )}
972
- {result && (
973
- <Badge
974
- variant={result.ok ? "secondary" : "destructive"}
975
- className={cn(
976
- "shrink-0",
977
- result.ok && "bg-green-600 text-white hover:bg-green-700"
978
- )}
979
- >
980
- {result.ok ? (
981
- <><CheckCircle2 className="h-3 w-3 mr-1" />{t("settings.aiTools.testPassed")}</>
982
- ) : (
983
- <><XCircle className="h-3 w-3 mr-1" />{t("settings.aiTools.testFailed")}</>
984
- )}
985
- </Badge>
986
- )}
987
- </div>
988
- <p className="text-xs text-muted-foreground mt-0.5">
989
- {adapter.type}
990
- </p>
991
- </div>
992
- <div className="flex items-center gap-2 shrink-0">
993
- {!isDefault && (
994
- <Button
995
- variant="outline"
996
- size="sm"
997
- onClick={() => handleSetAdapterDefault(adapter.type)}
998
- >
999
- <Star className="h-3.5 w-3.5 mr-1.5 text-muted-foreground" />
1000
- {t("settings.prompts.setDefault")}
1001
- </Button>
1002
- )}
1003
- <Button
1004
- variant="outline"
1005
- size="sm"
1006
- onClick={() => handleTestAdapter(adapter.type)}
1007
- disabled={isTesting}
1008
- >
1009
- {isTesting ? (
1010
- <>
1011
- <Loader2 className="h-3.5 w-3.5 animate-spin mr-1.5" />
1012
- {t("settings.aiTools.testing")}
1013
- </>
1014
- ) : (
1015
- t("settings.aiTools.testConnection")
1016
- )}
1017
- </Button>
1018
- {adapter.source === "external" && (
1019
- <Button
1020
- variant="outline"
1021
- size="icon-sm"
1022
- className="h-8 w-8 text-destructive hover:text-destructive"
1023
- title={t("common.delete")}
1024
- >
1025
- <Trash2 className="h-4 w-4" />
1026
- </Button>
1027
- )}
1028
- </div>
1029
- </div>
1030
-
1031
- {/* Test results */}
1032
- {result && (
1033
- <div className="mt-3 rounded-md border border-border bg-muted/30 px-4 py-3">
1034
- <div className="space-y-1.5">
1035
- {result.checks.map((check) => (
1036
- <div
1037
- key={`${adapter.type}-${check.name}`}
1038
- className="flex items-center gap-2 text-sm"
1039
- >
1040
- <span
1041
- className={cn(
1042
- "w-1.5 h-1.5 rounded-full shrink-0",
1043
- check.passed ? "bg-green-500" : "bg-red-500"
1044
- )}
1045
- />
1046
- <span className={cn(
1047
- check.passed
1048
- ? "text-foreground"
1049
- : "text-red-700 dark:text-red-300"
1050
- )}>
1051
- {check.message}
1052
- </span>
1053
- </div>
1054
- ))}
1055
- </div>
1056
- </div>
1057
- )}
1058
- </div>
1059
- </li>
1060
- );
1061
- })}
1062
- </ul>
1063
- );
1064
- }
1065
-
1066
- function renderPrompts() {
1067
- if (!mounted) {
1068
- return <div className="h-32 rounded-lg bg-muted animate-pulse" />;
1069
- }
1070
-
1071
- return (
1072
- <div className="space-y-4">
1073
- {/* Create button */}
1074
- <div className="flex justify-end">
1075
- <Button
1076
- onClick={openCreatePromptDialog}
1077
- variant="default"
1078
- >
1079
- <Plus className="h-4 w-4 mr-2" />
1080
- {t("settings.prompts.newPrompt")}
1081
- </Button>
1082
- </div>
1083
-
1084
- {/* Prompt list — table-like rows */}
1085
- {prompts.length === 0 ? (
1086
- <div className="flex flex-col items-center justify-center py-12 text-center rounded-lg border border-dashed border-border/50">
1087
- <p className="text-muted-foreground">
1088
- {t("settings.prompts.empty")}
1089
- </p>
1090
- <p className="mt-1 text-sm text-muted-foreground">
1091
- {t("settings.prompts.emptyHint")}
1092
- </p>
1093
- </div>
1094
- ) : (
1095
- <div className="rounded-xl border border-border/50 divide-y divide-border/50">
1096
- {prompts.map((prompt) => (
1097
- <div
1098
- key={prompt.id}
1099
- className="flex items-center justify-between px-4 py-3.5 hover:bg-muted/30 transition-colors"
1100
- >
1101
- <div className="flex-1 min-w-0">
1102
- <div className="flex items-center gap-2">
1103
- <h4 className="text-sm font-medium truncate">
1104
- {prompt.name}
1105
- </h4>
1106
- {prompt.isDefault && (
1107
- <Badge
1108
- variant="secondary"
1109
- className="shrink-0 rounded-full text-xs"
1110
- >
1111
- <Star className="h-3 w-3 mr-1 fill-yellow-400 text-yellow-400" />
1112
- {t("settings.prompts.default")}
1113
- </Badge>
1114
- )}
1115
- </div>
1116
- {prompt.description && (
1117
- <p className="mt-0.5 text-xs text-muted-foreground truncate">
1118
- {prompt.description}
1119
- </p>
1120
- )}
1121
- </div>
1122
- <div className="flex items-center gap-1 shrink-0 ml-4">
1123
- <Button
1124
- variant="ghost"
1125
- size="icon-sm"
1126
- onClick={() => handleSetDefaultPrompt(prompt.id)}
1127
- title={t("settings.prompts.setDefault")}
1128
- >
1129
- <Star
1130
- className={cn(
1131
- "h-4 w-4",
1132
- prompt.isDefault
1133
- ? "fill-yellow-400 text-yellow-400"
1134
- : "text-muted-foreground"
1135
- )}
1136
- />
1137
- </Button>
1138
- <Button
1139
- variant="ghost"
1140
- size="icon-sm"
1141
- onClick={() => openEditPromptDialog(prompt)}
1142
- title={t("settings.prompts.editPrompt")}
1143
- >
1144
- <Edit className="h-4 w-4" />
1145
- </Button>
1146
- <Button
1147
- variant="ghost"
1148
- size="icon-sm"
1149
- onClick={() => setDeletePromptId(prompt.id)}
1150
- className="text-destructive"
1151
- title={t("settings.prompts.delete")}
1152
- >
1153
- <Trash2 className="h-4 w-4" />
1154
- </Button>
1155
- </div>
1156
- </div>
1157
- ))}
1158
- </div>
1159
- )}
1160
-
1161
- {/* Create/Edit Dialog */}
1162
- <Dialog open={promptDialogOpen} onOpenChange={setPromptDialogOpen}>
1163
- <DialogContent>
1164
- <DialogHeader>
1165
- <DialogTitle>
1166
- {editingPrompt
1167
- ? t("settings.prompts.editPrompt")
1168
- : t("settings.prompts.newPrompt")}
1169
- </DialogTitle>
1170
- <DialogDescription>
1171
- {editingPrompt
1172
- ? t("settings.prompts.editPrompt")
1173
- : t("settings.prompts.newPrompt")}
1174
- </DialogDescription>
1175
- </DialogHeader>
1176
- <div className="space-y-4 py-4">
1177
- <div>
1178
- <Label htmlFor="prompt-name">
1179
- {t("settings.prompts.promptName")}
1180
- </Label>
1181
- <Input
1182
- id="prompt-name"
1183
- value={promptName}
1184
- onChange={(e) => setPromptName(e.target.value)}
1185
- placeholder={t("settings.prompts.promptNamePlaceholder")}
1186
- className="mt-1.5"
1187
- />
1188
- </div>
1189
- <div>
1190
- <Label htmlFor="prompt-description">
1191
- {t("settings.prompts.promptDescription")}
1192
- </Label>
1193
- <Input
1194
- id="prompt-description"
1195
- value={promptDescription}
1196
- onChange={(e) => setPromptDescription(e.target.value)}
1197
- placeholder={t(
1198
- "settings.prompts.promptDescriptionPlaceholder"
1199
- )}
1200
- className="mt-1.5"
1201
- />
1202
- </div>
1203
- <div>
1204
- <Label htmlFor="prompt-content">
1205
- {t("settings.prompts.promptContent")}
1206
- </Label>
1207
- <Textarea
1208
- id="prompt-content"
1209
- value={promptContent}
1210
- onChange={(e) => setPromptContent(e.target.value)}
1211
- placeholder={t("settings.prompts.promptContentPlaceholder")}
1212
- rows={8}
1213
- className="mt-1.5 font-mono text-sm"
1214
- />
1215
- </div>
1216
- </div>
1217
- <DialogFooter>
1218
- <Button
1219
- variant="outline"
1220
- onClick={() => setPromptDialogOpen(false)}
1221
- >
1222
- {t("settings.prompts.cancel")}
1223
- </Button>
1224
- <Button
1225
- onClick={handleSavePrompt}
1226
- disabled={!promptName.trim() || !promptContent.trim()}
1227
- >
1228
- {t("settings.prompts.save")}
1229
- </Button>
1230
- </DialogFooter>
1231
- </DialogContent>
1232
- </Dialog>
1233
-
1234
- {/* Delete Confirmation Dialog */}
1235
- <Dialog
1236
- open={!!deletePromptId}
1237
- onOpenChange={(open) => !open && setDeletePromptId(null)}
1238
- >
1239
- <DialogContent>
1240
- <DialogHeader>
1241
- <DialogTitle>
1242
- {t("settings.prompts.deleteConfirmTitle")}
1243
- </DialogTitle>
1244
- <DialogDescription>
1245
- {t("settings.prompts.deleteConfirmMessage")}
1246
- </DialogDescription>
1247
- </DialogHeader>
1248
- <DialogFooter>
1249
- <Button
1250
- variant="outline"
1251
- onClick={() => setDeletePromptId(null)}
1252
- >
1253
- {t("settings.prompts.cancel")}
1254
- </Button>
1255
- <Button variant="destructive" onClick={handleDeletePrompt}>
1256
- {t("settings.prompts.delete")}
1257
- </Button>
1258
- </DialogFooter>
1259
- </DialogContent>
1260
- </Dialog>
1261
- </div>
1262
- );
1263
- }
1264
-
1265
- function renderSystemConfig() {
1266
- return (
1267
- <div className="space-y-8">
1268
- {/* ── Git Path Mapping Rules ──────────────────────────── */}
1269
- <div>
1270
- <div className="flex items-center justify-between mb-4">
1271
- <div>
1272
- <h3 className="text-sm font-semibold">
1273
- {t("settings.config.git.title")}
1274
- </h3>
1275
- <p className="mt-0.5 text-xs text-muted-foreground">
1276
- {t("settings.config.git.desc")}
1277
- </p>
1278
- </div>
1279
- <Button
1280
- onClick={() => {
1281
- setAddRuleForm({ ...EMPTY_FORM });
1282
- setShowAddRuleForm(true);
1283
- }}
1284
- >
1285
- <Plus className="mr-2 h-4 w-4" />
1286
- {t("settings.config.git.addRule")}
1287
- </Button>
1288
- </div>
1289
-
1290
- <div className="space-y-3">
1291
- {rules.length === 0 && !showAddRuleForm ? (
1292
- <div className="rounded-xl border border-dashed border-border p-8 text-center">
1293
- <p className="text-sm text-muted-foreground">
1294
- {t("settings.config.git.noRules")}
1295
- </p>
1296
- </div>
1297
- ) : (
1298
- <ul className="divide-y rounded-xl border border-border bg-card">
1299
- {rules.map((rule) =>
1300
- editingRuleId === rule.id ? (
1301
- <li key={rule.id} className="px-5 py-4 bg-muted/20">
1302
- <div className="grid grid-cols-2 gap-3">
1303
- <div className="space-y-1">
1304
- <label className="text-xs text-muted-foreground">{t("settings.config.git.host")}</label>
1305
- <Input value={editRuleForm.host} onChange={(e) => setEditRuleForm((f) => ({ ...f, host: e.target.value }))} placeholder={t("settings.config.git.hostPlaceholder")} className="text-sm" />
1306
- </div>
1307
- <div className="space-y-1">
1308
- <label className="text-xs text-muted-foreground">{t("settings.config.git.ownerMatch")}</label>
1309
- <Input value={editRuleForm.ownerMatch} onChange={(e) => setEditRuleForm((f) => ({ ...f, ownerMatch: e.target.value }))} placeholder={t("settings.config.git.ownerMatchPlaceholder")} className="text-sm" />
1310
- </div>
1311
- <div className="space-y-1 col-span-2">
1312
- <label className="text-xs text-muted-foreground">{t("settings.config.git.localPathTemplate")}</label>
1313
- <Input value={editRuleForm.localPathTemplate} onChange={(e) => setEditRuleForm((f) => ({ ...f, localPathTemplate: e.target.value }))} placeholder={t("settings.config.git.localPathTemplatePlaceholder")} className="text-sm font-mono" />
1314
- </div>
1315
- <div className="space-y-1">
1316
- <label className="text-xs text-muted-foreground">{t("settings.config.git.priority")}</label>
1317
- <Input type="number" value={editRuleForm.priority} onChange={(e) => setEditRuleForm((f) => ({ ...f, priority: Number(e.target.value) }))} className="text-sm w-24" />
1318
- </div>
1319
- </div>
1320
- <div className="flex justify-end gap-2 mt-3">
1321
- <Button variant="ghost" size="sm" onClick={() => setEditingRuleId(null)}>{t("settings.config.git.cancel")}</Button>
1322
- <Button size="sm" onClick={() => handleEditRuleSave(rule.id)}>{t("settings.config.git.save")}</Button>
1323
- </div>
1324
- </li>
1325
- ) : (
1326
- <li key={rule.id} className="group px-5 py-4 hover:bg-muted/20 transition-colors">
1327
- <div className="flex items-center gap-4">
1328
- <div className="min-w-0 flex-1">
1329
- <div className="flex items-center gap-2">
1330
- <span className="font-medium text-sm">{rule.host}</span>
1331
- {rule.ownerMatch !== "*" && (
1332
- <span className="text-xs text-muted-foreground">/ {rule.ownerMatch}</span>
1333
- )}
1334
- <Badge variant="outline" className="text-[10px] px-1.5 py-0">{t("settings.config.git.priority")} {rule.priority}</Badge>
1335
- </div>
1336
- <p className="mt-0.5 font-mono text-xs text-muted-foreground truncate">{rule.localPathTemplate}</p>
1337
- </div>
1338
- <div className="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity">
1339
- <Button variant="ghost" size="icon-sm" onClick={() => handleEditRuleStart(rule)} title={t("settings.config.git.edit")}>
1340
- <Edit className="h-4 w-4" />
1341
- </Button>
1342
- <Button variant="ghost" size="icon-sm" onClick={() => setDeleteRuleConfirmId(rule.id)} className="text-destructive" title={t("settings.config.git.delete")}>
1343
- <Trash2 className="h-4 w-4" />
1344
- </Button>
1345
- </div>
1346
- </div>
1347
- </li>
1348
- )
1349
- )}
1350
- </ul>
1351
- )}
1352
-
1353
- {/* Add rule form */}
1354
- {showAddRuleForm && (
1355
- <div className="rounded-xl border border-border bg-muted/20 p-5 space-y-4">
1356
- <div className="grid grid-cols-2 gap-4">
1357
- <div className="space-y-1.5">
1358
- <label className="text-xs font-medium">{t("settings.config.git.host")}</label>
1359
- <Input value={addRuleForm.host} onChange={(e) => setAddRuleForm((f) => ({ ...f, host: e.target.value }))} placeholder={t("settings.config.git.hostPlaceholder")} className="text-sm" autoFocus />
1360
- </div>
1361
- <div className="space-y-1.5">
1362
- <label className="text-xs font-medium">{t("settings.config.git.ownerMatch")}</label>
1363
- <Input value={addRuleForm.ownerMatch} onChange={(e) => setAddRuleForm((f) => ({ ...f, ownerMatch: e.target.value }))} placeholder={t("settings.config.git.ownerMatchPlaceholder")} className="text-sm" />
1364
- </div>
1365
- </div>
1366
-
1367
- <div className="space-y-1.5">
1368
- <label className="text-xs font-medium">{t("settings.config.git.localPathTemplate")}</label>
1369
- <div className="flex items-center gap-2">
1370
- <Input
1371
- value={addRuleForm.localPathTemplate}
1372
- onChange={(e) => setAddRuleForm((f) => ({ ...f, localPathTemplate: e.target.value }))}
1373
- placeholder={t("settings.config.git.localPathTemplatePlaceholder")}
1374
- className="text-sm font-mono flex-1"
1375
- />
1376
- <button
1377
- type="button"
1378
- onClick={() => setUseFullPath((v) => !v)}
1379
- className={cn(
1380
- "shrink-0 rounded-full px-2.5 py-1 text-[11px] font-mono font-medium transition-colors cursor-pointer",
1381
- useFullPath ? "bg-foreground text-background" : "bg-muted text-muted-foreground hover:text-foreground"
1382
- )}
1383
- >
1384
- {"{path}"}
1385
- </button>
1386
- </div>
1387
- <p className="text-xs text-muted-foreground">
1388
- {useFullPath ? t("onboarding.step3.pathHintFull") : t("onboarding.step3.pathHintRepo")}
1389
- </p>
1390
- </div>
1391
-
1392
- <div className="space-y-1.5">
1393
- <label className="text-xs font-medium">{t("settings.config.git.priority")}</label>
1394
- <Input type="number" value={addRuleForm.priority} onChange={(e) => setAddRuleForm((f) => ({ ...f, priority: Number(e.target.value) }))} className="text-sm w-24" />
1395
- </div>
1396
-
1397
- {/* Live preview */}
1398
- {addRuleForm.localPathTemplate && (() => {
1399
- const basePath = addRuleForm.localPathTemplate.trim().replace(/\/+$/, "");
1400
- const tpl = useFullPath ? `${basePath}/{path}` : basePath;
1401
- const samples = [
1402
- { label: "GitHub SSH", url: "git@github.com:user/my-app.git" },
1403
- { label: "GitHub HTTPS", url: "https://github.com/user/my-app.git" },
1404
- { label: "GitLab Subgroup", url: "https://gitlab.com/org/team/sub/my-api.git" },
1405
- ];
1406
- return (
1407
- <div className="rounded-lg bg-muted/40 border border-border px-4 py-3 space-y-2">
1408
- <div className="flex items-center gap-2">
1409
- <span className="text-xs font-medium text-muted-foreground">{t("onboarding.step3.previewLabel")}</span>
1410
- <div className="flex gap-1">
1411
- {samples.map((s, i) => (
1412
- <button key={i} type="button" onClick={() => setPreviewIdx(i)}
1413
- className={cn("rounded-md px-2 py-0.5 text-[11px] font-medium transition-colors cursor-pointer",
1414
- previewIdx === i ? "bg-foreground text-background" : "bg-muted text-muted-foreground hover:text-foreground"
1415
- )}>
1416
- {s.label}
1417
- </button>
1418
- ))}
1419
- </div>
1420
- </div>
1421
- <div className="space-y-0.5">
1422
- <p className="font-mono text-[11px] text-muted-foreground truncate">{samples[previewIdx].url}</p>
1423
- <p className="font-mono text-sm">
1424
- <span className="text-muted-foreground">→ </span>
1425
- <span className="text-foreground font-medium">{previewPath(tpl, samples[previewIdx].url)}</span>
1426
- </p>
1427
- </div>
1428
- </div>
1429
- );
1430
- })()}
1431
-
1432
- <div className="flex justify-end gap-2">
1433
- <Button variant="ghost" size="sm" onClick={() => setShowAddRuleForm(false)}>{t("settings.config.git.cancel")}</Button>
1434
- <Button size="sm" onClick={handleAddRule} disabled={!addRuleForm.host.trim() || !addRuleForm.localPathTemplate.trim()}>
1435
- <Save className="h-3.5 w-3.5 mr-1.5" />
1436
- {t("settings.config.git.save")}
1437
- </Button>
1438
- </div>
1439
- </div>
1440
- )}
1441
- </div>
1442
- </div>
1443
-
1444
- {/* ── System Parameters ────────────────────────────────── */}
1445
- <div className="rounded-xl border border-border bg-muted/50 p-5 space-y-4">
1446
- <div>
1447
- <h3 className="text-sm font-semibold">
1448
- {t("settings.config.system.title")}
1449
- </h3>
1450
- <p className="mt-0.5 text-xs text-muted-foreground">
1451
- {t("settings.config.system.desc")}
1452
- </p>
1453
- </div>
1454
- <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
1455
- <div className="flex items-center gap-4">
1456
- <div className="flex-1 min-w-0">
1457
- <label className="text-sm font-medium">
1458
- {t("settings.config.system.maxUpload")}
1459
- </label>
1460
- <p className="text-xs text-muted-foreground">
1461
- {t("settings.config.system.maxUploadHint")}
1462
- </p>
1463
- </div>
1464
- <div className="flex items-center gap-2">
1465
- <Input
1466
- type="number"
1467
- min={1}
1468
- max={500}
1469
- value={systemForm.maxUploadMb}
1470
- onChange={(e) =>
1471
- setSystemForm((f) => ({
1472
- ...f,
1473
- maxUploadMb: Number(e.target.value),
1474
- }))
1475
- }
1476
- className="w-24 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1477
- />
1478
- <span className="text-sm text-muted-foreground">MB</span>
1479
- </div>
1480
- </div>
1481
- <div className="flex items-center gap-4">
1482
- <div className="flex-1 min-w-0">
1483
- <label className="text-sm font-medium">
1484
- {t("settings.config.system.maxConcurrent")}
1485
- </label>
1486
- <p className="text-xs text-muted-foreground">
1487
- {t("settings.config.system.maxConcurrentHint")}
1488
- </p>
1489
- </div>
1490
- <Input
1491
- type="number"
1492
- min={1}
1493
- max={10}
1494
- value={systemForm.maxConcurrent}
1495
- onChange={(e) =>
1496
- setSystemForm((f) => ({
1497
- ...f,
1498
- maxConcurrent: Number(e.target.value),
1499
- }))
1500
- }
1501
- className="w-24 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1502
- />
1503
- </div>
1504
- </div>
1505
- <Button onClick={handleSaveSystem} className="rounded-lg">
1506
- {t("common.save")}
1507
- </Button>
1508
- </div>
1509
-
1510
- {/* ── Git Parameters ──────────────────────────────────── */}
1511
- <div className="rounded-xl border border-border bg-muted/50 p-5 space-y-4">
1512
- <div>
1513
- <h3 className="text-sm font-semibold">
1514
- {t("settings.config.gitParams.title")}
1515
- </h3>
1516
- <p className="mt-0.5 text-xs text-muted-foreground">
1517
- {t("settings.config.gitParams.desc")}
1518
- </p>
1519
- </div>
1520
- <div className="flex items-center gap-4">
1521
- <div className="flex-1">
1522
- <label className="text-sm font-medium">
1523
- {t("settings.config.gitParams.timeout")}
1524
- </label>
1525
- <p className="text-xs text-muted-foreground">
1526
- {t("settings.config.gitParams.timeoutHint")}
1527
- </p>
1528
- </div>
1529
- <div className="flex items-center gap-2">
1530
- <Input
1531
- type="number"
1532
- min={5}
1533
- max={300}
1534
- value={gitParamsForm.timeoutSec}
1535
- onChange={(e) =>
1536
- setGitParamsForm((f) => ({
1537
- ...f,
1538
- timeoutSec: Number(e.target.value),
1539
- }))
1540
- }
1541
- className="w-24 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1542
- />
1543
- <span className="text-sm text-muted-foreground">s</span>
1544
- </div>
1545
- </div>
1546
- <Button onClick={handleSaveGitParams} className="rounded-lg">
1547
- {t("common.save")}
1548
- </Button>
1549
- </div>
1550
-
1551
- {/* ── Search Parameters ───────────────────────────────── */}
1552
- <div className="rounded-xl border border-border bg-muted/50 p-5 space-y-4">
1553
- <div>
1554
- <h3 className="text-sm font-semibold">
1555
- {t("settings.config.search.title")}
1556
- </h3>
1557
- <p className="mt-0.5 text-xs text-muted-foreground">
1558
- {t("settings.config.search.desc")}
1559
- </p>
1560
- </div>
1561
- <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
1562
- <div className="flex items-center gap-4">
1563
- <div className="flex-1 min-w-0">
1564
- <label className="text-sm font-medium">
1565
- {t("settings.config.search.resultLimit")}
1566
- </label>
1567
- <p className="text-xs text-muted-foreground">
1568
- {t("settings.config.search.resultLimitHint")}
1569
- </p>
1570
- </div>
1571
- <Input
1572
- type="number"
1573
- min={5}
1574
- max={100}
1575
- value={searchForm.resultLimit}
1576
- onChange={(e) =>
1577
- setSearchForm((f) => ({
1578
- ...f,
1579
- resultLimit: Number(e.target.value),
1580
- }))
1581
- }
1582
- className="w-24 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1583
- />
1584
- </div>
1585
- <div className="flex items-center gap-4">
1586
- <div className="flex-1 min-w-0">
1587
- <label className="text-sm font-medium">
1588
- {t("settings.config.search.allModeCap")}
1589
- </label>
1590
- <p className="text-xs text-muted-foreground">
1591
- {t("settings.config.search.allModeCapHint")}
1592
- </p>
1593
- </div>
1594
- <Input
1595
- type="number"
1596
- min={1}
1597
- max={20}
1598
- value={searchForm.allModeCap}
1599
- onChange={(e) =>
1600
- setSearchForm((f) => ({
1601
- ...f,
1602
- allModeCap: Number(e.target.value),
1603
- }))
1604
- }
1605
- className="w-24 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1606
- />
1607
- </div>
1608
- <div className="flex items-center gap-4">
1609
- <div className="flex-1 min-w-0">
1610
- <label className="text-sm font-medium">
1611
- {t("settings.config.search.debounceMs")}
1612
- </label>
1613
- <p className="text-xs text-muted-foreground">
1614
- {t("settings.config.search.debounceMsHint")}
1615
- </p>
1616
- </div>
1617
- <div className="flex items-center gap-2">
1618
- <Input
1619
- type="number"
1620
- min={50}
1621
- max={1000}
1622
- value={searchForm.debounceMs}
1623
- onChange={(e) =>
1624
- setSearchForm((f) => ({
1625
- ...f,
1626
- debounceMs: Number(e.target.value),
1627
- }))
1628
- }
1629
- className="w-24 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1630
- />
1631
- <span className="text-sm text-muted-foreground">ms</span>
1632
- </div>
1633
- </div>
1634
- <div className="flex items-center gap-4">
1635
- <div className="flex-1 min-w-0">
1636
- <label className="text-sm font-medium">
1637
- {t("settings.config.search.snippetLength")}
1638
- </label>
1639
- <p className="text-xs text-muted-foreground">
1640
- {t("settings.config.search.snippetLengthHint")}
1641
- </p>
1642
- </div>
1643
- <Input
1644
- type="number"
1645
- min={20}
1646
- max={500}
1647
- value={searchForm.snippetLength}
1648
- onChange={(e) =>
1649
- setSearchForm((f) => ({
1650
- ...f,
1651
- snippetLength: Number(e.target.value),
1652
- }))
1653
- }
1654
- className="w-24 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1655
- />
1656
- </div>
1657
- </div>
1658
- <Button onClick={handleSaveSearch} className="rounded-lg">
1659
- {t("common.save")}
1660
- </Button>
1661
- </div>
1662
-
1663
- {/* ── Missions Grid Layout ────────────────────────────── */}
1664
- <div className="rounded-xl border border-border bg-muted/50 p-5 space-y-4">
1665
- <div>
1666
- <h3 className="text-sm font-semibold">
1667
- {t("settings.config.missions.title")}
1668
- </h3>
1669
- <p className="mt-0.5 text-xs text-muted-foreground">
1670
- {t("settings.config.missions.desc")}
1671
- </p>
1672
- </div>
1673
- <div className="grid grid-cols-2 gap-4">
1674
- <div className="flex items-center gap-4">
1675
- <label className="text-sm font-medium flex-1">
1676
- {t("settings.config.missions.minCols")}
1677
- </label>
1678
- <Input
1679
- type="number"
1680
- min={1}
1681
- max={10}
1682
- value={missionsGridForm.minCols}
1683
- onChange={(e) =>
1684
- setMissionsGridForm((f) => ({
1685
- ...f,
1686
- minCols: Number(e.target.value),
1687
- }))
1688
- }
1689
- className="w-20 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1690
- />
1691
- </div>
1692
- <div className="flex items-center gap-4">
1693
- <label className="text-sm font-medium flex-1">
1694
- {t("settings.config.missions.maxCols")}
1695
- </label>
1696
- <Input
1697
- type="number"
1698
- min={1}
1699
- max={10}
1700
- value={missionsGridForm.maxCols}
1701
- onChange={(e) =>
1702
- setMissionsGridForm((f) => ({
1703
- ...f,
1704
- maxCols: Number(e.target.value),
1705
- }))
1706
- }
1707
- className="w-20 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1708
- />
1709
- </div>
1710
- <div className="flex items-center gap-4">
1711
- <label className="text-sm font-medium flex-1">
1712
- {t("settings.config.missions.minRows")}
1713
- </label>
1714
- <Input
1715
- type="number"
1716
- min={1}
1717
- max={10}
1718
- value={missionsGridForm.minRows}
1719
- onChange={(e) =>
1720
- setMissionsGridForm((f) => ({
1721
- ...f,
1722
- minRows: Number(e.target.value),
1723
- }))
1724
- }
1725
- className="w-20 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1726
- />
1727
- </div>
1728
- <div className="flex items-center gap-4">
1729
- <label className="text-sm font-medium flex-1">
1730
- {t("settings.config.missions.maxRows")}
1731
- </label>
1732
- <Input
1733
- type="number"
1734
- min={1}
1735
- max={10}
1736
- value={missionsGridForm.maxRows}
1737
- onChange={(e) =>
1738
- setMissionsGridForm((f) => ({
1739
- ...f,
1740
- maxRows: Number(e.target.value),
1741
- }))
1742
- }
1743
- className="w-20 text-right rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1744
- />
1745
- </div>
1746
- </div>
1747
- <Button onClick={handleSaveMissionsGrid} className="rounded-lg">
1748
- {t("common.save")}
1749
- </Button>
1750
- </div>
1751
-
1752
- {/* ── Hooks Configuration ─────────────────────────────── */}
1753
- <div className="rounded-xl border border-border bg-muted/50 p-5 space-y-4">
1754
- <div>
1755
- <h3 className="text-sm font-semibold">
1756
- {t("settings.config.hooks.title")}
1757
- </h3>
1758
- <p className="mt-0.5 text-xs text-muted-foreground">
1759
- {t("settings.config.hooks.desc")}
1760
- </p>
1761
- </div>
1762
- <div className="flex items-center gap-4">
1763
- <div className="flex-1">
1764
- <label className="text-sm font-medium">
1765
- {t("settings.config.hooks.autoUploadTypes")}
1766
- </label>
1767
- <p className="text-xs text-muted-foreground">
1768
- {t("settings.config.hooks.autoUploadTypesHint")}
1769
- </p>
1770
- </div>
1771
- <Input
1772
- value={autoUploadTypes}
1773
- onChange={(e) => setAutoUploadTypes(e.target.value)}
1774
- placeholder="png, jpg, jpeg, gif, webp, svg, pdf"
1775
- className="w-80 rounded-lg border-border/50 bg-muted/30 focus:ring-2 focus:ring-amber-500/30"
1776
- />
1777
- </div>
1778
- <Button onClick={handleSaveAutoUploadTypes} className="rounded-lg">
1779
- {t("common.save")}
1780
- </Button>
1781
-
1782
- <div className="flex items-center gap-4 pt-4 border-t border-border/50">
1783
- <div className="flex-1">
1784
- <label className="text-sm font-medium">
1785
- {hookStatus?.installed
1786
- ? t("settings.config.hooks.installed")
1787
- : t("settings.config.hooks.notInstalled")}
1788
- </label>
1789
- <p className="text-xs text-muted-foreground">
1790
- {t("settings.config.hooks.installHint")}
1791
- </p>
1792
- </div>
1793
- <Button
1794
- variant={hookStatus?.installed ? "destructive" : "default"}
1795
- onClick={handleToggleHook}
1796
- disabled={hookLoading || !hookStatus}
1797
- className="rounded-lg"
1798
- >
1799
- {hookStatus?.installed
1800
- ? t("settings.config.hooks.uninstall")
1801
- : t("settings.config.hooks.install")}
1802
- </Button>
1803
- </div>
1804
- </div>
1805
-
1806
- {/* Delete Rule Confirmation Dialog */}
1807
- <Dialog
1808
- open={!!deleteRuleConfirmId}
1809
- onOpenChange={(open) => !open && setDeleteRuleConfirmId(null)}
1810
- >
1811
- <DialogContent>
1812
- <DialogHeader>
1813
- <DialogTitle>
1814
- {t("settings.config.git.deleteConfirm")}
1815
- </DialogTitle>
1816
- <DialogDescription>
1817
- {t("settings.config.git.deleteConfirmMessage")}
1818
- </DialogDescription>
1819
- </DialogHeader>
1820
- <DialogFooter>
1821
- <Button
1822
- variant="outline"
1823
- onClick={() => setDeleteRuleConfirmId(null)}
1824
- >
1825
- {t("settings.config.git.cancel")}
1826
- </Button>
1827
- <Button
1828
- variant="destructive"
1829
- onClick={() =>
1830
- deleteRuleConfirmId && handleDeleteRule(deleteRuleConfirmId)
1831
- }
1832
- >
1833
- {t("settings.config.git.delete")}
1834
- </Button>
1835
- </DialogFooter>
1836
- </DialogContent>
1837
- </Dialog>
1838
- </div>
1839
- );
1840
- }
1841
-
1842
- function renderCliProfile() {
1843
- if (cliLoading) {
1844
- return (
1845
- <div className="flex items-center justify-center py-12">
1846
- <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
1847
- </div>
1848
- );
1849
- }
1850
-
1851
- if (!cliProfile) {
1852
- return (
1853
- <div className="text-sm text-muted-foreground">
1854
- {t("settings.cliProfile.noProfile")}
1855
- </div>
1856
- );
1857
- }
1858
-
1859
- return (
1860
- <div className="space-y-6">
1861
- {/* Command */}
1862
- <div>
1863
- <div className="flex items-center gap-2 mb-2">
1864
- <label className="text-sm font-medium">
1865
- {t("settings.cliProfile.command")}
1866
- </label>
1867
- </div>
1868
- <p className="text-xs text-muted-foreground mb-2">
1869
- {t("settings.cliProfile.commandHint")}
1870
- </p>
1871
- <Input
1872
- type="text"
1873
- value={cliCommand}
1874
- onChange={(e) => setCliCommand(e.target.value)}
1875
- placeholder={t("settings.cliProfile.commandPlaceholder")}
1876
- className="w-full rounded-lg border-border/50 bg-zinc-900 dark:bg-zinc-950 text-cyan-400 font-mono text-sm px-4 py-2.5 focus:ring-2 focus:ring-cyan-500/30 placeholder:text-zinc-600"
1877
- />
1878
- </div>
1879
-
1880
- {/* Base args */}
1881
- <div>
1882
- <div className="flex items-center gap-2 mb-2">
1883
- <label className="text-sm font-medium">
1884
- {t("settings.cliProfile.baseArgs")}
1885
- </label>
1886
- <Badge
1887
- variant="secondary"
1888
- className="text-xs rounded-full px-2 py-0"
1889
- >
1890
- one per line
1891
- </Badge>
1892
- </div>
1893
- <p className="text-xs text-muted-foreground mb-2">
1894
- {t("settings.cliProfile.baseArgsHint")}
1895
- </p>
1896
- <Textarea
1897
- value={cliBaseArgsText}
1898
- onChange={(e) => setCliBaseArgsText(e.target.value)}
1899
- placeholder={t("settings.cliProfile.baseArgsPlaceholder")}
1900
- rows={4}
1901
- className="w-full rounded-lg border-border/50 bg-zinc-900 dark:bg-zinc-950 text-cyan-400 font-mono text-sm px-4 py-3 leading-relaxed focus:ring-2 focus:ring-cyan-500/30 placeholder:text-zinc-600 resize-none"
1902
- />
1903
- </div>
1904
-
1905
- {/* Env vars */}
1906
- <div>
1907
- <div className="flex items-center gap-2 mb-2">
1908
- <label className="text-sm font-medium">
1909
- {t("settings.cliProfile.envVars")}
1910
- </label>
1911
- <Badge
1912
- variant="secondary"
1913
- className="text-xs rounded-full px-2 py-0"
1914
- >
1915
- KEY=VALUE per line
1916
- </Badge>
1917
- </div>
1918
- <p className="text-xs text-muted-foreground mb-2">
1919
- {t("settings.cliProfile.envVarsHint")}
1920
- </p>
1921
- <Textarea
1922
- value={cliEnvVarsText}
1923
- onChange={(e) => setCliEnvVarsText(e.target.value)}
1924
- placeholder={t("settings.cliProfile.envVarsPlaceholder")}
1925
- rows={4}
1926
- className="w-full rounded-lg border-border/50 bg-zinc-900 dark:bg-zinc-950 text-cyan-400 font-mono text-sm px-4 py-3 leading-relaxed focus:ring-2 focus:ring-cyan-500/30 placeholder:text-zinc-600 resize-none"
1927
- />
1928
- </div>
1929
-
1930
- {/* Save button with inline success indicator */}
1931
- <div className="flex items-center gap-3">
1932
- <Button onClick={handleSaveCliProfile} className="rounded-lg">
1933
- <Save className="h-4 w-4 mr-2" />
1934
- {t("common.save")}
1935
- </Button>
1936
- {cliSaveStatus === "saved" && (
1937
- <span className="inline-flex items-center gap-1 text-sm text-emerald-600 dark:text-emerald-400 animate-in fade-in duration-300">
1938
- <Check className="h-4 w-4" />
1939
- {t("settings.cliProfile.saved")}
1940
- </span>
1941
- )}
1942
- {cliSaveStatus === "error" && (
1943
- <span className="inline-flex items-center gap-1 text-sm text-red-600 dark:text-red-400 animate-in fade-in duration-300">
1944
- <XCircle className="h-4 w-4" />
1945
- {t("settings.cliProfile.saveError")}
1946
- </span>
1947
- )}
1948
- </div>
1949
- </div>
1950
- );
1951
- }
1952
-
1953
- function renderNotifications() {
1954
- return (
1955
- <div className="divide-y divide-border/50">
1956
- <div className="flex items-center justify-between py-4">
1957
- <div>
1958
- <div className="text-sm font-medium">
1959
- {t("settings.notifications.enable")}
1960
- </div>
1961
- <div className="text-xs text-muted-foreground mt-0.5">
1962
- {t("settings.notifications.enableDesc")}
1963
- </div>
1964
- </div>
1965
- <Switch
1966
- checked={notifEnabled}
1967
- onCheckedChange={handleToggleNotif}
1968
- />
1969
- </div>
1970
- </div>
1971
- );
1972
- }
1973
-
1974
- // =========================================================================
1975
- // Section router
1976
- // =========================================================================
1977
- function renderSectionContent() {
1978
- switch (activeSection) {
1979
- case "general":
1980
- return renderGeneral();
1981
- case "ai-tools":
1982
- return renderAiTools();
1983
- case "prompts":
1984
- return renderPrompts();
1985
- case "config":
1986
- return renderSystemConfig();
1987
- case "cli-profile":
1988
- return renderCliProfile();
1989
- case "notifications":
1990
- return renderNotifications();
1991
- }
1992
- }
1993
-
1994
- // =========================================================================
1995
- // MAIN RENDER
1996
- // =========================================================================
1997
- return (
1998
- <div className="flex h-full flex-col bg-background">
1999
- {/* Top header bar */}
2000
- <div className="flex-shrink-0 border-b bg-card/50 backdrop-blur-sm">
2001
- <div className="mx-auto max-w-5xl px-6">
2002
- {/* Title row */}
2003
- <div className="flex items-center justify-between pb-3 pt-5">
2004
- <div>
2005
- <h1 className="text-2xl font-bold tracking-tight">
2006
- {t("settings.title")}
2007
- </h1>
2008
- <p className="mt-0.5 text-sm text-muted-foreground">
2009
- {t("settings.configDesc")}
2010
- </p>
2011
- </div>
2012
- <Button
2013
- variant="outline"
2014
- onClick={handleClose}
2015
- className="gap-1.5 bg-card shadow-sm cursor-pointer"
2016
- >
2017
- <X className="h-3.5 w-3.5" />
2018
- ESC
2019
- </Button>
2020
- </div>
2021
-
2022
- {/* Horizontal tab navigation */}
2023
- <div ref={tabsRef} className="relative flex gap-1 overflow-x-auto">
2024
- {SECTIONS.map((section) => {
2025
- const Icon = section.icon;
2026
- const isActive = activeSection === section.id;
2027
- const accent = ACCENT_STYLES[section.accent];
2028
-
2029
- return (
2030
- <button
2031
- key={section.id}
2032
- data-section={section.id}
2033
- onClick={() => setActiveSection(section.id)}
2034
- className={cn(
2035
- "relative flex items-center gap-2 rounded-t-lg px-4 py-2.5",
2036
- "text-sm font-medium whitespace-nowrap cursor-pointer",
2037
- "transition-colors duration-200",
2038
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2039
- isActive
2040
- ? `${accent.text} bg-background`
2041
- : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
2042
- )}
2043
- >
2044
- <span
2045
- className={cn(
2046
- "flex h-6 w-6 items-center justify-center rounded-md",
2047
- "transition-colors duration-200",
2048
- isActive ? accent.bg : "bg-transparent"
2049
- )}
2050
- >
2051
- <Icon className="h-3.5 w-3.5" />
2052
- </span>
2053
- <span>{t(section.labelKey)}</span>
2054
- </button>
2055
- );
2056
- })}
2057
-
2058
- {/* Sliding active indicator */}
2059
- <div
2060
- className={cn(
2061
- "absolute bottom-0 h-0.5 rounded-full",
2062
- "transition-all duration-250 ease-out",
2063
- accentStyle.indicator
2064
- )}
2065
- style={{
2066
- left: indicatorStyle.left,
2067
- width: indicatorStyle.width,
2068
- }}
2069
- />
2070
- </div>
2071
- </div>
2072
- </div>
2073
-
2074
- {/* Scrollable content area */}
2075
- <div className="flex-1 overflow-auto">
2076
- <div className="mx-auto max-w-4xl px-6 py-8">
2077
- {/* Section header with colored icon badge */}
2078
- {activeConfig && (
2079
- <div className="mb-6 flex items-start gap-4">
2080
- <div
2081
- className={cn(
2082
- "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl",
2083
- "ring-1",
2084
- accentStyle.bg,
2085
- accentStyle.text,
2086
- accentStyle.ring
2087
- )}
2088
- >
2089
- <activeConfig.icon className="h-5 w-5" />
2090
- </div>
2091
- <div className="min-w-0">
2092
- <h2 className="text-lg font-semibold leading-tight">
2093
- {t(activeConfig.labelKey)}
2094
- </h2>
2095
- <p className="mt-0.5 text-sm text-muted-foreground">
2096
- {t(activeConfig.descKey)}
2097
- </p>
2098
- </div>
2099
- </div>
2100
- )}
2101
-
2102
- {/* Divider */}
2103
- <div className="mb-6 border-t" />
2104
-
2105
- {/* Config content */}
2106
- {renderSectionContent()}
2107
- </div>
2108
- </div>
2109
- </div>
2110
- );
2111
- }