@seqyuan/annodex 0.1.12 → 0.1.14

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 (478) hide show
  1. package/.next/BUILD_ID +1 -0
  2. package/.next/app-path-routes-manifest.json +39 -0
  3. package/.next/build-manifest.json +20 -0
  4. package/.next/diagnostics/build-diagnostics.json +6 -0
  5. package/.next/diagnostics/framework.json +1 -0
  6. package/.next/export-marker.json +6 -0
  7. package/.next/images-manifest.json +68 -0
  8. package/.next/next-minimal-server.js.nft.json +1 -0
  9. package/.next/next-server.js.nft.json +1 -0
  10. package/.next/package.json +1 -0
  11. package/.next/prerender-manifest.json +109 -0
  12. package/.next/react-loadable-manifest.json +2320 -0
  13. package/.next/required-server-files.js +343 -0
  14. package/.next/required-server-files.json +343 -0
  15. package/.next/routes-manifest.json +286 -0
  16. package/.next/server/app/_global-error/page.js +32 -0
  17. package/.next/server/app/_global-error/page.js.nft.json +1 -0
  18. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -0
  19. package/.next/server/app/_global-error.html +1 -0
  20. package/.next/server/app/_global-error.meta +16 -0
  21. package/.next/server/app/_global-error.rsc +14 -0
  22. package/.next/server/app/_global-error.segments/_full.segment.rsc +14 -0
  23. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +5 -0
  24. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +5 -0
  25. package/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
  26. package/.next/server/app/_global-error.segments/_index.segment.rsc +5 -0
  27. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  28. package/.next/server/app/_not-found/page.js +2 -0
  29. package/.next/server/app/_not-found/page.js.nft.json +1 -0
  30. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  31. package/.next/server/app/_not-found.html +1 -0
  32. package/.next/server/app/_not-found.meta +16 -0
  33. package/.next/server/app/_not-found.rsc +18 -0
  34. package/.next/server/app/_not-found.segments/_full.segment.rsc +18 -0
  35. package/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
  36. package/.next/server/app/_not-found.segments/_index.segment.rsc +5 -0
  37. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
  38. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +5 -0
  39. package/.next/server/app/_not-found.segments/_tree.segment.rsc +4 -0
  40. package/.next/server/app/api/agent/[id]/events/route.js +3 -0
  41. package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -0
  42. package/.next/server/app/api/agent/[id]/events/route_client-reference-manifest.js +1 -0
  43. package/.next/server/app/api/agent/[id]/route.js +1 -0
  44. package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -0
  45. package/.next/server/app/api/agent/[id]/route_client-reference-manifest.js +1 -0
  46. package/.next/server/app/api/agent/new/route.js +1 -0
  47. package/.next/server/app/api/agent/new/route.js.nft.json +1 -0
  48. package/.next/server/app/api/agent/new/route_client-reference-manifest.js +1 -0
  49. package/.next/server/app/api/auth/all-providers/route.js +1 -0
  50. package/.next/server/app/api/auth/all-providers/route.js.nft.json +1 -0
  51. package/.next/server/app/api/auth/all-providers/route_client-reference-manifest.js +1 -0
  52. package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -0
  53. package/.next/server/app/api/auth/api-key/[provider]/route.js.nft.json +1 -0
  54. package/.next/server/app/api/auth/api-key/[provider]/route_client-reference-manifest.js +1 -0
  55. package/.next/server/app/api/auth/login/[provider]/route.js +1 -0
  56. package/.next/server/app/api/auth/login/[provider]/route.js.nft.json +1 -0
  57. package/.next/server/app/api/auth/login/[provider]/route_client-reference-manifest.js +1 -0
  58. package/.next/server/app/api/auth/login/route.js +1 -0
  59. package/.next/server/app/api/auth/login/route.js.nft.json +1 -0
  60. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -0
  61. package/.next/server/app/api/auth/logout/[provider]/route.js +1 -0
  62. package/.next/server/app/api/auth/logout/[provider]/route.js.nft.json +1 -0
  63. package/.next/server/app/api/auth/logout/[provider]/route_client-reference-manifest.js +1 -0
  64. package/.next/server/app/api/auth/providers/route.js +1 -0
  65. package/.next/server/app/api/auth/providers/route.js.nft.json +1 -0
  66. package/.next/server/app/api/auth/providers/route_client-reference-manifest.js +1 -0
  67. package/.next/server/app/api/auth/status/route.js +1 -0
  68. package/.next/server/app/api/auth/status/route.js.nft.json +1 -0
  69. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -0
  70. package/.next/server/app/api/default-cwd/route.js +1 -0
  71. package/.next/server/app/api/default-cwd/route.js.nft.json +1 -0
  72. package/.next/server/app/api/default-cwd/route_client-reference-manifest.js +1 -0
  73. package/.next/server/app/api/files/[...path]/route.js +4 -0
  74. package/.next/server/app/api/files/[...path]/route.js.nft.json +1 -0
  75. package/.next/server/app/api/files/[...path]/route_client-reference-manifest.js +1 -0
  76. package/.next/server/app/api/harness/route.js +1 -0
  77. package/.next/server/app/api/harness/route.js.nft.json +1 -0
  78. package/.next/server/app/api/harness/route_client-reference-manifest.js +1 -0
  79. package/.next/server/app/api/home/route.js +1 -0
  80. package/.next/server/app/api/home/route.js.nft.json +1 -0
  81. package/.next/server/app/api/home/route_client-reference-manifest.js +1 -0
  82. package/.next/server/app/api/internal/runtime/route.js +1 -0
  83. package/.next/server/app/api/internal/runtime/route.js.nft.json +1 -0
  84. package/.next/server/app/api/internal/runtime/route_client-reference-manifest.js +1 -0
  85. package/.next/server/app/api/models/route.js +1 -0
  86. package/.next/server/app/api/models/route.js.nft.json +1 -0
  87. package/.next/server/app/api/models/route_client-reference-manifest.js +1 -0
  88. package/.next/server/app/api/models-config/discover/route.js +1 -0
  89. package/.next/server/app/api/models-config/discover/route.js.nft.json +1 -0
  90. package/.next/server/app/api/models-config/discover/route_client-reference-manifest.js +1 -0
  91. package/.next/server/app/api/models-config/route.js +1 -0
  92. package/.next/server/app/api/models-config/route.js.nft.json +1 -0
  93. package/.next/server/app/api/models-config/route_client-reference-manifest.js +1 -0
  94. package/.next/server/app/api/models-config/test/route.js +1 -0
  95. package/.next/server/app/api/models-config/test/route.js.nft.json +1 -0
  96. package/.next/server/app/api/models-config/test/route_client-reference-manifest.js +1 -0
  97. package/.next/server/app/api/projects/browse/route.js +1 -0
  98. package/.next/server/app/api/projects/browse/route.js.nft.json +1 -0
  99. package/.next/server/app/api/projects/browse/route_client-reference-manifest.js +1 -0
  100. package/.next/server/app/api/projects/route.js +1 -0
  101. package/.next/server/app/api/projects/route.js.nft.json +1 -0
  102. package/.next/server/app/api/projects/route_client-reference-manifest.js +1 -0
  103. package/.next/server/app/api/reports/[id]/route.js +10 -0
  104. package/.next/server/app/api/reports/[id]/route.js.nft.json +1 -0
  105. package/.next/server/app/api/reports/[id]/route_client-reference-manifest.js +1 -0
  106. package/.next/server/app/api/search/route.js +1 -0
  107. package/.next/server/app/api/search/route.js.nft.json +1 -0
  108. package/.next/server/app/api/search/route_client-reference-manifest.js +1 -0
  109. package/.next/server/app/api/sessions/[id]/context/route.js +1 -0
  110. package/.next/server/app/api/sessions/[id]/context/route.js.nft.json +1 -0
  111. package/.next/server/app/api/sessions/[id]/context/route_client-reference-manifest.js +1 -0
  112. package/.next/server/app/api/sessions/[id]/route.js +1 -0
  113. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -0
  114. package/.next/server/app/api/sessions/[id]/route_client-reference-manifest.js +1 -0
  115. package/.next/server/app/api/sessions/new/route.js +1 -0
  116. package/.next/server/app/api/sessions/new/route.js.nft.json +1 -0
  117. package/.next/server/app/api/sessions/new/route_client-reference-manifest.js +1 -0
  118. package/.next/server/app/api/sessions/route.js +1 -0
  119. package/.next/server/app/api/sessions/route.js.nft.json +1 -0
  120. package/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -0
  121. package/.next/server/app/api/settings/route.js +1 -0
  122. package/.next/server/app/api/settings/route.js.nft.json +1 -0
  123. package/.next/server/app/api/settings/route_client-reference-manifest.js +1 -0
  124. package/.next/server/app/api/skills/install/route.js +5 -0
  125. package/.next/server/app/api/skills/install/route.js.nft.json +1 -0
  126. package/.next/server/app/api/skills/install/route_client-reference-manifest.js +1 -0
  127. package/.next/server/app/api/skills/route.js +6 -0
  128. package/.next/server/app/api/skills/route.js.nft.json +1 -0
  129. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -0
  130. package/.next/server/app/api/skills/search/route.js +1 -0
  131. package/.next/server/app/api/skills/search/route.js.nft.json +1 -0
  132. package/.next/server/app/api/skills/search/route_client-reference-manifest.js +1 -0
  133. package/.next/server/app/api/soul/route.js +1 -0
  134. package/.next/server/app/api/soul/route.js.nft.json +1 -0
  135. package/.next/server/app/api/soul/route_client-reference-manifest.js +1 -0
  136. package/.next/server/app/api/version/route.js +1 -0
  137. package/.next/server/app/api/version/route.js.nft.json +1 -0
  138. package/.next/server/app/api/version/route_client-reference-manifest.js +1 -0
  139. package/.next/server/app/index.html +1 -0
  140. package/.next/server/app/index.meta +14 -0
  141. package/.next/server/app/index.rsc +17 -0
  142. package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -0
  143. package/.next/server/app/index.segments/_full.segment.rsc +17 -0
  144. package/.next/server/app/index.segments/_head.segment.rsc +6 -0
  145. package/.next/server/app/index.segments/_index.segment.rsc +5 -0
  146. package/.next/server/app/index.segments/_tree.segment.rsc +4 -0
  147. package/.next/server/app/login/page.js +2 -0
  148. package/.next/server/app/login/page.js.nft.json +1 -0
  149. package/.next/server/app/login/page_client-reference-manifest.js +1 -0
  150. package/.next/server/app/login.html +1 -0
  151. package/.next/server/app/login.meta +15 -0
  152. package/.next/server/app/login.rsc +22 -0
  153. package/.next/server/app/login.segments/_full.segment.rsc +22 -0
  154. package/.next/server/app/login.segments/_head.segment.rsc +6 -0
  155. package/.next/server/app/login.segments/_index.segment.rsc +5 -0
  156. package/.next/server/app/login.segments/_tree.segment.rsc +4 -0
  157. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +9 -0
  158. package/.next/server/app/login.segments/login.segment.rsc +5 -0
  159. package/.next/server/app/page.js +261 -0
  160. package/.next/server/app/page.js.nft.json +1 -0
  161. package/.next/server/app/page_client-reference-manifest.js +1 -0
  162. package/.next/server/app-paths-manifest.json +39 -0
  163. package/.next/server/chunks/1048.js +1 -0
  164. package/.next/server/chunks/1367.js +77 -0
  165. package/.next/server/chunks/1381.js +1 -0
  166. package/.next/server/chunks/165.js +1 -0
  167. package/.next/server/chunks/1681.js +215 -0
  168. package/.next/server/chunks/1688.js +45 -0
  169. package/.next/server/chunks/1703.js +79 -0
  170. package/.next/server/chunks/1712.js +43 -0
  171. package/.next/server/chunks/1813.js +1 -0
  172. package/.next/server/chunks/2325.js +80 -0
  173. package/.next/server/chunks/258.js +1 -0
  174. package/.next/server/chunks/2671.js +287 -0
  175. package/.next/server/chunks/2778.js +1 -0
  176. package/.next/server/chunks/2943.js +1 -0
  177. package/.next/server/chunks/3031.js +226 -0
  178. package/.next/server/chunks/3181.js +1 -0
  179. package/.next/server/chunks/3493.js +1 -0
  180. package/.next/server/chunks/3672.js +1 -0
  181. package/.next/server/chunks/3701.js +104 -0
  182. package/.next/server/chunks/4013.js +1 -0
  183. package/.next/server/chunks/402.js +2 -0
  184. package/.next/server/chunks/4035.js +80 -0
  185. package/.next/server/chunks/4248.js +153 -0
  186. package/.next/server/chunks/4367.js +1 -0
  187. package/.next/server/chunks/4406.js +141 -0
  188. package/.next/server/chunks/4741.js +18 -0
  189. package/.next/server/chunks/4768.js +1 -0
  190. package/.next/server/chunks/4858.js +148 -0
  191. package/.next/server/chunks/4980.js +1 -0
  192. package/.next/server/chunks/5155.js +5 -0
  193. package/.next/server/chunks/5293.js +166 -0
  194. package/.next/server/chunks/5399.js +8 -0
  195. package/.next/server/chunks/5409.js +1 -0
  196. package/.next/server/chunks/5797.js +93 -0
  197. package/.next/server/chunks/5851.js +36 -0
  198. package/.next/server/chunks/6206.js +1 -0
  199. package/.next/server/chunks/6296.js +1 -0
  200. package/.next/server/chunks/63.js +45 -0
  201. package/.next/server/chunks/6346.js +1 -0
  202. package/.next/server/chunks/6406.js +23 -0
  203. package/.next/server/chunks/642.js +1 -0
  204. package/.next/server/chunks/6429.js +50 -0
  205. package/.next/server/chunks/6729.js +64 -0
  206. package/.next/server/chunks/6907.js +115 -0
  207. package/.next/server/chunks/6980.js +1 -0
  208. package/.next/server/chunks/7073.js +24 -0
  209. package/.next/server/chunks/7233.js +24 -0
  210. package/.next/server/chunks/7307.js +1 -0
  211. package/.next/server/chunks/7362.js +9 -0
  212. package/.next/server/chunks/7567.js +29 -0
  213. package/.next/server/chunks/7765.js +1 -0
  214. package/.next/server/chunks/7890.js +1 -0
  215. package/.next/server/chunks/8065.js +1 -0
  216. package/.next/server/chunks/8238.js +34 -0
  217. package/.next/server/chunks/8276.js +1 -0
  218. package/.next/server/chunks/8336.js +1 -0
  219. package/.next/server/chunks/8477.js +3 -0
  220. package/.next/server/chunks/8490.js +1 -0
  221. package/.next/server/chunks/8916.js +1 -0
  222. package/.next/server/chunks/9280.js +252 -0
  223. package/.next/server/chunks/9315.js +1 -0
  224. package/.next/server/chunks/9537.js +90 -0
  225. package/.next/server/chunks/966.js +1 -0
  226. package/.next/server/chunks/9818.js +21 -0
  227. package/.next/server/chunks/static/media/pdf.worker.min.c476e1a0.mjs +6 -0
  228. package/.next/server/functions-config-manifest.json +16 -0
  229. package/.next/server/interception-route-rewrite-manifest.js +1 -0
  230. package/.next/server/middleware-build-manifest.js +1 -0
  231. package/.next/server/middleware-manifest.json +6 -0
  232. package/.next/server/middleware-react-loadable-manifest.js +1 -0
  233. package/.next/server/middleware.js +18 -0
  234. package/.next/server/middleware.js.nft.json +1 -0
  235. package/.next/server/next-font-manifest.js +1 -0
  236. package/.next/server/next-font-manifest.json +1 -0
  237. package/.next/server/pages/404.html +1 -0
  238. package/.next/server/pages/500.html +1 -0
  239. package/.next/server/pages-manifest.json +4 -0
  240. package/.next/server/prefetch-hints.json +1 -0
  241. package/.next/server/server-reference-manifest.js +1 -0
  242. package/.next/server/server-reference-manifest.json +1 -0
  243. package/.next/server/webpack-runtime.js +1 -0
  244. package/.next/static/9tDQsVwah2dRfj3LNFKBR/_buildManifest.js +1 -0
  245. package/.next/static/9tDQsVwah2dRfj3LNFKBR/_ssgManifest.js +1 -0
  246. package/.next/static/chunks/0b9a0da7.9075af772487e743.js +62 -0
  247. package/.next/static/chunks/1413.922d232de90c0c41.js +115 -0
  248. package/.next/static/chunks/1643.467a526a1f24f54d.js +24 -0
  249. package/.next/static/chunks/1852.5543122f11aa7fed.js +1 -0
  250. package/.next/static/chunks/1960.b1e26436d7a5f586.js +1 -0
  251. package/.next/static/chunks/2170a4aa.4213bb2183c9cdf9.js +1 -0
  252. package/.next/static/chunks/2274.6cd173f80a1405a2.js +21 -0
  253. package/.next/static/chunks/2419.347fdfe3c170854d.js +166 -0
  254. package/.next/static/chunks/2619.9aac8983f30c7c8a.js +1 -0
  255. package/.next/static/chunks/2623.d20fabd8e18197c6.js +287 -0
  256. package/.next/static/chunks/2729.f5365061a849d659.js +34 -0
  257. package/.next/static/chunks/2821.934bcf60fbdc28c6.js +1 -0
  258. package/.next/static/chunks/2918becc.abff2ece1de37bc1.js +153 -0
  259. package/.next/static/chunks/2947.114e51cb06d1c01a.js +23 -0
  260. package/.next/static/chunks/3079.4c511fa1144e3adf.js +79 -0
  261. package/.next/static/chunks/3274.208ca44844cd7d95.js +148 -0
  262. package/.next/static/chunks/3308.465a94263d04bfea.js +73 -0
  263. package/.next/static/chunks/3325.e4bfe1ca657f3b5b.js +80 -0
  264. package/.next/static/chunks/3506.2a7eaa08b9f55337.js +90 -0
  265. package/.next/static/chunks/363642f4-043c1475ab9af70e.js +1 -0
  266. package/.next/static/chunks/3794-123fdf632563f469.js +32 -0
  267. package/.next/static/chunks/3837.a755ccfe6f9c1c1c.js +5 -0
  268. package/.next/static/chunks/394.91597771688df6d0.js +1 -0
  269. package/.next/static/chunks/3997.1009c06025691712.js +1 -0
  270. package/.next/static/chunks/4453.91a357dc43c21745.js +1 -0
  271. package/.next/static/chunks/4491.44fdf20580ac72bd.js +24 -0
  272. package/.next/static/chunks/4829.cf1d50e43e6d9db5.js +1 -0
  273. package/.next/static/chunks/498.fe1d9da9ecad6c36.js +1 -0
  274. package/.next/static/chunks/4bd1b696-e356ca5ba0218e27.js +1 -0
  275. package/.next/static/chunks/5019.b5a1a2b8daf17525.js +1 -0
  276. package/.next/static/chunks/5034.8f16c3fa3ce75411.js +1 -0
  277. package/.next/static/chunks/5074.d16651da01ec4e02.js +1 -0
  278. package/.next/static/chunks/51fb665c.0950e1b79671348d.js +45 -0
  279. package/.next/static/chunks/532.5956ed631aff722b.js +9 -0
  280. package/.next/static/chunks/5326.69460442bdcd6cd3.js +1 -0
  281. package/.next/static/chunks/5403.ff110bf5bf600758.js +64 -0
  282. package/.next/static/chunks/547.902a733488cfe3f7.js +77 -0
  283. package/.next/static/chunks/5567.540d7fc108ad6ee5.js +215 -0
  284. package/.next/static/chunks/5590.ef62922166d308b4.js +1 -0
  285. package/.next/static/chunks/5690.9d6eb1edb1399995.js +1 -0
  286. package/.next/static/chunks/5749.25faee4a1e55b854.js +226 -0
  287. package/.next/static/chunks/58bb9007.1ccb6bba34b4c635.js +80 -0
  288. package/.next/static/chunks/6121.f3f43f1896ea0cd9.js +1 -0
  289. package/.next/static/chunks/6600.583c88eef37aa524.js +1 -0
  290. package/.next/static/chunks/6696.a41aec266e657d54.js +141 -0
  291. package/.next/static/chunks/6922.42148793782d2fe7.js +1 -0
  292. package/.next/static/chunks/7006.e191611ffc2b9528.js +43 -0
  293. package/.next/static/chunks/7343.9fbb58204d8ac681.js +1 -0
  294. package/.next/static/chunks/73972abe.25a4cffa03b2bcef.js +119 -0
  295. package/.next/static/chunks/7547.58bda8a2aabba0d4.js +93 -0
  296. package/.next/static/chunks/7648.4ae2f183b4db0353.js +1 -0
  297. package/.next/static/chunks/7874.8db6929b94cdf697.js +1 -0
  298. package/.next/static/chunks/7959.1f20a35df316216a.js +104 -0
  299. package/.next/static/chunks/83.85d62d7fc9850b75.js +29 -0
  300. package/.next/static/chunks/8436.cab94b59cca0a8ff.js +1 -0
  301. package/.next/static/chunks/8451.ff6ff72b57dc52e1.js +1 -0
  302. package/.next/static/chunks/8489.45f22859734f514f.js +36 -0
  303. package/.next/static/chunks/8568.f85d8b36fc9a9037.js +1 -0
  304. package/.next/static/chunks/8771-3e14b6810486df1f.js +1 -0
  305. package/.next/static/chunks/8863.be51033a67436277.js +1 -0
  306. package/.next/static/chunks/90542734.dc1a2723e4f6affb.js +1 -0
  307. package/.next/static/chunks/9500.1488aec06ee78127.js +1 -0
  308. package/.next/static/chunks/9633.155548b5fca6e580.js +1 -0
  309. package/.next/static/chunks/9779.673004a62d70e36a.js +1 -0
  310. package/.next/static/chunks/app/_global-error/page-cc518af6b1ffb191.js +1 -0
  311. package/.next/static/chunks/app/_not-found/page-c72daab99269beff.js +1 -0
  312. package/.next/static/chunks/app/api/agent/[id]/events/route-cc518af6b1ffb191.js +1 -0
  313. package/.next/static/chunks/app/api/agent/[id]/route-cc518af6b1ffb191.js +1 -0
  314. package/.next/static/chunks/app/api/agent/new/route-cc518af6b1ffb191.js +1 -0
  315. package/.next/static/chunks/app/api/auth/all-providers/route-cc518af6b1ffb191.js +1 -0
  316. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-cc518af6b1ffb191.js +1 -0
  317. package/.next/static/chunks/app/api/auth/login/[provider]/route-cc518af6b1ffb191.js +1 -0
  318. package/.next/static/chunks/app/api/auth/login/route-cc518af6b1ffb191.js +1 -0
  319. package/.next/static/chunks/app/api/auth/logout/[provider]/route-cc518af6b1ffb191.js +1 -0
  320. package/.next/static/chunks/app/api/auth/providers/route-cc518af6b1ffb191.js +1 -0
  321. package/.next/static/chunks/app/api/auth/status/route-cc518af6b1ffb191.js +1 -0
  322. package/.next/static/chunks/app/api/default-cwd/route-cc518af6b1ffb191.js +1 -0
  323. package/.next/static/chunks/app/api/files/[...path]/route-cc518af6b1ffb191.js +1 -0
  324. package/.next/static/chunks/app/api/harness/route-cc518af6b1ffb191.js +1 -0
  325. package/.next/static/chunks/app/api/home/route-cc518af6b1ffb191.js +1 -0
  326. package/.next/static/chunks/app/api/internal/runtime/route-cc518af6b1ffb191.js +1 -0
  327. package/.next/static/chunks/app/api/models/route-cc518af6b1ffb191.js +1 -0
  328. package/.next/static/chunks/app/api/models-config/discover/route-cc518af6b1ffb191.js +1 -0
  329. package/.next/static/chunks/app/api/models-config/route-cc518af6b1ffb191.js +1 -0
  330. package/.next/static/chunks/app/api/models-config/test/route-cc518af6b1ffb191.js +1 -0
  331. package/.next/static/chunks/app/api/projects/browse/route-cc518af6b1ffb191.js +1 -0
  332. package/.next/static/chunks/app/api/projects/route-cc518af6b1ffb191.js +1 -0
  333. package/.next/static/chunks/app/api/reports/[id]/route-cc518af6b1ffb191.js +1 -0
  334. package/.next/static/chunks/app/api/search/route-cc518af6b1ffb191.js +1 -0
  335. package/.next/static/chunks/app/api/sessions/[id]/context/route-cc518af6b1ffb191.js +1 -0
  336. package/.next/static/chunks/app/api/sessions/[id]/route-cc518af6b1ffb191.js +1 -0
  337. package/.next/static/chunks/app/api/sessions/new/route-cc518af6b1ffb191.js +1 -0
  338. package/.next/static/chunks/app/api/sessions/route-cc518af6b1ffb191.js +1 -0
  339. package/.next/static/chunks/app/api/settings/route-cc518af6b1ffb191.js +1 -0
  340. package/.next/static/chunks/app/api/skills/install/route-cc518af6b1ffb191.js +1 -0
  341. package/.next/static/chunks/app/api/skills/route-cc518af6b1ffb191.js +1 -0
  342. package/.next/static/chunks/app/api/skills/search/route-cc518af6b1ffb191.js +1 -0
  343. package/.next/static/chunks/app/api/soul/route-cc518af6b1ffb191.js +1 -0
  344. package/.next/static/chunks/app/api/version/route-cc518af6b1ffb191.js +1 -0
  345. package/.next/static/chunks/app/layout-be148b7ae915b22a.js +1 -0
  346. package/.next/static/chunks/app/login/page-ebf0e6de99062783.js +1 -0
  347. package/.next/static/chunks/app/page-a26fde41f0bbe84c.js +260 -0
  348. package/.next/static/chunks/d3ac728e.7964f816a1ca64e5.js +1 -0
  349. package/.next/static/chunks/framework-711ef29bc66f648c.js +1 -0
  350. package/.next/static/chunks/main-app-45a0f19af99d61b6.js +1 -0
  351. package/.next/static/chunks/main-f74964b7ae52493e.js +5 -0
  352. package/.next/static/chunks/next/dist/client/components/builtin/app-error-cc518af6b1ffb191.js +1 -0
  353. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-cc518af6b1ffb191.js +1 -0
  354. package/.next/static/chunks/next/dist/client/components/builtin/global-error-9bfa08b9491621f2.js +1 -0
  355. package/.next/static/chunks/next/dist/client/components/builtin/not-found-cc518af6b1ffb191.js +1 -0
  356. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-cc518af6b1ffb191.js +1 -0
  357. package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  358. package/.next/static/chunks/webpack-fcf4a889ecbd753c.js +1 -0
  359. package/.next/static/css/45029451a1d7255d.css +3 -0
  360. package/.next/static/media/15605e25b523335c-s.woff2 +0 -0
  361. package/.next/static/media/1a3dce5cfb5f7760-s.woff2 +0 -0
  362. package/.next/static/media/1cdd02902f937a18-s.woff2 +0 -0
  363. package/.next/static/media/4c4b3b30b6bcb2be-s.woff2 +0 -0
  364. package/.next/static/media/641a7b8a5800ee0e-s.woff2 +0 -0
  365. package/.next/static/media/7deddc85b7ffd1dc-s.p.woff2 +0 -0
  366. package/.next/static/media/ec14413c594b3356-s.p.woff2 +0 -0
  367. package/.next/static/media/pdf.worker.min.29aaf158.mjs +6 -0
  368. package/package.json +21 -21
  369. package/app/api/agent/[id]/events/route.ts +0 -94
  370. package/app/api/agent/[id]/route.ts +0 -83
  371. package/app/api/agent/new/route.ts +0 -53
  372. package/app/api/auth/all-providers/route.ts +0 -21
  373. package/app/api/auth/api-key/[provider]/route.ts +0 -7
  374. package/app/api/auth/login/[provider]/route.ts +0 -7
  375. package/app/api/auth/login/route.ts +0 -22
  376. package/app/api/auth/logout/[provider]/route.ts +0 -7
  377. package/app/api/auth/providers/route.ts +0 -15
  378. package/app/api/auth/status/route.ts +0 -6
  379. package/app/api/default-cwd/route.ts +0 -22
  380. package/app/api/files/[...path]/route.ts +0 -621
  381. package/app/api/harness/route.ts +0 -47
  382. package/app/api/home/route.ts +0 -6
  383. package/app/api/internal/runtime/route.ts +0 -26
  384. package/app/api/models/route.ts +0 -67
  385. package/app/api/models-config/discover/route.ts +0 -42
  386. package/app/api/models-config/route.ts +0 -152
  387. package/app/api/models-config/test/route.ts +0 -154
  388. package/app/api/projects/browse/route.ts +0 -51
  389. package/app/api/projects/route.ts +0 -83
  390. package/app/api/reports/[id]/route.ts +0 -108
  391. package/app/api/search/route.ts +0 -122
  392. package/app/api/sessions/[id]/context/route.ts +0 -23
  393. package/app/api/sessions/[id]/route.ts +0 -124
  394. package/app/api/sessions/new/route.ts +0 -5
  395. package/app/api/sessions/route.ts +0 -16
  396. package/app/api/settings/route.ts +0 -51
  397. package/app/api/skills/install/route.ts +0 -249
  398. package/app/api/skills/route.ts +0 -161
  399. package/app/api/skills/search/route.ts +0 -121
  400. package/app/api/soul/route.ts +0 -47
  401. package/app/api/version/route.ts +0 -55
  402. package/app/globals.css +0 -736
  403. package/app/layout.tsx +0 -40
  404. package/app/login/page.tsx +0 -133
  405. package/app/page.tsx +0 -10
  406. package/components/AppShell.tsx +0 -1058
  407. package/components/ChatInput.tsx +0 -1103
  408. package/components/ChatMinimap.tsx +0 -381
  409. package/components/ChatWindow.tsx +0 -576
  410. package/components/CodeMirrorEditor.tsx +0 -137
  411. package/components/ConversationSearch.tsx +0 -369
  412. package/components/DataTableViewer.tsx +0 -248
  413. package/components/FileExplorer.tsx +0 -758
  414. package/components/FileIcons.tsx +0 -241
  415. package/components/FileViewer.tsx +0 -1273
  416. package/components/GlobalFileEditor.tsx +0 -98
  417. package/components/MarkdownRenderer.tsx +0 -331
  418. package/components/MermaidDiagram.tsx +0 -80
  419. package/components/MessageView.tsx +0 -1141
  420. package/components/ModelsConfig.tsx +0 -1991
  421. package/components/ProjectContext.tsx +0 -252
  422. package/components/ProjectFolderPicker.tsx +0 -202
  423. package/components/ProjectsConfig.tsx +0 -288
  424. package/components/ProviderIcons.tsx +0 -91
  425. package/components/ReportPanel.tsx +0 -237
  426. package/components/ResizeHandle.tsx +0 -105
  427. package/components/SessionSidebar.tsx +0 -1464
  428. package/components/SettingsDialog.tsx +0 -287
  429. package/components/SkillsConfig.tsx +0 -1093
  430. package/components/SubagentPanel.tsx +0 -191
  431. package/components/TabBar.tsx +0 -115
  432. package/components/ToolPanel.tsx +0 -131
  433. package/components/WidgetRenderer.tsx +0 -505
  434. package/components/viewers/DocumentToolbar.tsx +0 -78
  435. package/components/viewers/DocxViewer.tsx +0 -97
  436. package/components/viewers/PdfViewer.tsx +0 -206
  437. package/components/viewers/PptxViewer.tsx +0 -240
  438. package/components/viewers/XlsxViewer.tsx +0 -143
  439. package/hooks/useAgentSession.ts +0 -710
  440. package/hooks/useAudio.ts +0 -50
  441. package/hooks/useDragDrop.ts +0 -52
  442. package/hooks/useResizable.ts +0 -60
  443. package/hooks/useTheme.ts +0 -85
  444. package/lib/agent-client.ts +0 -39
  445. package/lib/annodex-config.ts +0 -556
  446. package/lib/auth-token.ts +0 -74
  447. package/lib/auth.ts +0 -90
  448. package/lib/brand.ts +0 -5
  449. package/lib/code-theme.ts +0 -32
  450. package/lib/codex-compat-proxy.ts +0 -1603
  451. package/lib/codex-home.ts +0 -6
  452. package/lib/codex-server.ts +0 -796
  453. package/lib/codex-session.ts +0 -590
  454. package/lib/codex-usage.ts +0 -213
  455. package/lib/file-paths.ts +0 -34
  456. package/lib/model-discovery.ts +0 -379
  457. package/lib/normalize.ts +0 -30
  458. package/lib/npx.ts +0 -87
  459. package/lib/pi-types.ts +0 -49
  460. package/lib/projects.ts +0 -269
  461. package/lib/provider-api.ts +0 -88
  462. package/lib/report-prompt.ts +0 -61
  463. package/lib/report-store.ts +0 -597
  464. package/lib/report-update-parser.ts +0 -66
  465. package/lib/rpc-manager.ts +0 -668
  466. package/lib/runtime-state.ts +0 -117
  467. package/lib/session-reader.ts +0 -903
  468. package/lib/session-runtime.ts +0 -105
  469. package/lib/subagent-progress.ts +0 -279
  470. package/lib/types.ts +0 -241
  471. package/lib/widget-export.ts +0 -318
  472. package/lib/widget-guidelines.ts +0 -288
  473. package/lib/widget-prompt.ts +0 -76
  474. package/lib/widget-utils.ts +0 -523
  475. package/postcss.config.mjs +0 -8
  476. package/proxy.ts +0 -64
  477. package/scripts/postinstall.cjs +0 -25
  478. package/tsconfig.json +0 -41
@@ -1,1058 +0,0 @@
1
- "use client";
2
-
3
- import { useState, useCallback, useRef, useEffect } from "react";
4
- import { useRouter, useSearchParams } from "next/navigation";
5
- import { SessionSidebar } from "./SessionSidebar";
6
- import { ChatWindow } from "./ChatWindow";
7
- import { FileViewer } from "./FileViewer";
8
- import { GlobalFileEditor } from "./GlobalFileEditor";
9
- import { ReportPanel } from "./ReportPanel";
10
- import { ResizeHandle } from "./ResizeHandle";
11
- import { TabBar, type Tab } from "./TabBar";
12
- import { SettingsDialog, type SettingsTab } from "./SettingsDialog";
13
- import { useTheme } from "@/hooks/useTheme";
14
- import { useResizable } from "@/hooks/useResizable";
15
- import type { SessionInfo } from "@/lib/types";
16
- import type { ChatInputHandle } from "./ChatInput";
17
-
18
- interface AppSettings {
19
- generativeUI: boolean;
20
- }
21
-
22
- interface RuntimeState {
23
- running: boolean;
24
- status: "running" | "orphaned" | "stopped";
25
- version: string | null;
26
- url: string | null;
27
- restartPending: boolean;
28
- installedVersion: string | null;
29
- restartDetectedAt: string | null;
30
- restartStartedAt: string | null;
31
- }
32
-
33
- interface VersionStatus {
34
- current: string;
35
- latest: string | null;
36
- updateAvailable: boolean;
37
- updateCommand: string;
38
- runtime: RuntimeState | null;
39
- }
40
-
41
- export function AppShell() {
42
- const router = useRouter();
43
- const searchParams = useSearchParams();
44
- const { isDark, toggleTheme } = useTheme();
45
- const [selectedSession, setSelectedSession] = useState<SessionInfo | null>(null);
46
- // When user clicks +, we only store the cwd — no fake session id
47
- const [newSessionCwd, setNewSessionCwd] = useState<string | null>(null);
48
- const [refreshKey, setRefreshKey] = useState(0);
49
- const [sessionKey, setSessionKey] = useState(0);
50
- const [explorerRefreshKey, setExplorerRefreshKey] = useState(0);
51
- const [modelsRefreshKey, setModelsRefreshKey] = useState(0);
52
- const [settingsOpen, setSettingsOpen] = useState(false);
53
- const [settingsInitialTab, setSettingsInitialTab] = useState<SettingsTab>("projects");
54
- const [settings, setSettings] = useState<AppSettings>({ generativeUI: true });
55
- const [versionStatus, setVersionStatus] = useState<VersionStatus | null>(null);
56
- const [sidebarOpen, setSidebarOpen] = useState(true);
57
-
58
- // Resizable panels
59
- const sidebarResize = useResizable({ initialWidth: 260, minWidth: 180, maxWidth: 500, storageKey: "--annodex-sidebar-width" });
60
- const rightPanelResize = useResizable({ initialWidth: 500, minWidth: 300, maxWidth: 1200, storageKey: "--annodex-right-panel-width", direction: "left" });
61
- const chatInputRef = useRef<ChatInputHandle | null>(null);
62
- const topBarRef = useRef<HTMLDivElement>(null);
63
-
64
- const [systemPrompt, setSystemPrompt] = useState<string | null>(null);
65
- const systemBtnRef = useRef<HTMLButtonElement>(null);
66
- const [editingTitle, setEditingTitle] = useState(false);
67
- const [titleDraft, setTitleDraft] = useState("");
68
- const titleInputRef = useRef<HTMLInputElement>(null);
69
- const titleEditCanceledRef = useRef(false);
70
-
71
- const handleSystemPromptChange = useCallback((prompt: string | null) => {
72
- setSystemPrompt(prompt);
73
- }, []);
74
-
75
- useEffect(() => {
76
- setEditingTitle(false);
77
- }, [selectedSession?.id]);
78
-
79
- const getSessionTitle = useCallback((session: SessionInfo | null) => {
80
- if (!session) return "";
81
- return session.name || session.firstMessage.slice(0, 80) || session.id.slice(0, 12);
82
- }, []);
83
-
84
- const handleStartTitleEdit = useCallback(() => {
85
- if (!selectedSession) return;
86
- titleEditCanceledRef.current = false;
87
- setTitleDraft(selectedSession.name || getSessionTitle(selectedSession));
88
- setEditingTitle(true);
89
- setTimeout(() => titleInputRef.current?.select(), 0);
90
- }, [getSessionTitle, selectedSession]);
91
-
92
- const handleSaveTitle = useCallback(async () => {
93
- if (titleEditCanceledRef.current) {
94
- titleEditCanceledRef.current = false;
95
- setEditingTitle(false);
96
- return;
97
- }
98
- if (!selectedSession) {
99
- setEditingTitle(false);
100
- return;
101
- }
102
- const name = titleDraft.trim();
103
- const fallbackTitle = getSessionTitle(selectedSession);
104
- setEditingTitle(false);
105
- if (name === (selectedSession.name ?? "") || (!selectedSession.name && name === fallbackTitle)) return;
106
- try {
107
- const res = await fetch(`/api/sessions/${encodeURIComponent(selectedSession.id)}`, {
108
- method: "PATCH",
109
- headers: { "Content-Type": "application/json" },
110
- body: JSON.stringify({ name }),
111
- });
112
- if (res.ok) {
113
- setSelectedSession((prev) => prev && prev.id === selectedSession.id ? { ...prev, name } : prev);
114
- setRefreshKey((k) => k + 1);
115
- }
116
- } catch {
117
- // keep the local title unchanged if saving fails
118
- }
119
- }, [getSessionTitle, selectedSession, titleDraft]);
120
-
121
- const handleTitleKeyDown = useCallback((event: React.KeyboardEvent<HTMLInputElement>) => {
122
- if (event.key === "Enter") {
123
- event.preventDefault();
124
- void handleSaveTitle();
125
- } else if (event.key === "Escape") {
126
- titleEditCanceledRef.current = true;
127
- setEditingTitle(false);
128
- }
129
- }, [handleSaveTitle]);
130
-
131
- useEffect(() => {
132
- let cancelled = false;
133
- fetch("/api/settings")
134
- .then((res) => res.ok ? res.json() : null)
135
- .then((data: { settings?: Partial<AppSettings> } | null) => {
136
- if (cancelled) return;
137
- setSettings((cur) => ({
138
- generativeUI: typeof data?.settings?.generativeUI === "boolean" ? data.settings.generativeUI : cur.generativeUI,
139
- }));
140
- })
141
- .catch(() => {});
142
- return () => { cancelled = true; };
143
- }, []);
144
-
145
- useEffect(() => {
146
- let cancelled = false;
147
- let inFlight = false;
148
- const load = () => {
149
- if (inFlight) return;
150
- inFlight = true;
151
- fetch("/api/version")
152
- .then((res) => res.ok ? res.json() : null)
153
- .then((data: VersionStatus | null) => {
154
- if (!cancelled) setVersionStatus(data);
155
- })
156
- .catch(() => {})
157
- .finally(() => { inFlight = false; });
158
- };
159
- load();
160
- const timer = window.setInterval(load, 60_000);
161
- return () => {
162
- cancelled = true;
163
- window.clearInterval(timer);
164
- };
165
- }, []);
166
-
167
- const handleGenerativeUIToggle = useCallback(() => {
168
- const next = !settings.generativeUI;
169
- setSettings((cur) => ({ ...cur, generativeUI: next }));
170
- fetch("/api/settings", {
171
- method: "PUT",
172
- headers: { "Content-Type": "application/json" },
173
- body: JSON.stringify({ settings: { generativeUI: next } }),
174
- })
175
- .then((res) => res.ok ? res.json() : Promise.reject(new Error(`HTTP ${res.status}`)))
176
- .then((data: { settings?: Partial<AppSettings> }) => {
177
- setSettings((cur) => ({
178
- ...cur,
179
- ...(typeof data.settings?.generativeUI === "boolean" ? { generativeUI: data.settings.generativeUI } : {}),
180
- }));
181
- })
182
- .catch(() => setSettings((cur) => ({ ...cur, generativeUI: !cur.generativeUI })));
183
- }, [settings.generativeUI]);
184
-
185
- // Session stats (tokens + cost) — populated by ChatWindow, displayed in top bar
186
- const [sessionStats, setSessionStats] = useState<{ tokens: { input: number; output: number; cacheRead: number; cacheWrite: number }; cost?: number } | null>(null);
187
- const handleSessionStatsChange = useCallback((stats: { tokens: { input: number; output: number; cacheRead: number; cacheWrite: number }; cost?: number } | null) => {
188
- setSessionStats(stats);
189
- }, []);
190
-
191
- // Context usage — populated by ChatWindow, displayed in top bar
192
- const [contextUsage, setContextUsage] = useState<{ percent: number | null; contextWindow: number; tokens: number | null } | null>(null);
193
- const handleContextUsageChange = useCallback((usage: { percent: number | null; contextWindow: number; tokens: number | null } | null) => {
194
- setContextUsage(usage);
195
- }, []);
196
-
197
- // Top-bar system prompt dropdown
198
- const [activeTopPanel, setActiveTopPanel] = useState<"system" | null>(null);
199
- const [topPanelPos, setTopPanelPos] = useState<{ top: number; left: number; width: number } | null>(null);
200
-
201
- const toggleTopPanel = useCallback((panel: "system") => {
202
- setActiveTopPanel((cur) => cur === panel ? null : panel);
203
- }, []);
204
-
205
- useEffect(() => {
206
- if (!activeTopPanel || !topBarRef.current) return;
207
- const update = () => {
208
- const rect = topBarRef.current!.getBoundingClientRect();
209
- setTopPanelPos({ top: rect.bottom, left: rect.left, width: rect.width });
210
- };
211
- update();
212
- const ro = new ResizeObserver(update);
213
- ro.observe(topBarRef.current);
214
- return () => ro.disconnect();
215
- }, [activeTopPanel]);
216
-
217
- // Single active panel — only one dropdown open at a time
218
- // Right panel — pinned report tab plus file tabs
219
- const [fileTabs, setFileTabs] = useState<Tab[]>([]);
220
- const [activeRightTabId, setActiveRightTabId] = useState<string>("report");
221
- const [rightPanelOpen, setRightPanelOpen] = useState(false);
222
- const [reportRefreshKey, setReportRefreshKey] = useState(0);
223
-
224
- const handleAtMention = useCallback((relativePath: string) => {
225
- chatInputRef.current?.insertText("`" + relativePath + "`");
226
- }, []);
227
-
228
- const [initialSessionId] = useState<string | null>(() => searchParams.get("session"));
229
- const [activeCwd, setActiveCwd] = useState<string | null>(null);
230
- // True once the initial ?session= URL param has been resolved (or confirmed absent)
231
- const [initialSessionRestored, setInitialSessionRestored] = useState<boolean>(() => !searchParams.get("session"));
232
- // Suppresses sessionKey bump in handleCwdChange during the initial URL restore
233
- const suppressCwdBumpRef = useRef(false);
234
-
235
- const handleCwdChange = useCallback((cwd: string | null) => {
236
- setActiveCwd(cwd);
237
- // Skip if cwd is null (initial mount) or during the initial URL restore.
238
- if (!cwd || suppressCwdBumpRef.current) return;
239
- // Close any session that belongs to a different cwd — it no longer
240
- // matches the selected project directory.
241
- setSelectedSession((prev) => {
242
- if (prev && prev.cwd !== cwd) return null;
243
- return prev;
244
- });
245
- setNewSessionCwd((prev) => {
246
- if (prev && prev !== cwd) return null;
247
- return prev;
248
- });
249
- setSessionKey((k) => k + 1);
250
- setExplorerRefreshKey((k) => k + 1);
251
- setSystemPrompt(null);
252
- setActiveTopPanel(null);
253
- router.replace("/", { scroll: false });
254
- }, [router]);
255
-
256
- const handleProjectSelect = useCallback((cwd: string) => {
257
- handleCwdChange(cwd);
258
- setSettingsOpen(false);
259
- setRefreshKey((k) => k + 1);
260
- }, [handleCwdChange]);
261
-
262
- const handleSelectSession = useCallback((session: SessionInfo, isRestore = false) => {
263
- setNewSessionCwd(null);
264
- setActiveCwd(session.cwd);
265
- setSelectedSession(session);
266
- setSessionKey((k) => k + 1);
267
- setSystemPrompt(null);
268
- setInitialSessionRestored(true);
269
- if (isRestore) {
270
- // Suppress the redundant sessionKey bump that would come from the
271
- // onCwdChange effect firing after setSelectedCwd in the sidebar
272
- suppressCwdBumpRef.current = true;
273
- setTimeout(() => { suppressCwdBumpRef.current = false; }, 0);
274
- }
275
- // Skip router.replace when restoring from URL — the param is already correct
276
- // and calling replace in production Next.js triggers a Suspense remount loop
277
- if (!isRestore) {
278
- router.replace(`?session=${encodeURIComponent(session.id)}`, { scroll: false });
279
- }
280
- }, [router]);
281
-
282
- const handleNewSession = useCallback((_sessionId: string, cwd: string) => {
283
- setSelectedSession(null);
284
- setNewSessionCwd(cwd);
285
- setActiveCwd(cwd);
286
- setSessionKey((k) => k + 1);
287
- setSystemPrompt(null);
288
- setActiveTopPanel(null);
289
- router.replace("/", { scroll: false });
290
- }, [router]);
291
-
292
- // Called by ChatWindow when a new session gets its real id
293
- const handleSessionCreated = useCallback((session: SessionInfo) => {
294
- setNewSessionCwd(null);
295
- setActiveCwd(session.cwd);
296
- setSelectedSession(session);
297
- setRefreshKey((k) => k + 1);
298
- router.replace(`?session=${encodeURIComponent(session.id)}`, { scroll: false });
299
- }, [router]);
300
-
301
- const handleAgentEnd = useCallback(() => {
302
- setRefreshKey((k) => k + 1);
303
- setExplorerRefreshKey((k) => k + 1);
304
- }, []);
305
-
306
- const handleSessionForked = useCallback((newSessionId: string) => {
307
- setRefreshKey((k) => k + 1);
308
- setNewSessionCwd(null);
309
- setSelectedSession((prev) => ({
310
- ...(prev ?? { path: "", cwd: "", created: "", modified: "", messageCount: 0, firstMessage: "" }),
311
- id: newSessionId,
312
- }));
313
- router.replace(`?session=${encodeURIComponent(newSessionId)}`, { scroll: false });
314
- }, [router]);
315
-
316
- const handleInitialRestoreDone = useCallback(() => {
317
- setInitialSessionRestored(true);
318
- }, []);
319
-
320
- const handleSessionDeleted = useCallback((sessionId: string) => {
321
- setRefreshKey((k) => k + 1);
322
- if (selectedSession?.id === sessionId) {
323
- const cwd = selectedSession.cwd;
324
- setSelectedSession(null);
325
- setNewSessionCwd(cwd ?? null);
326
- setSessionKey((k) => k + 1);
327
- setSystemPrompt(null);
328
- setActiveTopPanel(null);
329
- router.replace("/", { scroll: false });
330
- }
331
- }, [selectedSession, router]);
332
-
333
- const handleOpenFile = useCallback((filePath: string, fileName: string) => {
334
- const tabId = `file:${filePath}`;
335
- setFileTabs((prev) => {
336
- if (prev.find((t) => t.id === tabId)) return prev;
337
- return [...prev, { id: tabId, label: fileName, filePath }];
338
- });
339
- setActiveRightTabId(tabId);
340
- setRightPanelOpen(true);
341
- }, []);
342
-
343
- const handleCloseFileTab = useCallback((tabId: string) => {
344
- if (tabId === "report") return;
345
- setFileTabs((prev) => {
346
- const next = prev.filter((t) => t.id !== tabId);
347
- return next;
348
- });
349
- setActiveRightTabId((cur) => {
350
- if (cur !== tabId) return cur;
351
- const remaining = fileTabs.filter((t) => t.id !== tabId);
352
- return remaining.length > 0 ? remaining[remaining.length - 1].id : "report";
353
- });
354
- }, [fileTabs]);
355
-
356
- // Show chat area if a session is selected, or if we have a cwd to start a new session in
357
- const effectiveNewSessionCwd = newSessionCwd ?? (selectedSession === null && activeCwd ? activeCwd : null);
358
- const showChat = selectedSession !== null || effectiveNewSessionCwd !== null;
359
- // While restoring initial session from URL, don't show the placeholder
360
- const showPlaceholder = initialSessionRestored && !showChat;
361
-
362
- const rightTabs: Tab[] = [{ id: "report", label: "Report", closable: false, icon: "report" }, ...fileTabs];
363
- const activeFileTab = fileTabs.find((t) => t.id === activeRightTabId) ?? null;
364
- const topBarSessionTitle = selectedSession ? getSessionTitle(selectedSession) : effectiveNewSessionCwd ? "New chat" : "No session";
365
- const topBarCwd = selectedSession?.cwd ?? effectiveNewSessionCwd ?? activeCwd ?? "";
366
- const topBarProjectName = topBarCwd ? topBarCwd.replace(/\/+$/, "").split(/[\\/]/).filter(Boolean).pop() || topBarCwd : "";
367
- const settingsCwd = activeCwd ?? selectedSession?.cwd ?? newSessionCwd ?? null;
368
- const updateStatus = (() => {
369
- const runtime = versionStatus?.runtime;
370
- const target = runtime?.installedVersion ?? versionStatus?.latest;
371
- if (runtime?.restartPending && target) {
372
- const restarting = Boolean(runtime.restartStartedAt);
373
- return {
374
- label: `${restarting ? "Restarting" : "Restart queued"} ${target}`,
375
- title: [
376
- `Current runtime: v${runtime.version ?? versionStatus?.current ?? "unknown"}`,
377
- `Installed: v${target}`,
378
- restarting ? "A replacement server is starting." : "annodex will restart after active sessions become idle.",
379
- ].join("\n"),
380
- active: true,
381
- };
382
- }
383
- if (versionStatus?.updateAvailable && versionStatus.latest) {
384
- return {
385
- label: `Update ${versionStatus.latest}`,
386
- title: `Current: v${versionStatus.current}\nLatest: v${versionStatus.latest}\nRun: ${versionStatus.updateCommand}`,
387
- active: false,
388
- };
389
- }
390
- return null;
391
- })();
392
- const openSettings = useCallback((tab: SettingsTab = "projects") => {
393
- setSettingsInitialTab(tab);
394
- setSettingsOpen(true);
395
- }, []);
396
-
397
- const sidebarContent = (
398
- <>
399
- <SessionSidebar
400
- selectedSessionId={selectedSession?.id ?? null}
401
- onSelectSession={handleSelectSession}
402
- onNewSession={handleNewSession}
403
- initialSessionId={initialSessionId}
404
- onInitialRestoreDone={handleInitialRestoreDone}
405
- refreshKey={refreshKey}
406
- onSessionDeleted={handleSessionDeleted}
407
- selectedCwd={selectedSession?.cwd ?? newSessionCwd ?? activeCwd ?? null}
408
- onCwdChange={handleCwdChange}
409
- onOpenFile={handleOpenFile}
410
- explorerRefreshKey={explorerRefreshKey}
411
- onAtMention={handleAtMention}
412
- />
413
- <div style={{ padding: "8px", flexShrink: 0 }}>
414
- <button
415
- type="button"
416
- onClick={() => openSettings("projects")}
417
- title="Settings"
418
- aria-label="Settings"
419
- style={{
420
- width: 34,
421
- display: "flex",
422
- alignItems: "center",
423
- justifyContent: "center",
424
- height: 34,
425
- padding: 0,
426
- background: "none",
427
- border: "none",
428
- borderRadius: 9,
429
- color: "var(--text-muted)",
430
- cursor: "pointer",
431
- fontSize: 12,
432
- transition: "background 0.12s, color 0.12s",
433
- }}
434
- onMouseEnter={(e) => { e.currentTarget.style.background = "var(--bg-hover)"; e.currentTarget.style.color = "var(--text)"; }}
435
- onMouseLeave={(e) => { e.currentTarget.style.background = "none"; e.currentTarget.style.color = "var(--text-muted)"; }}
436
- >
437
- <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}>
438
- <path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.38a2 2 0 0 0-.73-2.73l-.15-.09a2 2 0 0 1-1-1.74v-.51a2 2 0 0 1 1-1.72l.15-.1a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2Z" />
439
- <circle cx="12" cy="12" r="3" />
440
- </svg>
441
- </button>
442
- </div>
443
- </>
444
- );
445
-
446
- return (
447
- <>
448
- <div style={{ display: "flex", height: "100dvh", overflow: "hidden", background: "var(--bg)" }}>
449
- {/* Mobile overlay backdrop */}
450
- <div
451
- className="sidebar-overlay-backdrop"
452
- onClick={() => setSidebarOpen(false)}
453
- style={{
454
- position: "fixed",
455
- inset: 0,
456
- zIndex: 199,
457
- background: "rgba(0,0,0,0.4)",
458
- opacity: sidebarOpen ? 1 : 0,
459
- pointerEvents: sidebarOpen ? "auto" : "none",
460
- transition: "opacity 0.25s ease",
461
- }}
462
- />
463
-
464
- {/* Left sidebar */}
465
- <div
466
- className={`sidebar-container${sidebarOpen ? " sidebar-open" : " sidebar-closed"}`}
467
- style={{
468
- background: "var(--bg-panel)",
469
- borderRight: "1px solid var(--border)",
470
- display: "flex",
471
- flexDirection: "column",
472
- flexShrink: 0,
473
- zIndex: 200,
474
- width: sidebarResize.width,
475
- minWidth: sidebarResize.width,
476
- transition: sidebarOpen || sidebarResize.isResizing ? "none" : undefined,
477
- }}
478
- >
479
- {sidebarContent}
480
- </div>
481
-
482
- {/* Sidebar drag handle */}
483
- {sidebarOpen && (
484
- <ResizeHandle
485
- side="right"
486
- ariaLabel="Resize sidebar"
487
- onResizeStart={sidebarResize.beginResize}
488
- onResize={sidebarResize.resizeBy}
489
- onResizeEnd={sidebarResize.endResize}
490
- />
491
- )}
492
-
493
- {/* Center: chat */}
494
- <div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden", minWidth: 0 }}>
495
- {/* Top bar */}
496
- <div
497
- ref={topBarRef}
498
- className="app-topbar"
499
- style={{
500
- display: "flex",
501
- alignItems: "center",
502
- gap: 8,
503
- flexShrink: 0,
504
- borderBottom: "1px solid var(--border)",
505
- height: 48,
506
- padding: "0 8px",
507
- background: "var(--bg)",
508
- }}
509
- >
510
- <button
511
- className="topbar-sidebar-toggle"
512
- onClick={() => setSidebarOpen((v) => !v)}
513
- title={sidebarOpen ? "Hide sidebar" : "Show sidebar"}
514
- style={{
515
- display: "flex", alignItems: "center", justifyContent: "center",
516
- width: 32, height: 32, padding: 0,
517
- background: "var(--bg-panel)", border: "1px solid var(--border)", borderRadius: 7,
518
- color: "var(--text-muted)", cursor: "pointer", flexShrink: 0, transition: "color 0.12s, background 0.12s",
519
- }}
520
- onMouseEnter={(e) => { e.currentTarget.style.color = "var(--text)"; e.currentTarget.style.background = "var(--bg-hover)"; }}
521
- onMouseLeave={(e) => { e.currentTarget.style.color = "var(--text-muted)"; e.currentTarget.style.background = "var(--bg-panel)"; }}
522
- >
523
- {sidebarOpen ? (
524
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
525
- <rect x="3" y="3" width="18" height="18" rx="2" /><line x1="9" y1="3" x2="9" y2="21" />
526
- </svg>
527
- ) : (
528
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
529
- <line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" />
530
- </svg>
531
- )}
532
- </button>
533
-
534
- <div className="topbar-title-area" style={{ display: "flex", alignItems: "center", gap: 7, minWidth: 0, flex: 1 }}>
535
- <div style={{ minWidth: 0, display: "flex", alignItems: "center", gap: 6 }}>
536
- {editingTitle && selectedSession ? (
537
- <input
538
- ref={titleInputRef}
539
- value={titleDraft}
540
- onChange={(e) => setTitleDraft(e.target.value)}
541
- onKeyDown={handleTitleKeyDown}
542
- onBlur={() => void handleSaveTitle()}
543
- style={{
544
- width: "min(360px, 34vw)",
545
- height: 28,
546
- boxSizing: "border-box",
547
- border: "1px solid var(--border)",
548
- borderRadius: 6,
549
- background: "var(--bg-panel)",
550
- color: "var(--text)",
551
- padding: "0 8px",
552
- fontSize: 13,
553
- fontWeight: 500,
554
- outline: "none",
555
- }}
556
- />
557
- ) : (
558
- <>
559
- <div
560
- className="topbar-session-title"
561
- title={topBarSessionTitle}
562
- style={{
563
- minWidth: 0,
564
- maxWidth: "min(420px, 36vw)",
565
- overflow: "hidden",
566
- textOverflow: "ellipsis",
567
- whiteSpace: "nowrap",
568
- color: showChat ? "var(--text)" : "var(--text-muted)",
569
- fontSize: 14,
570
- fontWeight: 600,
571
- lineHeight: 1.2,
572
- }}
573
- >
574
- {topBarSessionTitle}
575
- </div>
576
- {selectedSession && (
577
- <button
578
- type="button"
579
- className="topbar-rename-button"
580
- onClick={handleStartTitleEdit}
581
- title="Rename session"
582
- style={{
583
- width: 22,
584
- height: 22,
585
- display: "flex",
586
- alignItems: "center",
587
- justifyContent: "center",
588
- padding: 0,
589
- border: "none",
590
- borderRadius: 5,
591
- background: "transparent",
592
- color: "var(--text-dim)",
593
- cursor: "pointer",
594
- flexShrink: 0,
595
- }}
596
- onMouseEnter={(e) => { e.currentTarget.style.color = "var(--text)"; e.currentTarget.style.background = "var(--bg-hover)"; }}
597
- onMouseLeave={(e) => { e.currentTarget.style.color = "var(--text-dim)"; e.currentTarget.style.background = "transparent"; }}
598
- >
599
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
600
- <path d="M12 20h9" />
601
- <path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z" />
602
- </svg>
603
- </button>
604
- )}
605
- </>
606
- )}
607
- </div>
608
- {topBarProjectName && (
609
- <>
610
- <span className="topbar-project-crumb" style={{ color: "var(--text-dim)", fontSize: 12, flexShrink: 0 }}>/</span>
611
- <span
612
- className="topbar-project-crumb"
613
- title={topBarCwd || topBarProjectName}
614
- style={{
615
- minWidth: 0,
616
- maxWidth: "min(280px, 24vw)",
617
- overflow: "hidden",
618
- textOverflow: "ellipsis",
619
- whiteSpace: "nowrap",
620
- color: "var(--text-muted)",
621
- fontSize: 12,
622
- lineHeight: 1.2,
623
- }}
624
- >
625
- {topBarProjectName}
626
- </span>
627
- </>
628
- )}
629
- </div>
630
-
631
- {showChat && (
632
- <div className="topbar-chat-tools" style={{ display: "flex", alignItems: "center", gap: 6, height: 28, flexShrink: 0 }}>
633
- <button
634
- ref={systemBtnRef}
635
- className="topbar-system-button"
636
- onClick={() => toggleTopPanel("system")}
637
- title="System prompt"
638
- aria-label="System prompt"
639
- style={{
640
- display: "flex", alignItems: "center", gap: 6,
641
- height: 28, padding: "0 9px",
642
- background: activeTopPanel === "system" ? "var(--bg-selected)" : "var(--bg-panel)",
643
- border: `1px solid ${activeTopPanel === "system" ? "rgba(37,99,235,0.45)" : "var(--border)"}`,
644
- borderRadius: 7,
645
- cursor: "pointer",
646
- color: activeTopPanel === "system" ? "var(--text)" : "var(--text-muted)",
647
- fontSize: 11, whiteSpace: "nowrap", transition: "color 0.1s, background 0.1s",
648
- }}
649
- onMouseEnter={(e) => { e.currentTarget.style.color = "var(--text)"; e.currentTarget.style.background = "var(--bg-hover)"; }}
650
- onMouseLeave={(e) => {
651
- e.currentTarget.style.color = activeTopPanel === "system" ? "var(--text)" : "var(--text-muted)";
652
- e.currentTarget.style.background = activeTopPanel === "system" ? "var(--bg-selected)" : "var(--bg-panel)";
653
- }}
654
- >
655
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ color: systemPrompt ? "var(--accent)" : "var(--text-dim)", flexShrink: 0 }}>
656
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
657
- <polyline points="14 2 14 8 20 8" />
658
- <line x1="8" y1="13" x2="16" y2="13" />
659
- <line x1="8" y1="17" x2="13" y2="17" />
660
- </svg>
661
- <span className="topbar-system-label">System</span>
662
- </button>
663
- </div>
664
- )}
665
- {/* Session stats — right-aligned in top bar */}
666
- {showChat && (sessionStats || contextUsage) && (() => {
667
- const t = sessionStats?.tokens;
668
- const c = sessionStats?.cost ?? 0;
669
- const fmt = (n: number) => n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)}M` : n >= 1000 ? `${(n / 1000).toFixed(0)}k` : String(n);
670
- const costStr = c > 0 ? (c >= 0.01 ? `$${c.toFixed(2)}` : `<$0.01`) : null;
671
-
672
- let ctxColor = "var(--text-muted)";
673
- let ctxStr: string | null = null;
674
- if (contextUsage?.contextWindow) {
675
- const pct = contextUsage.percent;
676
- const used = contextUsage.tokens;
677
- if (pct !== null && pct > 90) ctxColor = "#ef4444";
678
- else if (pct !== null && pct > 70) ctxColor = "rgba(234,179,8,0.95)";
679
- ctxStr = used !== null ? `${fmt(used)} / ${fmt(contextUsage.contextWindow)}` : `? / ${fmt(contextUsage.contextWindow)}`;
680
- }
681
-
682
- const tooltipParts: string[] = [];
683
- if (t) {
684
- tooltipParts.push(`in: ${t.input.toLocaleString()}`);
685
- tooltipParts.push(`out: ${t.output.toLocaleString()}`);
686
- tooltipParts.push(`cache read: ${t.cacheRead.toLocaleString()}`);
687
- tooltipParts.push(`cache write: ${t.cacheWrite.toLocaleString()}`);
688
- if (c > 0) tooltipParts.push(`cost: $${c.toFixed(4)}`);
689
- }
690
- if (contextUsage?.contextWindow) {
691
- const pct = contextUsage.percent;
692
- tooltipParts.push(`context: ${contextUsage.tokens !== null ? contextUsage.tokens.toLocaleString() : "unknown"} of ${contextUsage.contextWindow.toLocaleString()} tokens${pct !== null ? ` (${pct.toFixed(1)}%)` : ""}`);
693
- }
694
- const tooltip = tooltipParts.join(" | ");
695
-
696
- return (
697
- <div
698
- className="topbar-session-stats"
699
- title={tooltip}
700
- style={{
701
- display: "flex", alignItems: "center", gap: 10,
702
- padding: "0 8px",
703
- height: 28,
704
- border: "1px solid var(--border)",
705
- borderRadius: 7,
706
- background: "var(--bg-panel)",
707
- fontSize: 11, color: "var(--text-muted)",
708
- whiteSpace: "nowrap", cursor: "default",
709
- fontVariantNumeric: "tabular-nums",
710
- }}
711
- >
712
- {t && t.input > 0 && (
713
- <span style={{ display: "flex", alignItems: "center", gap: 4 }}>
714
- <svg width="12" height="12" viewBox="0 0 10 10" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round">
715
- <line x1="5" y1="8.5" x2="5" y2="1.5" /><polyline points="2 4 5 1.5 8 4" />
716
- </svg>
717
- {fmt(t.input)}
718
- </span>
719
- )}
720
- {t && t.output > 0 && (
721
- <span style={{ display: "flex", alignItems: "center", gap: 4 }}>
722
- <svg width="12" height="12" viewBox="0 0 10 10" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round">
723
- <line x1="5" y1="1.5" x2="5" y2="8.5" /><polyline points="2 6 5 8.5 8 6" />
724
- </svg>
725
- {fmt(t.output)}
726
- </span>
727
- )}
728
- {t && t.cacheRead > 0 && (
729
- <span style={{ display: "flex", alignItems: "center", gap: 4 }}>
730
- <svg width="12" height="12" viewBox="0 0 10 10" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round">
731
- <path d="M8.5 5a3.5 3.5 0 1 1-1-2.45" /><polyline points="6.5 1.5 8.5 2.5 7.5 4.5" />
732
- </svg>
733
- {fmt(t.cacheRead)}
734
- </span>
735
- )}
736
- {costStr && (
737
- <span style={{ display: "flex", alignItems: "center", color: "var(--text)", fontWeight: 500 }}>
738
- {costStr}
739
- </span>
740
- )}
741
- {ctxStr && (
742
- <span style={{ display: "flex", alignItems: "center", gap: 4, color: ctxColor }}>
743
- <svg width="12" height="12" viewBox="0 0 10 10" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round">
744
- <path d="M1 9 L1 5 Q1 1 5 1 Q9 1 9 5 L9 9" /><line x1="1" y1="9" x2="9" y2="9" />
745
- </svg>
746
- {ctxStr}
747
- </span>
748
- )}
749
- </div>
750
- );
751
- })()}
752
- {updateStatus && (
753
- <div
754
- className="topbar-update-status"
755
- title={updateStatus.title}
756
- style={{
757
- display: "flex",
758
- alignItems: "center",
759
- gap: 6,
760
- height: 28,
761
- padding: "0 8px",
762
- border: `1px solid ${updateStatus.active ? "rgba(37,99,235,0.45)" : "var(--border)"}`,
763
- borderRadius: 7,
764
- background: updateStatus.active ? "var(--bg-selected)" : "var(--bg-panel)",
765
- color: updateStatus.active ? "var(--accent)" : "var(--text-muted)",
766
- fontSize: 11,
767
- whiteSpace: "nowrap",
768
- flexShrink: 0,
769
- fontVariantNumeric: "tabular-nums",
770
- }}
771
- >
772
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}>
773
- <path d="M21 12a9 9 0 0 1-15.5 6.2" />
774
- <path d="M3 12A9 9 0 0 1 18.5 5.8" />
775
- <path d="M7 18H5.5v1.5" />
776
- <path d="M17 6h1.5V4.5" />
777
- </svg>
778
- <span>{updateStatus.label}</span>
779
- </div>
780
- )}
781
- <button
782
- type="button"
783
- className="topbar-icon-button topbar-generate-ui-toggle"
784
- onClick={handleGenerativeUIToggle}
785
- title={`生成式 UI: ${settings.generativeUI ? "on" : "off"}`}
786
- aria-label={`生成式 UI: ${settings.generativeUI ? "on" : "off"}`}
787
- style={{
788
- display: "flex", alignItems: "center", justifyContent: "center",
789
- width: 32, height: 28, padding: 0,
790
- background: settings.generativeUI ? "var(--bg-selected)" : "var(--bg-panel)",
791
- border: `1px solid ${settings.generativeUI ? "rgba(37,99,235,0.45)" : "var(--border)"}`,
792
- borderRadius: 7,
793
- color: settings.generativeUI ? "var(--accent)" : "var(--text-muted)",
794
- cursor: "pointer",
795
- flexShrink: 0,
796
- transition: "color 0.12s, background 0.12s",
797
- }}
798
- onMouseEnter={(e) => { e.currentTarget.style.color = settings.generativeUI ? "var(--accent)" : "var(--text)"; e.currentTarget.style.background = "var(--bg-hover)"; }}
799
- onMouseLeave={(e) => {
800
- e.currentTarget.style.color = settings.generativeUI ? "var(--accent)" : "var(--text-muted)";
801
- e.currentTarget.style.background = settings.generativeUI ? "var(--bg-selected)" : "var(--bg-panel)";
802
- }}
803
- >
804
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
805
- <rect x="3" y="3" width="7" height="7" rx="1.5" />
806
- <rect x="14" y="3" width="7" height="7" rx="1.5" />
807
- <rect x="3" y="14" width="7" height="7" rx="1.5" />
808
- <path d="M16 17h5" />
809
- <path d="M18.5 14.5v5" />
810
- </svg>
811
- </button>
812
- <button
813
- className="topbar-icon-button topbar-theme-toggle"
814
- onClick={(e) => {
815
- const rect = e.currentTarget.getBoundingClientRect();
816
- toggleTheme({ x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 });
817
- }}
818
- title={isDark ? "Switch to light mode" : "Switch to dark mode"}
819
- aria-label={isDark ? "Switch to light mode" : "Switch to dark mode"}
820
- aria-pressed={isDark}
821
- style={{
822
- display: "flex", alignItems: "center", justifyContent: "center",
823
- width: 32, height: 28, padding: 0,
824
- background: "var(--bg-panel)", border: "1px solid var(--border)", borderRadius: 7,
825
- color: "var(--text-muted)", cursor: "pointer", flexShrink: 0, transition: "color 0.12s, background 0.12s",
826
- }}
827
- onMouseEnter={(e) => { e.currentTarget.style.color = "var(--text)"; e.currentTarget.style.background = "var(--bg-hover)"; }}
828
- onMouseLeave={(e) => { e.currentTarget.style.color = "var(--text-muted)"; e.currentTarget.style.background = "var(--bg-panel)"; }}
829
- >
830
- {isDark ? (
831
- <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
832
- <circle cx="12" cy="12" r="5" />
833
- <line x1="12" y1="1" x2="12" y2="3" /><line x1="12" y1="21" x2="12" y2="23" />
834
- <line x1="4.22" y1="4.22" x2="5.64" y2="5.64" /><line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
835
- <line x1="1" y1="12" x2="3" y2="12" /><line x1="21" y1="12" x2="23" y2="12" />
836
- <line x1="4.22" y1="19.78" x2="5.64" y2="18.36" /><line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
837
- </svg>
838
- ) : (
839
- <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
840
- <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
841
- </svg>
842
- )}
843
- </button>
844
- <button
845
- className="topbar-icon-button topbar-right-panel-toggle"
846
- onClick={() => setRightPanelOpen((v) => !v)}
847
- title={rightPanelOpen ? "Hide report panel" : "Show report panel"}
848
- aria-label={rightPanelOpen ? "Hide report panel" : "Show report panel"}
849
- style={{
850
- display: "flex", alignItems: "center", justifyContent: "center",
851
- width: 32, height: 28, padding: 0,
852
- background: rightPanelOpen ? "var(--bg-selected)" : "var(--bg-panel)",
853
- border: `1px solid ${rightPanelOpen ? "rgba(37,99,235,0.45)" : "var(--border)"}`,
854
- borderRadius: 7,
855
- color: rightPanelOpen ? "var(--accent)" : "var(--text-muted)",
856
- cursor: "pointer",
857
- flexShrink: 0,
858
- transition: "color 0.12s, background 0.12s",
859
- }}
860
- onMouseEnter={(e) => { e.currentTarget.style.color = rightPanelOpen ? "var(--accent)" : "var(--text)"; e.currentTarget.style.background = "var(--bg-hover)"; }}
861
- onMouseLeave={(e) => {
862
- e.currentTarget.style.color = rightPanelOpen ? "var(--accent)" : "var(--text-muted)";
863
- e.currentTarget.style.background = rightPanelOpen ? "var(--bg-selected)" : "var(--bg-panel)";
864
- }}
865
- >
866
- <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
867
- <rect x="3" y="3" width="18" height="18" rx="2" /><line x1="15" y1="3" x2="15" y2="21" />
868
- </svg>
869
- </button>
870
- {/* Top panel dropdown — shared, only one active at a time */}
871
- {activeTopPanel && topPanelPos && (
872
- <div style={{
873
- position: "fixed",
874
- top: topPanelPos.top,
875
- left: topPanelPos.left,
876
- width: topPanelPos.width,
877
- zIndex: 500,
878
- }}>
879
- {activeTopPanel === "system" && (
880
- <div style={{
881
- background: "var(--bg-panel)",
882
- borderBottom: "1px solid var(--border)",
883
- }}>
884
- {systemPrompt ? (
885
- <div style={{
886
- maxHeight: "min(600px, 75vh)",
887
- overflowY: "auto",
888
- padding: "12px 16px",
889
- color: "var(--text-muted)",
890
- fontSize: 12,
891
- lineHeight: 1.6,
892
- whiteSpace: "pre-wrap",
893
- fontFamily: "var(--font-mono)",
894
- }}>
895
- {systemPrompt}
896
- </div>
897
- ) : systemPrompt === "" ? (
898
- <div style={{ padding: "10px 16px", fontSize: 12, color: "var(--text-muted)", fontStyle: "italic" }}>
899
- System prompt is empty (tools are disabled)
900
- </div>
901
- ) : (
902
- <div style={{ padding: "10px 16px", fontSize: 12, color: "var(--text-muted)", fontStyle: "italic" }}>
903
- Send a message to load the system prompt
904
- </div>
905
- )}
906
- </div>
907
- )}
908
- </div>
909
- )}
910
-
911
- </div>
912
-
913
- {/* Chat content */}
914
- <div style={{ flex: 1, overflow: "hidden", position: "relative" }}>
915
- {showChat ? (
916
- <ChatWindow
917
- key={sessionKey}
918
- session={selectedSession}
919
- newSessionCwd={effectiveNewSessionCwd}
920
- onAgentEnd={handleAgentEnd}
921
- onSessionCreated={handleSessionCreated}
922
- onSessionForked={handleSessionForked}
923
- modelsRefreshKey={modelsRefreshKey}
924
- chatInputRef={chatInputRef}
925
- onSystemPromptChange={handleSystemPromptChange}
926
- onSessionStatsChange={handleSessionStatsChange}
927
- onContextUsageChange={handleContextUsageChange}
928
- onReportUpdated={() => setReportRefreshKey((k) => k + 1)}
929
- generativeUI={settings.generativeUI}
930
- />
931
- ) : showPlaceholder ? (
932
- activeCwd ? (
933
- <div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-muted)", fontSize: 15 }}>
934
- Select a session from the sidebar
935
- </div>
936
- ) : (
937
- <div style={{ position: "absolute", top: 12, left: 12, display: "flex", alignItems: "flex-start", gap: 8, userSelect: "none", pointerEvents: "none" }}>
938
- <svg width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.7, flexShrink: 0 }}>
939
- <line x1="20" y1="12" x2="4" y2="12" /><polyline points="10 6 4 12 10 18" />
940
- </svg>
941
- <div>
942
- <div style={{ fontSize: 18, fontWeight: 600, color: "var(--text)", marginBottom: 8 }}>Get Started</div>
943
- <div style={{ fontSize: 12, color: "var(--text-muted)", lineHeight: 1.8 }}>
944
- <span style={{ color: "var(--text-dim)", marginRight: 6 }}>1.</span>Select a project directory from the sidebar<br />
945
- <span style={{ color: "var(--text-dim)", marginRight: 6 }}>2.</span>Add models via the <strong style={{ color: "var(--text)" }}>Models</strong> button at the bottom
946
- </div>
947
- </div>
948
- </div>
949
- )
950
- ) : null}
951
- </div>
952
- </div>
953
-
954
- {/* Right panel drag handle */}
955
- {rightPanelOpen && (
956
- <ResizeHandle
957
- side="left"
958
- ariaLabel="Resize right panel"
959
- onResizeStart={rightPanelResize.beginResize}
960
- onResize={rightPanelResize.resizeBy}
961
- onResizeEnd={rightPanelResize.endResize}
962
- />
963
- )}
964
-
965
- {/* Right panel: report + file viewer */}
966
- <div
967
- className={`right-panel-container${rightPanelOpen ? " right-panel-open" : " right-panel-closed"}`}
968
- style={{
969
- display: rightPanelOpen ? "flex" : "none",
970
- flexDirection: "column",
971
- borderLeft: "1px solid var(--border)",
972
- background: "var(--bg)",
973
- flexShrink: 0,
974
- width: rightPanelResize.width,
975
- minWidth: rightPanelResize.width,
976
- transition: rightPanelResize.isResizing ? "none" : undefined,
977
- }}
978
- >
979
- {/* Right panel tab bar */}
980
- <div style={{ display: "flex", alignItems: "center", flexShrink: 0, background: "var(--bg-panel)", borderBottom: "1px solid var(--border)", height: 36 }}>
981
- <button
982
- type="button"
983
- className="right-panel-back-button"
984
- onClick={() => setRightPanelOpen(false)}
985
- title="Back to chat"
986
- aria-label="Back to chat"
987
- style={{
988
- height: 36,
989
- padding: "0 10px",
990
- border: "none",
991
- borderRight: "1px solid var(--border)",
992
- background: "var(--bg-panel)",
993
- color: "var(--text-muted)",
994
- cursor: "pointer",
995
- fontSize: 12,
996
- alignItems: "center",
997
- gap: 6,
998
- flexShrink: 0,
999
- }}
1000
- >
1001
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
1002
- <line x1="19" y1="12" x2="5" y2="12" />
1003
- <polyline points="12 19 5 12 12 5" />
1004
- </svg>
1005
- <span>Chat</span>
1006
- </button>
1007
- <div style={{ flex: 1, overflow: "hidden" }}>
1008
- <TabBar
1009
- tabs={rightTabs}
1010
- activeTabId={activeRightTabId}
1011
- onSelectTab={setActiveRightTabId}
1012
- onCloseTab={handleCloseFileTab}
1013
- />
1014
- </div>
1015
-
1016
- </div>
1017
-
1018
- {/* File content */}
1019
- <div style={{ flex: 1, overflow: "hidden" }}>
1020
- {activeRightTabId === "report" ? (
1021
- <ReportPanel
1022
- sessionId={selectedSession?.id ?? null}
1023
- cwd={selectedSession?.cwd ?? activeCwd ?? undefined}
1024
- refreshKey={reportRefreshKey}
1025
- onOpenFile={handleOpenFile}
1026
- />
1027
- ) : activeFileTab?.filePath ? (
1028
- activeFileTab.filePath.startsWith("__") ? (
1029
- <GlobalFileEditor filePath={activeFileTab.filePath} />
1030
- ) : (
1031
- <FileViewer filePath={activeFileTab.filePath} cwd={activeCwd ?? undefined} onOpenFile={handleOpenFile} />
1032
- )
1033
- ) : (
1034
- <div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-dim)", fontSize: 12 }}>
1035
- No file open
1036
- </div>
1037
- )}
1038
- </div>
1039
- </div>
1040
- </div>
1041
- {settingsOpen && (
1042
- <SettingsDialog
1043
- cwd={settingsCwd}
1044
- generativeUI={settings.generativeUI}
1045
- initialTab={settingsInitialTab}
1046
- onGenerativeUIToggle={handleGenerativeUIToggle}
1047
- onModelsChanged={() => setModelsRefreshKey((k) => k + 1)}
1048
- onProjectSelect={handleProjectSelect}
1049
- onProjectsChanged={() => setRefreshKey((k) => k + 1)}
1050
- onClose={() => {
1051
- setSettingsOpen(false);
1052
- setModelsRefreshKey((k) => k + 1);
1053
- }}
1054
- />
1055
- )}
1056
- </>
1057
- );
1058
- }