@jlongo78/agent-spaces 0.7.2 → 0.7.4

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 (605) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +8 -0
  3. package/.next/standalone/.next/build-manifest.json +2 -2
  4. package/.next/standalone/.next/routes-manifest.json +48 -0
  5. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page.js +1 -1
  6. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/(desktop)/admin/users/page.js +1 -1
  9. package/.next/standalone/.next/server/app/(desktop)/admin/users/page.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/(desktop)/analytics/page.js +1 -1
  12. package/.next/standalone/.next/server/app/(desktop)/analytics/page.js.nft.json +1 -1
  13. package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
  14. package/.next/standalone/.next/server/app/(desktop)/cortex/page.js +1 -1
  15. package/.next/standalone/.next/server/app/(desktop)/cortex/page.js.nft.json +1 -1
  16. package/.next/standalone/.next/server/app/(desktop)/cortex/page_client-reference-manifest.js +1 -1
  17. package/.next/standalone/.next/server/app/(desktop)/network/page.js +1 -1
  18. package/.next/standalone/.next/server/app/(desktop)/network/page.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/(desktop)/page.js +1 -1
  21. package/.next/standalone/.next/server/app/(desktop)/page.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/(desktop)/projects/page.js +1 -1
  24. package/.next/standalone/.next/server/app/(desktop)/projects/page.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
  26. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js +1 -1
  27. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
  29. package/.next/standalone/.next/server/app/(desktop)/sessions/page.js +1 -1
  30. package/.next/standalone/.next/server/app/(desktop)/sessions/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/(desktop)/settings/page.js +1 -1
  33. package/.next/standalone/.next/server/app/(desktop)/settings/page.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js +1 -1
  36. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
  38. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js +1 -1
  39. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js +1 -1
  42. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/(desktop)/workspaces/page.js +1 -1
  45. package/.next/standalone/.next/server/app/(desktop)/workspaces/page.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
  47. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  48. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  49. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  50. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  51. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  52. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  53. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  54. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  56. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  57. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  59. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  60. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  61. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  62. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  63. package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
  64. package/.next/standalone/.next/server/app/admin/analytics.rsc +17 -16
  65. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +2 -2
  66. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
  67. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  68. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  69. package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +17 -16
  70. package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
  71. package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +2 -2
  72. package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
  73. package/.next/standalone/.next/server/app/admin/users.html +1 -1
  74. package/.next/standalone/.next/server/app/admin/users.rsc +17 -16
  75. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +2 -2
  76. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
  77. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  78. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  79. package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +17 -16
  80. package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
  81. package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +2 -2
  82. package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
  83. package/.next/standalone/.next/server/app/analytics.html +1 -1
  84. package/.next/standalone/.next/server/app/analytics.rsc +17 -16
  85. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +2 -2
  86. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
  87. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  88. package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +17 -16
  89. package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
  90. package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +2 -2
  91. package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  92. package/.next/standalone/.next/server/app/api/admin/analytics/route.js +1 -1
  93. package/.next/standalone/.next/server/app/api/admin/analytics/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/admin/users/[id]/route.js +1 -1
  95. package/.next/standalone/.next/server/app/api/admin/users/[id]/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/admin/users/route.js +1 -1
  97. package/.next/standalone/.next/server/app/api/admin/users/route.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/api/analytics/overview/route.js +3 -3
  99. package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
  100. package/.next/standalone/.next/server/app/api/auth/login/route.js +1 -1
  101. package/.next/standalone/.next/server/app/api/auth/login/route.js.nft.json +1 -1
  102. package/.next/standalone/.next/server/app/api/auth/logout/route.js +1 -1
  103. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/api/auth/me/route.js +1 -1
  105. package/.next/standalone/.next/server/app/api/auth/me/route.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/api/auth/totp/setup/route.js +1 -1
  107. package/.next/standalone/.next/server/app/api/auth/totp/setup/route.js.nft.json +1 -1
  108. package/.next/standalone/.next/server/app/api/auth/totp/status/route.js +1 -1
  109. package/.next/standalone/.next/server/app/api/auth/totp/status/route.js.nft.json +1 -1
  110. package/.next/standalone/.next/server/app/api/auth/totp/verify/route.js +1 -1
  111. package/.next/standalone/.next/server/app/api/auth/totp/verify/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/bulk/route.js +2 -2
  113. package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/api/chat/route.js +1 -1
  115. package/.next/standalone/.next/server/app/api/chat/route.js.nft.json +1 -1
  116. package/.next/standalone/.next/server/app/api/config/route.js +1 -1
  117. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  118. package/.next/standalone/.next/server/app/api/cortex/context/route.js +1 -1
  119. package/.next/standalone/.next/server/app/api/cortex/context/route.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/app-paths-manifest.json +3 -0
  121. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/build-manifest.json +11 -0
  122. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/server-reference-manifest.json +4 -0
  123. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js +7 -0
  124. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.map +5 -0
  125. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.nft.json +1 -0
  126. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route_client-reference-manifest.js +2 -0
  127. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/app-paths-manifest.json +3 -0
  128. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/build-manifest.json +11 -0
  129. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/server-reference-manifest.json +4 -0
  130. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js +7 -0
  131. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.map +5 -0
  132. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.nft.json +1 -0
  133. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route_client-reference-manifest.js +2 -0
  134. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/app-paths-manifest.json +3 -0
  135. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/build-manifest.json +11 -0
  136. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/server-reference-manifest.json +4 -0
  137. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js +7 -0
  138. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.map +5 -0
  139. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.nft.json +1 -0
  140. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route_client-reference-manifest.js +2 -0
  141. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/app-paths-manifest.json +3 -0
  142. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/build-manifest.json +11 -0
  143. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/server-reference-manifest.json +4 -0
  144. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js +7 -0
  145. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.map +5 -0
  146. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.nft.json +1 -0
  147. package/.next/standalone/.next/server/app/api/cortex/curation/review/route_client-reference-manifest.js +2 -0
  148. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/app-paths-manifest.json +3 -0
  149. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/build-manifest.json +11 -0
  150. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/server-reference-manifest.json +4 -0
  151. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js +7 -0
  152. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.map +5 -0
  153. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.nft.json +1 -0
  154. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route_client-reference-manifest.js +2 -0
  155. package/.next/standalone/.next/server/app/api/cortex/export/route.js +1 -1
  156. package/.next/standalone/.next/server/app/api/cortex/export/route.js.nft.json +1 -1
  157. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js +1 -1
  158. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js.nft.json +1 -1
  159. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js +1 -1
  160. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js.nft.json +1 -1
  161. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js +1 -1
  162. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js.nft.json +1 -1
  163. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js +1 -1
  164. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js.nft.json +1 -1
  165. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js +1 -1
  166. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js.nft.json +1 -1
  167. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js +1 -1
  168. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js.nft.json +1 -1
  169. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js +1 -1
  170. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js.nft.json +1 -1
  171. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js +1 -1
  172. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js.nft.json +1 -1
  173. package/.next/standalone/.next/server/app/api/cortex/import/route.js +1 -1
  174. package/.next/standalone/.next/server/app/api/cortex/import/route.js.nft.json +1 -1
  175. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js +1 -1
  176. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js.nft.json +1 -1
  177. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js +1 -1
  178. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js.nft.json +1 -1
  179. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js +1 -1
  180. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js.nft.json +1 -1
  181. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js +1 -1
  182. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js.nft.json +1 -1
  183. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js +1 -1
  184. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js.nft.json +1 -1
  185. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js +1 -1
  186. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js.nft.json +1 -1
  187. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js +1 -1
  188. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js.nft.json +1 -1
  189. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js +1 -1
  190. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js.nft.json +1 -1
  191. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/app-paths-manifest.json +3 -0
  192. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/build-manifest.json +11 -0
  193. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/server-reference-manifest.json +4 -0
  194. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js +7 -0
  195. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.map +5 -0
  196. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.nft.json +1 -0
  197. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route_client-reference-manifest.js +2 -0
  198. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/app-paths-manifest.json +3 -0
  199. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/build-manifest.json +11 -0
  200. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/server-reference-manifest.json +4 -0
  201. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js +7 -0
  202. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.map +5 -0
  203. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.nft.json +1 -0
  204. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route_client-reference-manifest.js +2 -0
  205. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js +1 -1
  206. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js.nft.json +1 -1
  207. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js +1 -1
  208. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js.nft.json +1 -1
  209. package/.next/standalone/.next/server/app/api/cortex/search/route.js +1 -1
  210. package/.next/standalone/.next/server/app/api/cortex/search/route.js.nft.json +1 -1
  211. package/.next/standalone/.next/server/app/api/cortex/settings/route.js +1 -1
  212. package/.next/standalone/.next/server/app/api/cortex/settings/route.js.nft.json +1 -1
  213. package/.next/standalone/.next/server/app/api/cortex/status/route.js +1 -1
  214. package/.next/standalone/.next/server/app/api/cortex/status/route.js.nft.json +1 -1
  215. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js +1 -1
  216. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js.nft.json +1 -1
  217. package/.next/standalone/.next/server/app/api/cortex/usage/route.js +1 -1
  218. package/.next/standalone/.next/server/app/api/cortex/usage/route.js.nft.json +1 -1
  219. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js +1 -1
  220. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js.nft.json +1 -1
  221. package/.next/standalone/.next/server/app/api/events/route.js +1 -1
  222. package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
  223. package/.next/standalone/.next/server/app/api/files/route.js +1 -1
  224. package/.next/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  225. package/.next/standalone/.next/server/app/api/folders/route.js +1 -1
  226. package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
  227. package/.next/standalone/.next/server/app/api/network/connect-callback/route.js +1 -1
  228. package/.next/standalone/.next/server/app/api/network/connect-callback/route.js.nft.json +1 -1
  229. package/.next/standalone/.next/server/app/api/network/connect-request/[id]/route.js +1 -1
  230. package/.next/standalone/.next/server/app/api/network/connect-request/[id]/route.js.nft.json +1 -1
  231. package/.next/standalone/.next/server/app/api/network/connect-request/route.js +1 -1
  232. package/.next/standalone/.next/server/app/api/network/connect-request/route.js.nft.json +1 -1
  233. package/.next/standalone/.next/server/app/api/network/discovered/route.js +1 -1
  234. package/.next/standalone/.next/server/app/api/network/discovered/route.js.nft.json +1 -1
  235. package/.next/standalone/.next/server/app/api/network/handshake/route.js +1 -1
  236. package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
  237. package/.next/standalone/.next/server/app/api/network/health/route.js +1 -1
  238. package/.next/standalone/.next/server/app/api/network/health/route.js.nft.json +1 -1
  239. package/.next/standalone/.next/server/app/api/network/identity/route.js +1 -1
  240. package/.next/standalone/.next/server/app/api/network/identity/route.js.nft.json +1 -1
  241. package/.next/standalone/.next/server/app/api/network/keys/[id]/route.js +1 -1
  242. package/.next/standalone/.next/server/app/api/network/keys/[id]/route.js.nft.json +1 -1
  243. package/.next/standalone/.next/server/app/api/network/keys/route.js +1 -1
  244. package/.next/standalone/.next/server/app/api/network/keys/route.js.nft.json +1 -1
  245. package/.next/standalone/.next/server/app/api/network/nodes/[id]/route.js +1 -1
  246. package/.next/standalone/.next/server/app/api/network/nodes/[id]/route.js.nft.json +1 -1
  247. package/.next/standalone/.next/server/app/api/network/nodes/check/route.js +1 -1
  248. package/.next/standalone/.next/server/app/api/network/nodes/check/route.js.nft.json +1 -1
  249. package/.next/standalone/.next/server/app/api/network/nodes/route.js +1 -1
  250. package/.next/standalone/.next/server/app/api/network/nodes/route.js.nft.json +1 -1
  251. package/.next/standalone/.next/server/app/api/network/projects/route.js +1 -1
  252. package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
  253. package/.next/standalone/.next/server/app/api/network/proxy/[nodeId]/[...path]/route.js +1 -1
  254. package/.next/standalone/.next/server/app/api/network/proxy/[nodeId]/[...path]/route.js.nft.json +1 -1
  255. package/.next/standalone/.next/server/app/api/network/search/route.js +1 -1
  256. package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
  257. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js +1 -1
  258. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
  259. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js +1 -1
  260. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
  261. package/.next/standalone/.next/server/app/api/network/sessions/route.js +1 -1
  262. package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
  263. package/.next/standalone/.next/server/app/api/network/terminal/token/route.js +1 -1
  264. package/.next/standalone/.next/server/app/api/network/terminal/token/route.js.nft.json +1 -1
  265. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js +1 -1
  266. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
  267. package/.next/standalone/.next/server/app/api/network/workspaces/route.js +1 -1
  268. package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
  269. package/.next/standalone/.next/server/app/api/panes/[id]/route.js +2 -2
  270. package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
  271. package/.next/standalone/.next/server/app/api/panes/route.js +2 -2
  272. package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
  273. package/.next/standalone/.next/server/app/api/projects/route.js +2 -2
  274. package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  275. package/.next/standalone/.next/server/app/api/search/route.js +2 -2
  276. package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  277. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js +1 -1
  278. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
  279. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js +2 -2
  280. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
  281. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js +2 -2
  282. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  283. package/.next/standalone/.next/server/app/api/sessions/route.js +2 -2
  284. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  285. package/.next/standalone/.next/server/app/api/sync/route.js +1 -1
  286. package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
  287. package/.next/standalone/.next/server/app/api/tags/route.js +2 -2
  288. package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
  289. package/.next/standalone/.next/server/app/api/tier/route.js +1 -1
  290. package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
  291. package/.next/standalone/.next/server/app/api/updates/route/app-paths-manifest.json +3 -0
  292. package/.next/standalone/.next/server/app/api/updates/route/build-manifest.json +11 -0
  293. package/.next/standalone/.next/server/app/api/updates/route/server-reference-manifest.json +4 -0
  294. package/.next/standalone/.next/server/app/api/updates/route.js +7 -0
  295. package/.next/standalone/.next/server/app/api/updates/route.js.map +5 -0
  296. package/.next/standalone/.next/server/app/api/updates/route.js.nft.json +1 -0
  297. package/.next/standalone/.next/server/app/api/updates/route_client-reference-manifest.js +2 -0
  298. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js +1 -1
  299. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
  300. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js +1 -1
  301. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
  302. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js +1 -1
  303. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
  304. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js +1 -1
  305. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
  306. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js +2 -2
  307. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
  308. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js +2 -2
  309. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
  310. package/.next/standalone/.next/server/app/api/workspaces/route.js +2 -2
  311. package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  312. package/.next/standalone/.next/server/app/cortex.html +1 -1
  313. package/.next/standalone/.next/server/app/cortex.rsc +17 -16
  314. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex/__PAGE__.segment.rsc +2 -2
  315. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex.segment.rsc +1 -1
  316. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  317. package/.next/standalone/.next/server/app/cortex.segments/_full.segment.rsc +17 -16
  318. package/.next/standalone/.next/server/app/cortex.segments/_head.segment.rsc +1 -1
  319. package/.next/standalone/.next/server/app/cortex.segments/_index.segment.rsc +2 -2
  320. package/.next/standalone/.next/server/app/cortex.segments/_tree.segment.rsc +2 -2
  321. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  322. package/.next/standalone/.next/server/app/login.html +1 -1
  323. package/.next/standalone/.next/server/app/login.rsc +2 -2
  324. package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
  325. package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
  326. package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +2 -2
  327. package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  328. package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  329. package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
  330. package/.next/standalone/.next/server/app/m/page.js.nft.json +1 -1
  331. package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
  332. package/.next/standalone/.next/server/app/m/projects/page.js.nft.json +1 -1
  333. package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
  334. package/.next/standalone/.next/server/app/m/projects.html +1 -1
  335. package/.next/standalone/.next/server/app/m/projects.rsc +4 -4
  336. package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +4 -4
  337. package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
  338. package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +2 -2
  339. package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
  340. package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +2 -2
  341. package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
  342. package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +2 -2
  343. package/.next/standalone/.next/server/app/m/sessions/[id]/page.js.nft.json +1 -1
  344. package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
  345. package/.next/standalone/.next/server/app/m/sessions/page.js.nft.json +1 -1
  346. package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
  347. package/.next/standalone/.next/server/app/m/sessions.html +1 -1
  348. package/.next/standalone/.next/server/app/m/sessions.rsc +4 -4
  349. package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +4 -4
  350. package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
  351. package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +2 -2
  352. package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
  353. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +2 -2
  354. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
  355. package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +2 -2
  356. package/.next/standalone/.next/server/app/m/settings/page.js.nft.json +1 -1
  357. package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
  358. package/.next/standalone/.next/server/app/m/settings.html +1 -1
  359. package/.next/standalone/.next/server/app/m/settings.rsc +4 -4
  360. package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +4 -4
  361. package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
  362. package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +2 -2
  363. package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
  364. package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +2 -2
  365. package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
  366. package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +2 -2
  367. package/.next/standalone/.next/server/app/m/terminal/page.js.nft.json +1 -1
  368. package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
  369. package/.next/standalone/.next/server/app/m/terminal.html +1 -1
  370. package/.next/standalone/.next/server/app/m/terminal.rsc +4 -4
  371. package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +4 -4
  372. package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
  373. package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +2 -2
  374. package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
  375. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
  376. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
  377. package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +2 -2
  378. package/.next/standalone/.next/server/app/m.html +1 -1
  379. package/.next/standalone/.next/server/app/m.rsc +4 -4
  380. package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +4 -4
  381. package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
  382. package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +2 -2
  383. package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
  384. package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +2 -2
  385. package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +2 -2
  386. package/.next/standalone/.next/server/app/network.html +1 -1
  387. package/.next/standalone/.next/server/app/network.rsc +17 -16
  388. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +2 -2
  389. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
  390. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  391. package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +17 -16
  392. package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
  393. package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +2 -2
  394. package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
  395. package/.next/standalone/.next/server/app/projects.html +1 -1
  396. package/.next/standalone/.next/server/app/projects.rsc +17 -16
  397. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +2 -2
  398. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
  399. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  400. package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +17 -16
  401. package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  402. package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +2 -2
  403. package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  404. package/.next/standalone/.next/server/app/sessions.html +1 -1
  405. package/.next/standalone/.next/server/app/sessions.rsc +17 -16
  406. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +2 -2
  407. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
  408. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  409. package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +17 -16
  410. package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
  411. package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +2 -2
  412. package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
  413. package/.next/standalone/.next/server/app/settings.html +1 -1
  414. package/.next/standalone/.next/server/app/settings.rsc +17 -16
  415. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +2 -2
  416. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
  417. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  418. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +17 -16
  419. package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  420. package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  421. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  422. package/.next/standalone/.next/server/app/terminal.html +1 -1
  423. package/.next/standalone/.next/server/app/terminal.rsc +17 -16
  424. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
  425. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
  426. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  427. package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +17 -16
  428. package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
  429. package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +2 -2
  430. package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
  431. package/.next/standalone/.next/server/app/workspaces.html +1 -1
  432. package/.next/standalone/.next/server/app/workspaces.rsc +17 -16
  433. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +2 -2
  434. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
  435. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  436. package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +17 -16
  437. package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
  438. package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +2 -2
  439. package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
  440. package/.next/standalone/.next/server/app-paths-manifest.json +8 -0
  441. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0041efe4._.js +98 -0
  442. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__4d5f802e._.js → [root-of-the-server]__00bf0ace._.js} +2 -2
  443. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0fac388d._.js → [root-of-the-server]__08a68343._.js} +2 -2
  444. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0955695e._.js → [root-of-the-server]__0add852f._.js} +2 -2
  445. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2a7a798c._.js → [root-of-the-server]__0c113ed0._.js} +2 -2
  446. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__776b2fd5._.js → [root-of-the-server]__0e1a27e0._.js} +2 -2
  447. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__805ab6d4._.js → [root-of-the-server]__0e71d908._.js} +2 -2
  448. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__fcfb3d9b._.js → [root-of-the-server]__0e9142f3._.js} +2 -2
  449. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0b622fbb._.js → [root-of-the-server]__10e47926._.js} +2 -2
  450. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__6b94cc47._.js → [root-of-the-server]__1194f2c1._.js} +2 -2
  451. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__65015776._.js → [root-of-the-server]__1665dc78._.js} +2 -2
  452. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__a1c90b00._.js → [root-of-the-server]__175cbabf._.js} +2 -2
  453. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__6c6cfe82._.js → [root-of-the-server]__19c2d094._.js} +2 -2
  454. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__efefd88d._.js → [root-of-the-server]__1adae357._.js} +2 -2
  455. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d359752._.js +98 -0
  456. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__d2bbb75a._.js → [root-of-the-server]__1e8fabeb._.js} +2 -2
  457. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__c13f151f._.js → [root-of-the-server]__1f8deca0._.js} +2 -2
  458. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__3331633d._.js → [root-of-the-server]__253fdda1._.js} +2 -2
  459. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__d0439252._.js → [root-of-the-server]__28e6434f._.js} +2 -2
  460. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__3ba575ca._.js → [root-of-the-server]__2a386564._.js} +13 -13
  461. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__7901e2ab._.js → [root-of-the-server]__2acbd703._.js} +2 -2
  462. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__466c7e18._.js → [root-of-the-server]__2acefabb._.js} +2 -2
  463. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__8cddfa2d._.js → [root-of-the-server]__2c20fb38._.js} +2 -2
  464. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__4837b8c0._.js → [root-of-the-server]__309132cd._.js} +2 -2
  465. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__6d211342._.js → [root-of-the-server]__3786d8ae._.js} +2 -2
  466. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__f3e94a15._.js → [root-of-the-server]__3ae92407._.js} +2 -2
  467. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__7799fe3c._.js → [root-of-the-server]__3beda9fe._.js} +2 -2
  468. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__25d1fc87._.js → [root-of-the-server]__3e3f25a1._.js} +2 -2
  469. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0c59850c._.js → [root-of-the-server]__4619e9bd._.js} +2 -2
  470. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__3beca461._.js → [root-of-the-server]__4a051043._.js} +2 -2
  471. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__bc97ddc7._.js → [root-of-the-server]__50208a5f._.js} +2 -2
  472. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__7b4dd49b._.js → [root-of-the-server]__508002e4._.js} +2 -2
  473. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__57b959fd._.js → [root-of-the-server]__5086c373._.js} +2 -2
  474. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__ce1f6530._.js → [root-of-the-server]__5913e097._.js} +2 -2
  475. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__a4823fef._.js → [root-of-the-server]__5b5f68d2._.js} +2 -2
  476. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__b9761ef0._.js → [root-of-the-server]__5c1f2459._.js} +3 -3
  477. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__aeb7413c._.js → [root-of-the-server]__5ec8c977._.js} +2 -2
  478. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__df6bc9e9._.js → [root-of-the-server]__5f8c694a._.js} +2 -2
  479. package/.next/standalone/.next/server/chunks/[root-of-the-server]__63cebc6c._.js +98 -0
  480. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__e85d0854._.js → [root-of-the-server]__64d30d4d._.js} +2 -2
  481. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__ce0bdfd8._.js → [root-of-the-server]__6c54fc2e._.js} +2 -2
  482. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__bc0ee8ae._.js → [root-of-the-server]__6dc1fb7e._.js} +2 -2
  483. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__91eb478b._.js → [root-of-the-server]__6e568102._.js} +2 -2
  484. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__c476045d._.js → [root-of-the-server]__6faa04c0._.js} +2 -2
  485. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__3aa57139._.js → [root-of-the-server]__727d05f1._.js} +2 -2
  486. package/.next/standalone/.next/server/chunks/[root-of-the-server]__74a34dc3._.js +98 -0
  487. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__8ca5cdb4._.js → [root-of-the-server]__75d12b32._.js} +2 -2
  488. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__05885ab1._.js → [root-of-the-server]__7e7250a4._.js} +2 -2
  489. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__9952246f._.js → [root-of-the-server]__8309e0a4._.js} +2 -2
  490. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__5e1e3386._.js → [root-of-the-server]__86cc0e2b._.js} +2 -2
  491. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1a211143._.js → [root-of-the-server]__8915603e._.js} +2 -2
  492. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__db7825cc._.js → [root-of-the-server]__89c2565a._.js} +2 -2
  493. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__b000379d._.js → [root-of-the-server]__8d178ad9._.js} +2 -2
  494. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__3ae85e7a._.js → [root-of-the-server]__93ee06f3._.js} +2 -2
  495. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__6a2926b6._.js → [root-of-the-server]__9e4c154a._.js} +2 -2
  496. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__31f028ec._.js → [root-of-the-server]__a1fbc199._.js} +2 -2
  497. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__aa7644c6._.js → [root-of-the-server]__a9d2e1d3._.js} +2 -2
  498. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__b60a5497._.js → [root-of-the-server]__ae53d343._.js} +2 -2
  499. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__f5f82d4b._.js → [root-of-the-server]__b3a04cef._.js} +2 -2
  500. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b4270b77._.js +3 -0
  501. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__dd9f454c._.js → [root-of-the-server]__b6b6ce60._.js} +2 -2
  502. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b9545dd9._.js +3 -0
  503. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__41ae8be6._.js → [root-of-the-server]__c200e21a._.js} +2 -2
  504. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__190b05d8._.js → [root-of-the-server]__c3c74ca4._.js} +2 -2
  505. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c88b63f7._.js +98 -0
  506. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__6c674ff1._.js → [root-of-the-server]__cbf4ceb0._.js} +2 -2
  507. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__8d28317b._.js → [root-of-the-server]__cefdba2f._.js} +2 -2
  508. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0dd51116._.js → [root-of-the-server]__cf3c60c2._.js} +2 -2
  509. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__dae7832b._.js → [root-of-the-server]__cf9e82bb._.js} +2 -2
  510. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__de96c005._.js → [root-of-the-server]__d15515e3._.js} +2 -2
  511. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2367f5a6._.js → [root-of-the-server]__d2897392._.js} +2 -2
  512. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__7b4e92a1._.js → [root-of-the-server]__d3b2d856._.js} +2 -2
  513. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__81ece563._.js → [root-of-the-server]__d73273ca._.js} +2 -2
  514. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__a5b5007a._.js → [root-of-the-server]__d8417eb6._.js} +2 -2
  515. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__73409f3d._.js → [root-of-the-server]__db4726bc._.js} +2 -2
  516. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__17e04588._.js → [root-of-the-server]__dc2a55de._.js} +2 -2
  517. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__67c4abf3._.js → [root-of-the-server]__dc6e2e5f._.js} +2 -2
  518. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__4d225634._.js → [root-of-the-server]__e0d4690b._.js} +2 -2
  519. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e678dd53._.js +3 -0
  520. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__a3b0b968._.js → [root-of-the-server]__e9223f55._.js} +2 -2
  521. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__91522ce2._.js → [root-of-the-server]__ea630076._.js} +2 -2
  522. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0644670b._.js → [root-of-the-server]__eb8acb65._.js} +2 -2
  523. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__bbdbb0e1._.js → [root-of-the-server]__eee4c5e8._.js} +2 -2
  524. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2a21471b._.js → [root-of-the-server]__f26ca49d._.js} +2 -2
  525. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__6c15c973._.js → [root-of-the-server]__f33e1101._.js} +2 -2
  526. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__5bbc73ff._.js → [root-of-the-server]__f3a4c668._.js} +2 -2
  527. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2bfbbec2._.js → [root-of-the-server]__f515f865._.js} +2 -2
  528. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fceb5d60._.js +98 -0
  529. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__d9c653fc._.js → [root-of-the-server]__fed41403._.js} +2 -2
  530. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__c09d4b86._.js → [root-of-the-server]__ff2e98c2._.js} +2 -2
  531. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_assess_route_actions_3e8ef2a6.js +3 -0
  532. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_publish_route_actions_49238be3.js +3 -0
  533. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_refine_route_actions_05675688.js +3 -0
  534. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_review_route_actions_5cbb5f6b.js +3 -0
  535. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_seed_route_actions_21084bdb.js +3 -0
  536. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_marketplace_browse_route_actions_7ed0768c.js +3 -0
  537. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_marketplace_preview_route_actions_38d4cc17.js +3 -0
  538. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_updates_route_actions_91efaab5.js +3 -0
  539. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__23f374a2._.js +3 -0
  540. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
  541. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__efef0a06._.js → [root-of-the-server]__ca5beb09._.js} +2 -2
  542. package/.next/standalone/.next/server/chunks/ssr/{_b4db3983._.js → _01842037._.js} +2 -2
  543. package/.next/standalone/.next/server/chunks/ssr/{_7dd2ac82._.js → _036cbaa2._.js} +1 -1
  544. package/.next/standalone/.next/server/chunks/ssr/_10c0d382._.js +3 -0
  545. package/.next/standalone/.next/server/chunks/ssr/_163d0838._.js +3 -0
  546. package/.next/standalone/.next/server/chunks/ssr/{_9303a965._.js → _43455582._.js} +1 -1
  547. package/.next/standalone/.next/server/chunks/ssr/{_7e63066a._.js → _67887e33._.js} +2 -2
  548. package/.next/standalone/.next/server/chunks/ssr/_950142a4._.js +1 -1
  549. package/.next/standalone/.next/server/chunks/ssr/src_02bae6e5._.js +3 -0
  550. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_terminal_page_tsx_de5e8d85._.js +2 -2
  551. package/.next/standalone/.next/server/edge/chunks/_d73df637._.js +1 -1
  552. package/.next/standalone/.next/server/middleware-manifest.json +1 -1
  553. package/.next/standalone/.next/server/pages/404.html +1 -1
  554. package/.next/standalone/.next/server/pages/500.html +2 -2
  555. package/.next/standalone/.next/static/chunks/{a7b2795949a6c63e.js → 224aab5107987011.js} +2 -2
  556. package/.next/standalone/.next/static/chunks/415827af44b8c374.js +1 -0
  557. package/.next/standalone/.next/static/chunks/8a7f58872c123a53.css +3 -0
  558. package/.next/standalone/.next/static/chunks/b0484608571d975a.js +1 -0
  559. package/.next/standalone/.next/static/chunks/{e35e863c09511a51.js → b42a38df3e418ff0.js} +1 -1
  560. package/.next/standalone/.next/static/chunks/{0e61e67b7b8fc3f3.js → c418112e102673ce.js} +1 -1
  561. package/.next/standalone/.next/static/chunks/d6474f65a17c483e.js +1 -0
  562. package/.next/standalone/.next/static/chunks/e2f0a2330dedff4b.js +85 -0
  563. package/.next/standalone/.next/static/chunks/f0c8b3f8cc1939ec.js +1 -0
  564. package/.next/standalone/docs/superpowers/plans/2026-03-18-cortex-ui-integration.md +1846 -0
  565. package/.next/standalone/docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md +341 -0
  566. package/.next/standalone/package.json +1 -1
  567. package/.next/standalone/src/app/(desktop)/cortex/page.tsx +7 -4
  568. package/.next/standalone/src/app/api/cortex/curation/assess/route.ts +27 -0
  569. package/.next/standalone/src/app/api/cortex/curation/publish/route.ts +23 -0
  570. package/.next/standalone/src/app/api/cortex/curation/refine/route.ts +23 -0
  571. package/.next/standalone/src/app/api/cortex/curation/review/route.ts +29 -0
  572. package/.next/standalone/src/app/api/cortex/curation/seed/route.ts +23 -0
  573. package/.next/standalone/src/app/api/cortex/graph/populate/route.ts +3 -3
  574. package/.next/standalone/src/app/api/cortex/import/route.ts +51 -19
  575. package/.next/standalone/src/app/api/cortex/marketplace/browse/route.ts +43 -0
  576. package/.next/standalone/src/app/api/cortex/marketplace/preview/route.ts +46 -0
  577. package/.next/standalone/src/app/api/cortex/status/route.ts +40 -0
  578. package/.next/standalone/src/components/cortex/constants.ts +29 -0
  579. package/.next/standalone/src/components/cortex/cortex-dashboard.tsx +80 -4
  580. package/.next/standalone/src/components/cortex/curation-tab.tsx +810 -0
  581. package/.next/standalone/src/components/cortex/import-dialog.tsx +212 -0
  582. package/.next/standalone/src/components/cortex/knowledge-card.tsx +1 -19
  583. package/.next/standalone/src/components/cortex/knowledge-tab.tsx +103 -1
  584. package/.next/standalone/src/components/cortex/lobe-settings.tsx +16 -0
  585. package/.next/standalone/src/components/cortex/marketplace-card.tsx +126 -0
  586. package/.next/standalone/src/components/cortex/marketplace-tab.tsx +113 -0
  587. package/.next/standalone/src/lib/cortex/types.ts +1 -0
  588. package/bin/spaces-service.js +21 -9
  589. package/bin/spaces.js +85 -12
  590. package/bin/terminal-server.js +13 -2
  591. package/package.json +1 -1
  592. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d85c4a8b._.js +0 -98
  593. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ecce08b._.js +0 -3
  594. package/.next/standalone/.next/server/chunks/ssr/_cd50a174._.js +0 -3
  595. package/.next/standalone/.next/server/chunks/ssr/_e7a9e2b0._.js +0 -3
  596. package/.next/standalone/.next/server/chunks/ssr/src_133a7c8a._.js +0 -3
  597. package/.next/standalone/.next/static/chunks/441b03060c26dfd8.css +0 -3
  598. package/.next/standalone/.next/static/chunks/58d78765e5140dcb.js +0 -1
  599. package/.next/standalone/.next/static/chunks/78dd908e70bf8c4b.js +0 -85
  600. package/.next/standalone/.next/static/chunks/9196173f0d081f2c.js +0 -1
  601. package/.next/standalone/.next/static/chunks/9bd8a119aaeafc9e.js +0 -1
  602. package/.next/standalone/src/components/cortex/context-tab.tsx +0 -171
  603. /package/.next/standalone/.next/static/{L3G_bc6BtAETwbN4_gS1c → Ku7_sP1T1UuqtRhUTiJZw}/_buildManifest.js +0 -0
  604. /package/.next/standalone/.next/static/{L3G_bc6BtAETwbN4_gS1c → Ku7_sP1T1UuqtRhUTiJZw}/_clientMiddlewareManifest.json +0 -0
  605. /package/.next/standalone/.next/static/{L3G_bc6BtAETwbN4_gS1c → Ku7_sP1T1UuqtRhUTiJZw}/_ssgManifest.js +0 -0
@@ -0,0 +1,1846 @@
1
+ # Cortex UI Integration — Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Integrate @spaces/cortex curation, marketplace, quality dashboard, and domain context features into the Spaces UI with 6-tab Cortex page layout.
6
+
7
+ **Architecture:** Extend existing Cortex page (5 tabs → 6 tabs), add API routes that proxy to addon MCP tool handlers, build new UI components following established patterns (client components, `api()` helper, Tailwind dark theme, lucide-react icons).
8
+
9
+ **Tech Stack:** Next.js 15, React 19, TypeScript, Tailwind CSS, lucide-react
10
+
11
+ **Spec:** `docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md`
12
+
13
+ ---
14
+
15
+ ### Task 1: Extract Shared Constants
16
+
17
+ **Files:**
18
+ - Create: `src/components/cortex/constants.ts`
19
+ - Modify: `src/components/cortex/knowledge-card.tsx:6-16`
20
+ - Modify: `src/components/cortex/context-tab.tsx:18-28`
21
+
22
+ - [ ] **Step 1: Create the shared constants file**
23
+
24
+ ```typescript
25
+ // src/components/cortex/constants.ts
26
+ export const TYPE_COLORS: Record<string, string> = {
27
+ decision: 'bg-blue-500/20 text-blue-400',
28
+ preference: 'bg-pink-500/20 text-pink-400',
29
+ pattern: 'bg-green-500/20 text-green-400',
30
+ error_fix: 'bg-amber-500/20 text-amber-400',
31
+ context: 'bg-gray-500/20 text-gray-400',
32
+ code_pattern: 'bg-cyan-500/20 text-cyan-400',
33
+ command: 'bg-orange-500/20 text-orange-400',
34
+ conversation: 'bg-slate-500/20 text-slate-400',
35
+ summary: 'bg-violet-500/20 text-violet-400',
36
+ };
37
+
38
+ export const SENSITIVITY_COLORS: Record<string, string> = {
39
+ public: 'bg-green-500/20 text-green-400',
40
+ internal: 'bg-indigo-500/20 text-indigo-400',
41
+ restricted: 'bg-amber-500/20 text-amber-400',
42
+ confidential: 'bg-red-500/20 text-red-400',
43
+ };
44
+
45
+ export const INTENT_COLORS: Record<string, string> = {
46
+ debugging: 'text-red-400',
47
+ architecture: 'text-blue-400',
48
+ onboarding: 'text-green-400',
49
+ policy: 'text-purple-400',
50
+ 'how-to': 'text-amber-400',
51
+ review: 'text-pink-400',
52
+ security: 'text-red-500',
53
+ general: 'text-gray-400',
54
+ };
55
+ ```
56
+
57
+ - [ ] **Step 2: Update knowledge-card.tsx to import from constants**
58
+
59
+ Replace the local `TYPE_COLORS` and `SENSITIVITY_COLORS` definitions (lines 6-23) with:
60
+ ```typescript
61
+ import { TYPE_COLORS, SENSITIVITY_COLORS } from './constants';
62
+ ```
63
+
64
+ - [ ] **Step 3: Update context-tab.tsx to import from constants**
65
+
66
+ Replace the local `INTENT_COLORS` and `TYPE_COLORS` definitions (lines 7-28) with:
67
+ ```typescript
68
+ import { INTENT_COLORS, TYPE_COLORS } from './constants';
69
+ ```
70
+
71
+ - [ ] **Step 4: Verify build**
72
+
73
+ Run: `npx next build 2>&1 | tail -5`
74
+ Expected: Build succeeds with no errors
75
+
76
+ - [ ] **Step 5: Commit**
77
+
78
+ ```bash
79
+ git add src/components/cortex/constants.ts src/components/cortex/knowledge-card.tsx src/components/cortex/context-tab.tsx
80
+ git commit -m "refactor(cortex): extract shared color constants"
81
+ ```
82
+
83
+ ---
84
+
85
+ ### Task 2: Add domain_context to LobeConfig Type
86
+
87
+ **Files:**
88
+ - Modify: `src/lib/cortex/types.ts:23-38`
89
+
90
+ - [ ] **Step 1: Add domain_context field**
91
+
92
+ In `src/lib/cortex/types.ts`, add `domain_context?: string;` to the `LobeConfig` interface after `isPrivate`:
93
+
94
+ ```typescript
95
+ export interface LobeConfig {
96
+ tags: string[];
97
+ excludeTags: string[];
98
+ excludedFrom: number[];
99
+ subscriptions: string[];
100
+ private: boolean;
101
+ isPrivate?: boolean;
102
+ domain_context?: string;
103
+ }
104
+ ```
105
+
106
+ No change to `DEFAULT_LOBE_CONFIG` — the field is optional and defaults to undefined.
107
+
108
+ - [ ] **Step 2: Verify build**
109
+
110
+ Run: `npx next build 2>&1 | tail -5`
111
+ Expected: Build succeeds
112
+
113
+ - [ ] **Step 3: Commit**
114
+
115
+ ```bash
116
+ git add src/lib/cortex/types.ts
117
+ git commit -m "feat(cortex): add domain_context to LobeConfig type"
118
+ ```
119
+
120
+ ---
121
+
122
+ ### Task 3: Add Domain Context to Lobe Settings UI
123
+
124
+ **Files:**
125
+ - Modify: `src/components/cortex/lobe-settings.tsx`
126
+
127
+ - [ ] **Step 1: Add domain context state and textarea**
128
+
129
+ After the tags section (after the closing `</div>` of the tags `space-y-1.5` div, around line 155), add:
130
+
131
+ ```tsx
132
+ {/* Domain context */}
133
+ <div className="space-y-1.5">
134
+ <div className="text-[10px] text-zinc-500">
135
+ Domain Context
136
+ <span className="text-zinc-700 ml-1">— injected into distillation prompts for better extraction</span>
137
+ </div>
138
+ <textarea
139
+ value={config.domain_context || ''}
140
+ onChange={e => save({ domain_context: e.target.value })}
141
+ placeholder="Describe the domain expertise this lobe should focus on. E.g. 'This workspace covers CFB power plant engineering.'"
142
+ rows={3}
143
+ disabled={saving}
144
+ className="w-full px-2 py-1.5 bg-zinc-800 border border-zinc-700 rounded text-[11px] text-zinc-300 placeholder-zinc-600 focus:outline-none focus:border-purple-500/50 resize-y disabled:opacity-50"
145
+ />
146
+ </div>
147
+ ```
148
+
149
+ - [ ] **Step 2: Verify build**
150
+
151
+ Run: `npx next build 2>&1 | tail -5`
152
+ Expected: Build succeeds
153
+
154
+ - [ ] **Step 3: Commit**
155
+
156
+ ```bash
157
+ git add src/components/cortex/lobe-settings.tsx
158
+ git commit -m "feat(cortex): add domain context textarea to lobe settings"
159
+ ```
160
+
161
+ ---
162
+
163
+ ### Task 4: Extend Status API with Quality Data
164
+
165
+ **Files:**
166
+ - Modify: `src/app/api/cortex/status/route.ts`
167
+
168
+ - [ ] **Step 1: Add quality assessment to status response**
169
+
170
+ After the `graphStats` calculation (around line 114) and before the `return NextResponse.json(...)`, add:
171
+
172
+ ```typescript
173
+ // Quality assessment (aggregate across all lobes)
174
+ let quality = null;
175
+ try {
176
+ const addon = (await import('@/lib/cortex')).getCortexAddon?.();
177
+ if (addon?.assessLobe) {
178
+ // Get first workspace lobe for representative quality
179
+ const wsKeys = Object.keys(lobes).filter(k => k.startsWith('workspace/'));
180
+ if (wsKeys.length > 0) {
181
+ const wsId = parseInt(wsKeys[0].split('/')[1], 10);
182
+ quality = await addon.assessLobe(cortex.store, wsId);
183
+ }
184
+ }
185
+ } catch { /* addon doesn't support assess yet */ }
186
+
187
+ // Fallback: build quality from available data if addon doesn't have assessLobe
188
+ if (!quality) {
189
+ // Compute type distribution and sensitivity counts from browse data
190
+ const allUnits: any[] = [];
191
+ for (const layerKey of Object.keys(lobes)) {
192
+ try {
193
+ const items = await cortex.store.browse(layerKey, 100);
194
+ allUnits.push(...items);
195
+ } catch { /* skip */ }
196
+ }
197
+ if (allUnits.length > 0) {
198
+ const typeDist: Record<string, number> = {};
199
+ const sensCounts: Record<string, number> = {};
200
+ let confSum = 0;
201
+ let staleCount = 0;
202
+ for (const u of allUnits) {
203
+ typeDist[u.type] = (typeDist[u.type] || 0) + 1;
204
+ const sens = u.sensitivity || 'internal';
205
+ sensCounts[sens] = (sensCounts[sens] || 0) + 1;
206
+ confSum += u.confidence ?? 0;
207
+ if ((u.stale_score ?? 0) > 0.5) staleCount++;
208
+ }
209
+ const distilled = (typeDist.decision || 0) + (typeDist.pattern || 0) + (typeDist.preference || 0) + (typeDist.error_fix || 0);
210
+ quality = {
211
+ coverage_score: allUnits.length > 0 ? distilled / allUnits.length : 0,
212
+ type_distribution: typeDist,
213
+ avg_confidence: allUnits.length > 0 ? confSum / allUnits.length : 0,
214
+ stale_count: staleCount,
215
+ sensitivity_counts: sensCounts,
216
+ top_accessed: allUnits
217
+ .filter(u => (u.access_count ?? 0) > 0)
218
+ .sort((a, b) => (b.access_count ?? 0) - (a.access_count ?? 0))
219
+ .slice(0, 3)
220
+ .map(u => ({ text: u.text?.slice(0, 120), type: u.type, access_count: u.access_count })),
221
+ };
222
+ }
223
+ }
224
+ ```
225
+
226
+ Then update the return statement to include `quality`:
227
+
228
+ ```typescript
229
+ return NextResponse.json({
230
+ enabled: true,
231
+ status: 'healthy',
232
+ embedding_provider: cortex.embedding.name,
233
+ embedding_dimensions: cortex.embedding.dimensions,
234
+ distillation: config.ingestion?.distillation ?? false,
235
+ lobes,
236
+ totalCount,
237
+ totalSizeBytes,
238
+ usage,
239
+ graph: graphStats,
240
+ quality,
241
+ });
242
+ ```
243
+
244
+ - [ ] **Step 2: Verify build**
245
+
246
+ Run: `npx next build 2>&1 | tail -5`
247
+ Expected: Build succeeds
248
+
249
+ - [ ] **Step 3: Commit**
250
+
251
+ ```bash
252
+ git add src/app/api/cortex/status/route.ts
253
+ git commit -m "feat(cortex): add quality assessment data to status API"
254
+ ```
255
+
256
+ ---
257
+
258
+ ### Task 5: Enhance Dashboard with Quality Panels
259
+
260
+ **Files:**
261
+ - Modify: `src/components/cortex/cortex-dashboard.tsx`
262
+
263
+ - [ ] **Step 1: Import shared constants**
264
+
265
+ Add at the top of the file:
266
+ ```typescript
267
+ import { TYPE_COLORS, SENSITIVITY_COLORS } from './constants';
268
+ ```
269
+
270
+ - [ ] **Step 2: Update StatusData interface**
271
+
272
+ Add `quality` to the interface (after line 33):
273
+ ```typescript
274
+ quality: {
275
+ coverage_score: number;
276
+ type_distribution: Record<string, number>;
277
+ avg_confidence: number;
278
+ stale_count: number;
279
+ sensitivity_counts: Record<string, number>;
280
+ top_accessed: Array<{ text: string; type: string; access_count: number }>;
281
+ } | null;
282
+ ```
283
+
284
+ - [ ] **Step 3: Replace Graph stat card with Coverage Score**
285
+
286
+ Replace the Graph `StatCard` (around line 117-121) with:
287
+ ```tsx
288
+ <StatCard
289
+ label="Coverage"
290
+ value={data.quality ? data.quality.coverage_score.toFixed(2) : '—'}
291
+ sub={data.quality ? `${Math.round(data.quality.coverage_score * 100)}% distilled` : 'no data'}
292
+ color={data.quality
293
+ ? data.quality.coverage_score > 0.7 ? 'text-green-400'
294
+ : data.quality.coverage_score > 0.3 ? 'text-amber-400'
295
+ : 'text-red-400'
296
+ : 'text-gray-500'}
297
+ />
298
+ ```
299
+
300
+ - [ ] **Step 4: Add Type Distribution and Lobe Health panels**
301
+
302
+ After the existing lobe breakdown section (before the distillation detail section), add:
303
+
304
+ ```tsx
305
+ {/* Quality panels */}
306
+ {data.quality && (
307
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
308
+ {/* Type distribution */}
309
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-4">
310
+ <h3 className="text-xs font-medium text-gray-400 mb-3">Type Distribution</h3>
311
+ <BarChart
312
+ items={Object.entries(data.quality.type_distribution)
313
+ .sort((a, b) => b[1] - a[1])
314
+ .map(([type, count]) => ({
315
+ label: type.replace('_', ' '),
316
+ value: count,
317
+ color: TYPE_HEX[type] || '#7c3aed',
318
+ }))
319
+ }
320
+ maxValue={Math.max(...Object.values(data.quality.type_distribution), 1)}
321
+ />
322
+ </div>
323
+
324
+ {/* Lobe health */}
325
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-4">
326
+ <h3 className="text-xs font-medium text-gray-400 mb-3">Lobe Health</h3>
327
+ <div className="space-y-3">
328
+ <div className="flex justify-between text-[11px]">
329
+ <span className="text-gray-500">Stale units</span>
330
+ <span className={data.quality.stale_count > 10 ? 'text-amber-400' : 'text-gray-300'}>
331
+ {data.quality.stale_count}
332
+ </span>
333
+ </div>
334
+ <div className="flex justify-between text-[11px]">
335
+ <span className="text-gray-500">Avg confidence</span>
336
+ <span className="text-gray-300">{data.quality.avg_confidence.toFixed(2)}</span>
337
+ </div>
338
+ {data.quality.top_accessed.length > 0 && (
339
+ <div>
340
+ <div className="text-[10px] text-gray-500 mb-1">Top accessed</div>
341
+ <div className="text-[11px] text-gray-400 truncate">
342
+ &ldquo;{data.quality.top_accessed[0].text}&rdquo;
343
+ </div>
344
+ </div>
345
+ )}
346
+ {data.quality.sensitivity_counts && (
347
+ <div>
348
+ <div className="text-[10px] text-gray-500 mb-1">Sensitivity</div>
349
+ <div className="flex flex-wrap gap-1">
350
+ {Object.entries(data.quality.sensitivity_counts).map(([level, count]) => (
351
+ <span key={level} className={`text-[9px] px-1.5 py-0.5 rounded ${SENSITIVITY_COLORS[level] || SENSITIVITY_COLORS.internal}`}>
352
+ {count} {level}
353
+ </span>
354
+ ))}
355
+ </div>
356
+ </div>
357
+ )}
358
+ </div>
359
+ </div>
360
+ </div>
361
+ )}
362
+ ```
363
+
364
+ Add `TYPE_HEX` as a const inside the component (after the `LOBE_COLORS` array) since BarChart uses inline styles, not Tailwind classes:
365
+ ```typescript
366
+ const TYPE_HEX: Record<string, string> = {
367
+ decision: '#3b82f6', pattern: '#22c55e', preference: '#ec4899',
368
+ error_fix: '#f59e0b', context: '#6b7280', code_pattern: '#06b6d4',
369
+ command: '#f97316', conversation: '#64748b', summary: '#8b5cf6',
370
+ };
371
+ ```
372
+
373
+ - [ ] **Step 5: Verify build**
374
+
375
+ Run: `npx next build 2>&1 | tail -5`
376
+ Expected: Build succeeds
377
+
378
+ - [ ] **Step 6: Commit**
379
+
380
+ ```bash
381
+ git add src/components/cortex/cortex-dashboard.tsx
382
+ git commit -m "feat(cortex): add quality panels to dashboard"
383
+ ```
384
+
385
+ ---
386
+
387
+ ### Task 6: Merge Context Tab into Knowledge Tab
388
+
389
+ **Files:**
390
+ - Modify: `src/components/cortex/knowledge-tab.tsx`
391
+ - Delete: `src/components/cortex/context-tab.tsx`
392
+
393
+ - [ ] **Step 1: Add query analyzer section to knowledge-tab.tsx**
394
+
395
+ Add state and imports at the top:
396
+ ```typescript
397
+ import { useState, useCallback, useEffect } from 'react';
398
+ import { Search, ChevronDown, ChevronUp } from 'lucide-react';
399
+ import { api } from '@/lib/api';
400
+ import { KnowledgeCard } from './knowledge-card';
401
+ import { TYPE_COLORS, INTENT_COLORS } from './constants';
402
+ ```
403
+
404
+ Add state for the analyzer:
405
+ ```typescript
406
+ const [analyzerOpen, setAnalyzerOpen] = useState(false);
407
+ const [analyzerQuery, setAnalyzerQuery] = useState('');
408
+ const [analyzerResult, setAnalyzerResult] = useState<any>(null);
409
+ const [analyzerLoading, setAnalyzerLoading] = useState(false);
410
+
411
+ const handleAnalyze = async () => {
412
+ if (!analyzerQuery.trim()) return;
413
+ setAnalyzerLoading(true);
414
+ try {
415
+ const res = await fetch(api(`/api/cortex/context?q=${encodeURIComponent(analyzerQuery)}&limit=5`));
416
+ if (res.ok) setAnalyzerResult(await res.json());
417
+ } catch {}
418
+ setAnalyzerLoading(false);
419
+ };
420
+ ```
421
+
422
+ After the knowledge cards `</div>` (end of the scrollable area), add a collapsible Query Analyzer section. Use the full content from `context-tab.tsx` lines 46-170, wrapped in a collapsible container:
423
+
424
+ ```tsx
425
+ {/* Query Analyzer */}
426
+ <div className="border-t border-white/5 mt-4 pt-4">
427
+ <button
428
+ onClick={() => setAnalyzerOpen(!analyzerOpen)}
429
+ className="flex items-center gap-2 text-xs text-gray-500 hover:text-gray-300 mb-3"
430
+ >
431
+ {analyzerOpen ? <ChevronUp className="w-3 h-3" /> : <ChevronDown className="w-3 h-3" />}
432
+ Query Analyzer
433
+ </button>
434
+ {analyzerOpen && (
435
+ <div className="max-w-2xl">
436
+ {/* Paste the context-tab query input and results display here */}
437
+ {/* Use analyzerQuery/analyzerResult/analyzerLoading state */}
438
+ {/* ... full context-tab content adapted to use analyzer* state variables ... */}
439
+ </div>
440
+ )}
441
+ </div>
442
+ ```
443
+
444
+ Copy the full JSX body from `context-tab.tsx` (the input, results grid, source weights, results list, conflicts, raw context sections) into the `{analyzerOpen && (...)}` block, replacing `query` → `analyzerQuery`, `result` → `analyzerResult`, `loading` → `analyzerLoading`, `handleAnalyze` stays the same name.
445
+
446
+ **Do NOT delete `context-tab.tsx` yet** — `page.tsx` still imports it. The file is removed in Task 11 when the page is updated to the 6-tab layout.
447
+
448
+ - [ ] **Step 2: Verify build**
449
+
450
+ Run: `npx next build 2>&1 | tail -5`
451
+ Expected: Build succeeds (context-tab.tsx still exists, page.tsx still imports it)
452
+
453
+ - [ ] **Step 3: Commit**
454
+
455
+ ```bash
456
+ git add src/components/cortex/knowledge-tab.tsx
457
+ git commit -m "feat(cortex): add query analyzer section to knowledge tab"
458
+ ```
459
+
460
+ ---
461
+
462
+ ### Task 7: Create Curation API Routes
463
+
464
+ **Files:**
465
+ - Create: `src/app/api/cortex/curation/seed/route.ts`
466
+ - Create: `src/app/api/cortex/curation/assess/route.ts`
467
+ - Create: `src/app/api/cortex/curation/review/route.ts`
468
+ - Create: `src/app/api/cortex/curation/refine/route.ts`
469
+ - Create: `src/app/api/cortex/curation/publish/route.ts`
470
+
471
+ All routes follow the same pattern: auth check → get cortex → proxy to addon's `handleToolCall`.
472
+
473
+ All 5 curation routes use `handleToolCall` from `@/lib/cortex/mcp/server` — the same pattern as the existing `/api/cortex/mcp/call` route. This function internally delegates to the addon.
474
+
475
+ - [ ] **Step 1: Create seed route**
476
+
477
+ ```typescript
478
+ // src/app/api/cortex/curation/seed/route.ts
479
+ import { NextResponse } from 'next/server';
480
+ import type { NextRequest } from 'next/server';
481
+ import { getAuthUser, withUser } from '@/lib/auth';
482
+ import { isCortexAvailable, getCortex } from '@/lib/cortex';
483
+ import { handleToolCall } from '@/lib/cortex/mcp/server';
484
+
485
+ export async function POST(request: NextRequest) {
486
+ const user = getAuthUser(request);
487
+ return withUser(user, async () => {
488
+ if (!isCortexAvailable()) {
489
+ return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
490
+ }
491
+ const cortex = await getCortex();
492
+ if (!cortex) return NextResponse.json({ error: 'Cortex disabled' }, { status: 503 });
493
+
494
+ const body = await request.json();
495
+ const result = await handleToolCall('cortex_seed', body, cortex);
496
+ if (result.isError) {
497
+ return NextResponse.json({ error: JSON.parse(result.content[0].text) }, { status: 400 });
498
+ }
499
+ return NextResponse.json(JSON.parse(result.content[0].text));
500
+ });
501
+ }
502
+ ```
503
+
504
+ - [ ] **Step 2: Create assess route**
505
+
506
+ ```typescript
507
+ // src/app/api/cortex/curation/assess/route.ts
508
+ import { NextResponse } from 'next/server';
509
+ import type { NextRequest } from 'next/server';
510
+ import { getAuthUser, withUser } from '@/lib/auth';
511
+ import { isCortexAvailable, getCortex } from '@/lib/cortex';
512
+ import { handleToolCall } from '@/lib/cortex/mcp/server';
513
+
514
+ export async function GET(request: NextRequest) {
515
+ const user = getAuthUser(request);
516
+ return withUser(user, async () => {
517
+ if (!isCortexAvailable()) {
518
+ return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
519
+ }
520
+ const cortex = await getCortex();
521
+ if (!cortex) return NextResponse.json({ error: 'Cortex disabled' }, { status: 503 });
522
+
523
+ const url = new URL(request.url);
524
+ const workspace_id = parseInt(url.searchParams.get('workspace_id') || '0', 10);
525
+ if (!workspace_id) {
526
+ return NextResponse.json({ error: 'workspace_id is required' }, { status: 400 });
527
+ }
528
+
529
+ const result = await handleToolCall('cortex_assess', { workspace_id }, cortex);
530
+ if (result.isError) {
531
+ return NextResponse.json({ error: JSON.parse(result.content[0].text) }, { status: 400 });
532
+ }
533
+ return NextResponse.json(JSON.parse(result.content[0].text));
534
+ });
535
+ }
536
+ ```
537
+
538
+ - [ ] **Step 3: Create review route**
539
+
540
+ ```typescript
541
+ // src/app/api/cortex/curation/review/route.ts
542
+ import { NextResponse } from 'next/server';
543
+ import type { NextRequest } from 'next/server';
544
+ import { getAuthUser, withUser } from '@/lib/auth';
545
+ import { isCortexAvailable, getCortex } from '@/lib/cortex';
546
+ import { handleToolCall } from '@/lib/cortex/mcp/server';
547
+
548
+ export async function GET(request: NextRequest) {
549
+ const user = getAuthUser(request);
550
+ return withUser(user, async () => {
551
+ if (!isCortexAvailable()) {
552
+ return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
553
+ }
554
+ const cortex = await getCortex();
555
+ if (!cortex) return NextResponse.json({ error: 'Cortex disabled' }, { status: 503 });
556
+
557
+ const url = new URL(request.url);
558
+ const workspace_id = parseInt(url.searchParams.get('workspace_id') || '0', 10);
559
+ const topic = url.searchParams.get('topic') || '';
560
+ const limit = parseInt(url.searchParams.get('limit') || '10', 10);
561
+
562
+ if (!workspace_id || !topic) {
563
+ return NextResponse.json({ error: 'workspace_id and topic are required' }, { status: 400 });
564
+ }
565
+
566
+ const result = await handleToolCall('cortex_review', { workspace_id, topic, limit }, cortex);
567
+ if (result.isError) {
568
+ return NextResponse.json({ error: JSON.parse(result.content[0].text) }, { status: 400 });
569
+ }
570
+ return NextResponse.json(JSON.parse(result.content[0].text));
571
+ });
572
+ }
573
+ ```
574
+
575
+ - [ ] **Step 4: Create refine route**
576
+
577
+ ```typescript
578
+ // src/app/api/cortex/curation/refine/route.ts
579
+ import { NextResponse } from 'next/server';
580
+ import type { NextRequest } from 'next/server';
581
+ import { getAuthUser, withUser } from '@/lib/auth';
582
+ import { isCortexAvailable, getCortex } from '@/lib/cortex';
583
+ import { handleToolCall } from '@/lib/cortex/mcp/server';
584
+
585
+ export async function POST(request: NextRequest) {
586
+ const user = getAuthUser(request);
587
+ return withUser(user, async () => {
588
+ if (!isCortexAvailable()) {
589
+ return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
590
+ }
591
+ const cortex = await getCortex();
592
+ if (!cortex) return NextResponse.json({ error: 'Cortex disabled' }, { status: 503 });
593
+
594
+ const body = await request.json();
595
+ const result = await handleToolCall('cortex_refine', body, cortex);
596
+ if (result.isError) {
597
+ return NextResponse.json({ error: JSON.parse(result.content[0].text) }, { status: 400 });
598
+ }
599
+ return NextResponse.json(JSON.parse(result.content[0].text));
600
+ });
601
+ }
602
+ ```
603
+
604
+ - [ ] **Step 5: Create publish route**
605
+
606
+ ```typescript
607
+ // src/app/api/cortex/curation/publish/route.ts
608
+ import { NextResponse } from 'next/server';
609
+ import type { NextRequest } from 'next/server';
610
+ import { getAuthUser, withUser } from '@/lib/auth';
611
+ import { isCortexAvailable, getCortex } from '@/lib/cortex';
612
+ import { handleToolCall } from '@/lib/cortex/mcp/server';
613
+
614
+ export async function POST(request: NextRequest) {
615
+ const user = getAuthUser(request);
616
+ return withUser(user, async () => {
617
+ if (!isCortexAvailable()) {
618
+ return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
619
+ }
620
+ const cortex = await getCortex();
621
+ if (!cortex) return NextResponse.json({ error: 'Cortex disabled' }, { status: 503 });
622
+
623
+ const body = await request.json();
624
+ const result = await handleToolCall('cortex_publish', body, cortex);
625
+ if (result.isError) {
626
+ return NextResponse.json({ error: JSON.parse(result.content[0].text) }, { status: 400 });
627
+ }
628
+ return NextResponse.json(JSON.parse(result.content[0].text));
629
+ });
630
+ }
631
+ ```
632
+
633
+ - [ ] **Step 6: Verify build**
634
+
635
+ Run: `npx next build 2>&1 | tail -5`
636
+ Expected: Build succeeds
637
+
638
+ - [ ] **Step 7: Commit**
639
+
640
+ ```bash
641
+ git add src/app/api/cortex/curation/
642
+ git commit -m "feat(cortex): add curation API routes (seed/assess/review/refine/publish)"
643
+ ```
644
+
645
+ ---
646
+
647
+ ### Task 8: Create Marketplace API Routes
648
+
649
+ **Files:**
650
+ - Create: `src/app/api/cortex/marketplace/browse/route.ts`
651
+ - Create: `src/app/api/cortex/marketplace/preview/route.ts`
652
+ - Modify: `src/app/api/cortex/import/route.ts`
653
+
654
+ - [ ] **Step 1: Create browse route**
655
+
656
+ ```typescript
657
+ // src/app/api/cortex/marketplace/browse/route.ts
658
+ import { NextResponse } from 'next/server';
659
+ import type { NextRequest } from 'next/server';
660
+ import { getAuthUser, withUser } from '@/lib/auth';
661
+ import { getUserPaths } from '@/lib/config';
662
+ import fs from 'fs';
663
+ import path from 'path';
664
+ import { execSync } from 'child_process';
665
+
666
+ export async function GET(request: NextRequest) {
667
+ const user = getAuthUser(request);
668
+ return withUser(user, async () => {
669
+ const { spacesDir } = getUserPaths(user);
670
+ const marketDir = path.join(spacesDir, 'cortex', 'marketplace');
671
+
672
+ // Create directory if it doesn't exist
673
+ if (!fs.existsSync(marketDir)) {
674
+ fs.mkdirSync(marketDir, { recursive: true });
675
+ return NextResponse.json({ packs: [], directory: marketDir });
676
+ }
677
+
678
+ const files = fs.readdirSync(marketDir).filter(f => f.endsWith('.cortexpack'));
679
+ const packs: any[] = [];
680
+
681
+ for (const filename of files) {
682
+ try {
683
+ const filePath = path.join(marketDir, filename);
684
+ // Extract manifest.json from the tar.gz without full unpack
685
+ const stdout = execSync(
686
+ `tar -xzf "${filePath}" -O manifest.json 2>/dev/null`,
687
+ { encoding: 'utf-8', timeout: 5000 }
688
+ );
689
+ const manifest = JSON.parse(stdout);
690
+ packs.push({ filename, manifest });
691
+ } catch {
692
+ // Can't read manifest — list it with minimal info
693
+ const stat = fs.statSync(path.join(marketDir, filename));
694
+ packs.push({
695
+ filename,
696
+ manifest: {
697
+ version: 'unknown',
698
+ exportDate: stat.mtime.toISOString(),
699
+ unitCount: 0,
700
+ },
701
+ });
702
+ }
703
+ }
704
+
705
+ return NextResponse.json({ packs, directory: marketDir });
706
+ });
707
+ }
708
+ ```
709
+
710
+ - [ ] **Step 2: Create preview route**
711
+
712
+ ```typescript
713
+ // src/app/api/cortex/marketplace/preview/route.ts
714
+ import { NextResponse } from 'next/server';
715
+ import type { NextRequest } from 'next/server';
716
+ import { getAuthUser, withUser } from '@/lib/auth';
717
+ import { getUserPaths } from '@/lib/config';
718
+ import fs from 'fs';
719
+ import path from 'path';
720
+ import { execSync } from 'child_process';
721
+
722
+ export async function GET(request: NextRequest) {
723
+ const user = getAuthUser(request);
724
+ return withUser(user, async () => {
725
+ const url = new URL(request.url);
726
+ const filename = url.searchParams.get('file');
727
+ if (!filename) {
728
+ return NextResponse.json({ error: 'file parameter required' }, { status: 400 });
729
+ }
730
+
731
+ // Sanitize filename — prevent path traversal
732
+ const safe = path.basename(filename);
733
+ if (!safe.endsWith('.cortexpack')) {
734
+ return NextResponse.json({ error: 'Invalid file' }, { status: 400 });
735
+ }
736
+
737
+ const { spacesDir } = getUserPaths(user);
738
+ const filePath = path.join(spacesDir, 'cortex', 'marketplace', safe);
739
+ if (!fs.existsSync(filePath)) {
740
+ return NextResponse.json({ error: 'Pack not found' }, { status: 404 });
741
+ }
742
+
743
+ try {
744
+ // Extract first 5 lines of knowledge.jsonl for preview
745
+ const stdout = execSync(
746
+ `tar -xzf "${filePath}" -O knowledge.jsonl 2>/dev/null | head -5`,
747
+ { encoding: 'utf-8', timeout: 10000 }
748
+ );
749
+ const samples = stdout.trim().split('\n')
750
+ .filter(Boolean)
751
+ .map(line => {
752
+ try { const u = JSON.parse(line); return { text: u.text?.slice(0, 200), type: u.type }; }
753
+ catch { return null; }
754
+ })
755
+ .filter(Boolean);
756
+ return NextResponse.json({ samples });
757
+ } catch {
758
+ return NextResponse.json({ samples: [] });
759
+ }
760
+ });
761
+ }
762
+ ```
763
+
764
+ - [ ] **Step 3: Update import route to support both FormData uploads and JSON marketplace imports**
765
+
766
+ Replace the entire `src/app/api/cortex/import/route.ts`:
767
+
768
+ ```typescript
769
+ import { NextResponse } from 'next/server';
770
+ import type { NextRequest } from 'next/server';
771
+ import path from 'path';
772
+ import fs from 'fs';
773
+ import os from 'os';
774
+ import { getAuthUser, withUser } from '@/lib/auth';
775
+ import { isCortexAvailable, getCortex } from '@/lib/cortex';
776
+ import { importCortexpack } from '@/lib/cortex/portability/importer';
777
+ import { getUserPaths } from '@/lib/config';
778
+
779
+ export async function POST(request: NextRequest) {
780
+ const user = getAuthUser(request);
781
+ return withUser(user, async () => {
782
+ if (!isCortexAvailable()) {
783
+ return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
784
+ }
785
+ const cortex = await getCortex();
786
+ if (!cortex) return NextResponse.json({ error: 'Cortex disabled' }, { status: 503 });
787
+
788
+ const contentType = request.headers.get('content-type') || '';
789
+ let packPath: string;
790
+ let cleanup = false;
791
+
792
+ if (contentType.includes('application/json')) {
793
+ // JSON mode: import from marketplace directory by filename
794
+ const body = await request.json();
795
+ const filename = body.marketplace_file;
796
+ if (!filename) {
797
+ return NextResponse.json({ error: 'marketplace_file is required' }, { status: 400 });
798
+ }
799
+ const safe = path.basename(filename);
800
+ const { spacesDir } = getUserPaths(user);
801
+ packPath = path.join(spacesDir, 'cortex', 'marketplace', safe);
802
+ if (!fs.existsSync(packPath)) {
803
+ return NextResponse.json({ error: 'Pack not found' }, { status: 404 });
804
+ }
805
+
806
+ const targetLayer = body.target_layer || 'workspace';
807
+ const workspaceId = body.workspace_id;
808
+ const effectiveLayer = targetLayer === 'workspace' && workspaceId
809
+ ? `workspace/${workspaceId}` : targetLayer;
810
+
811
+ importCortexpack(packPath, cortex.store, cortex.embedding, {
812
+ targetLayer: effectiveLayer,
813
+ mergeStrategy: (body.merge_strategy || 'merge') as any,
814
+ reEmbed: body.re_embed ?? false,
815
+ });
816
+ return NextResponse.json({ status: 'started' });
817
+
818
+ } else {
819
+ // FormData mode: file upload (existing behavior)
820
+ const formData = await request.formData();
821
+ const file = formData.get('file') as File;
822
+ if (!file) {
823
+ return NextResponse.json({ error: 'No file uploaded' }, { status: 400 });
824
+ }
825
+
826
+ const tmpPath = path.join(os.tmpdir(), `cortex-import-${Date.now()}.cortexpack`);
827
+ const bytes = await file.arrayBuffer();
828
+ fs.writeFileSync(tmpPath, Buffer.from(bytes));
829
+
830
+ const targetLayer = (formData.get('target_layer') as string) || 'workspace';
831
+ const mergeStrategy = (formData.get('merge_strategy') as string) || 'merge';
832
+ const reEmbed = formData.get('re_embed') === 'true';
833
+ const workspaceId = formData.get('workspace_id') as string | null;
834
+ const effectiveLayer = targetLayer === 'workspace' && workspaceId
835
+ ? `workspace/${workspaceId}` : targetLayer;
836
+
837
+ importCortexpack(tmpPath, cortex.store, cortex.embedding, {
838
+ targetLayer: effectiveLayer,
839
+ mergeStrategy: mergeStrategy as any,
840
+ reEmbed,
841
+ }).finally(() => {
842
+ try { fs.unlinkSync(tmpPath); } catch { /* ignore */ }
843
+ });
844
+ return NextResponse.json({ status: 'started' });
845
+ }
846
+ });
847
+ }
848
+ ```
849
+ ```
850
+
851
+ - [ ] **Step 4: Verify build**
852
+
853
+ Run: `npx next build 2>&1 | tail -5`
854
+ Expected: Build succeeds
855
+
856
+ - [ ] **Step 5: Commit**
857
+
858
+ ```bash
859
+ git add src/app/api/cortex/marketplace/ src/app/api/cortex/import/route.ts
860
+ git commit -m "feat(cortex): add marketplace browse/preview APIs, update import route"
861
+ ```
862
+
863
+ ---
864
+
865
+ ### Task 9: Build Curation Tab Component
866
+
867
+ **Files:**
868
+ - Create: `src/components/cortex/curation-tab.tsx`
869
+
870
+ - [ ] **Step 1: Create the curation tab with pipeline bar and all 5 steps**
871
+
872
+ ```typescript
873
+ // src/components/cortex/curation-tab.tsx
874
+ 'use client';
875
+
876
+ import { useState, useEffect } from 'react';
877
+ import { Upload, BarChart3, Search, RefreshCw, Package, Loader2 } from 'lucide-react';
878
+ import { api } from '@/lib/api';
879
+ import { TYPE_COLORS } from './constants';
880
+
881
+ type Step = 'seed' | 'assess' | 'review' | 'refine' | 'publish';
882
+
883
+ const STEPS: { key: Step; label: string; icon: any }[] = [
884
+ { key: 'seed', label: 'Seed', icon: Upload },
885
+ { key: 'assess', label: 'Assess', icon: BarChart3 },
886
+ { key: 'review', label: 'Review', icon: Search },
887
+ { key: 'refine', label: 'Refine', icon: RefreshCw },
888
+ { key: 'publish', label: 'Publish', icon: Package },
889
+ ];
890
+
891
+ interface Workspace { id: number; name: string; color: string }
892
+
893
+ export function CurationTab() {
894
+ const [step, setStep] = useState<Step>('seed');
895
+ const [workspaces, setWorkspaces] = useState<Workspace[]>([]);
896
+ const [workspaceId, setWorkspaceId] = useState<number>(0);
897
+ const [loading, setLoading] = useState(false);
898
+ const [error, setError] = useState<string | null>(null);
899
+ const [result, setResult] = useState<any>(null);
900
+
901
+ // Seed state
902
+ const [seedText, setSeedText] = useState('');
903
+ const [seedFormat, setSeedFormat] = useState('auto');
904
+ const [seedSource, setSeedSource] = useState('');
905
+ const [seedDistill, setSeedDistill] = useState(true);
906
+
907
+ // Review state
908
+ const [reviewTopic, setReviewTopic] = useState('');
909
+ const [reviewLimit, setReviewLimit] = useState(10);
910
+
911
+ // Refine state
912
+ const [domainContext, setDomainContext] = useState('');
913
+ const [refineTypes, setRefineTypes] = useState<string[]>(['decisions', 'patterns', 'preferences', 'error_fixes']);
914
+
915
+ // Publish state
916
+ const [pubName, setPubName] = useState('');
917
+ const [pubAuthor, setPubAuthor] = useState('');
918
+ const [pubDesc, setPubDesc] = useState('');
919
+ const [pubTags, setPubTags] = useState('');
920
+ const [pubVersion, setPubVersion] = useState('1.0.0');
921
+ const [pubLicense, setPubLicense] = useState('cc-by');
922
+ const [pubPreviewCount, setPubPreviewCount] = useState(3);
923
+
924
+ useEffect(() => {
925
+ fetch(api('/api/workspaces'))
926
+ .then(r => r.json())
927
+ .then(data => {
928
+ const list = Array.isArray(data) ? data : data.local || [];
929
+ setWorkspaces(list);
930
+ if (list.length > 0 && !workspaceId) setWorkspaceId(list[0].id);
931
+ })
932
+ .catch(() => {});
933
+ }, []);
934
+
935
+ const clearResult = () => { setResult(null); setError(null); };
936
+
937
+ const doSeed = async () => {
938
+ if (!seedText.trim() || !workspaceId) return;
939
+ setLoading(true); clearResult();
940
+ try {
941
+ const res = await fetch(api('/api/cortex/curation/seed'), {
942
+ method: 'POST',
943
+ headers: { 'Content-Type': 'application/json' },
944
+ body: JSON.stringify({
945
+ text: seedText, format: seedFormat, source_ref: seedSource,
946
+ workspace_id: workspaceId, distill: seedDistill,
947
+ }),
948
+ });
949
+ const data = await res.json();
950
+ if (!res.ok) throw new Error(data.error?.message || data.error || 'Seed failed');
951
+ setResult(data);
952
+ } catch (e: any) { setError(e.message); }
953
+ setLoading(false);
954
+ };
955
+
956
+ const doAssess = async () => {
957
+ if (!workspaceId) return;
958
+ setLoading(true); clearResult();
959
+ try {
960
+ const res = await fetch(api(`/api/cortex/curation/assess?workspace_id=${workspaceId}`));
961
+ const data = await res.json();
962
+ if (!res.ok) throw new Error(data.error?.message || data.error || 'Assess failed');
963
+ setResult(data);
964
+ } catch (e: any) { setError(e.message); }
965
+ setLoading(false);
966
+ };
967
+
968
+ const doReview = async () => {
969
+ if (!workspaceId || !reviewTopic.trim()) return;
970
+ setLoading(true); clearResult();
971
+ try {
972
+ const params = new URLSearchParams({
973
+ workspace_id: String(workspaceId), topic: reviewTopic, limit: String(reviewLimit),
974
+ });
975
+ const res = await fetch(api(`/api/cortex/curation/review?${params}`));
976
+ const data = await res.json();
977
+ if (!res.ok) throw new Error(data.error?.message || data.error || 'Review failed');
978
+ setResult(data);
979
+ } catch (e: any) { setError(e.message); }
980
+ setLoading(false);
981
+ };
982
+
983
+ const doRefine = async () => {
984
+ if (!workspaceId) return;
985
+ setLoading(true); clearResult();
986
+ try {
987
+ const res = await fetch(api('/api/cortex/curation/refine'), {
988
+ method: 'POST',
989
+ headers: { 'Content-Type': 'application/json' },
990
+ body: JSON.stringify({
991
+ workspace_id: workspaceId,
992
+ domain_context: domainContext || undefined,
993
+ types: refineTypes.length > 0 ? refineTypes : undefined,
994
+ }),
995
+ });
996
+ const data = await res.json();
997
+ if (!res.ok) throw new Error(data.error?.message || data.error || 'Refine failed');
998
+ setResult(data);
999
+ } catch (e: any) { setError(e.message); }
1000
+ setLoading(false);
1001
+ };
1002
+
1003
+ const doPublish = async () => {
1004
+ if (!workspaceId || !pubName || !pubAuthor) return;
1005
+ setLoading(true); clearResult();
1006
+ try {
1007
+ const res = await fetch(api('/api/cortex/curation/publish'), {
1008
+ method: 'POST',
1009
+ headers: { 'Content-Type': 'application/json' },
1010
+ body: JSON.stringify({
1011
+ workspace_id: workspaceId, author: pubAuthor, name: pubName,
1012
+ description: pubDesc, tags: pubTags.split(',').map(t => t.trim()).filter(Boolean),
1013
+ version: pubVersion, license: pubLicense, preview_count: pubPreviewCount,
1014
+ }),
1015
+ });
1016
+ const data = await res.json();
1017
+ if (!res.ok) throw new Error(data.error?.message || data.error || 'Publish failed');
1018
+ setResult(data);
1019
+ } catch (e: any) { setError(e.message); }
1020
+ setLoading(false);
1021
+ };
1022
+
1023
+ return (
1024
+ <div className="p-6 max-w-4xl">
1025
+ {/* Workspace selector */}
1026
+ <div className="flex items-center gap-3 mb-6">
1027
+ <label className="text-xs text-gray-500">Workspace</label>
1028
+ <select
1029
+ value={workspaceId}
1030
+ onChange={e => { setWorkspaceId(parseInt(e.target.value, 10)); clearResult(); }}
1031
+ className="text-sm bg-white/5 border border-white/10 rounded-lg px-3 py-1.5 text-gray-300"
1032
+ >
1033
+ {workspaces.map(ws => (
1034
+ <option key={ws.id} value={ws.id}>{ws.name}</option>
1035
+ ))}
1036
+ </select>
1037
+ </div>
1038
+
1039
+ {/* Pipeline bar */}
1040
+ <div className="flex items-center gap-0 mb-8">
1041
+ {STEPS.map((s, i) => {
1042
+ const Icon = s.icon;
1043
+ const active = step === s.key;
1044
+ return (
1045
+ <div key={s.key} className="flex items-center">
1046
+ {i > 0 && <div className={`w-8 h-px ${active ? 'bg-purple-500/40' : 'bg-white/[0.06]'}`} />}
1047
+ <button
1048
+ onClick={() => { setStep(s.key); clearResult(); }}
1049
+ className={`flex items-center gap-1.5 px-4 py-2 rounded-full text-xs font-medium transition-colors ${
1050
+ active
1051
+ ? 'bg-purple-500/20 border border-purple-500/30 text-purple-400'
1052
+ : 'bg-white/[0.03] border border-white/[0.06] text-gray-500 hover:text-gray-300'
1053
+ }`}
1054
+ >
1055
+ <Icon className="w-3.5 h-3.5" />
1056
+ {s.label}
1057
+ </button>
1058
+ </div>
1059
+ );
1060
+ })}
1061
+ </div>
1062
+
1063
+ {/* Error banner */}
1064
+ {error && (
1065
+ <div className="mb-4 px-4 py-2 bg-red-500/10 border border-red-500/20 rounded-lg text-xs text-red-400">
1066
+ {error}
1067
+ </div>
1068
+ )}
1069
+
1070
+ {/* Step content */}
1071
+ <div className="min-h-[300px]">
1072
+ {step === 'seed' && (
1073
+ <div className="space-y-4">
1074
+ <textarea
1075
+ value={seedText}
1076
+ onChange={e => setSeedText(e.target.value)}
1077
+ placeholder="Paste document content here..."
1078
+ rows={8}
1079
+ className="w-full text-sm bg-white/5 border border-white/10 rounded-lg p-3 text-gray-300 placeholder-gray-600 focus:outline-none focus:border-purple-500/50 resize-y"
1080
+ />
1081
+ <div className="flex gap-3">
1082
+ <div>
1083
+ <label className="text-[10px] text-gray-500 block mb-1">Format</label>
1084
+ <select value={seedFormat} onChange={e => setSeedFormat(e.target.value)}
1085
+ className="text-xs bg-white/5 border border-white/10 rounded px-2 py-1 text-gray-300">
1086
+ <option value="auto">Auto-detect</option>
1087
+ <option value="markdown">Markdown</option>
1088
+ <option value="plaintext">Plain text</option>
1089
+ <option value="csv">CSV</option>
1090
+ </select>
1091
+ </div>
1092
+ <div className="flex-1">
1093
+ <label className="text-[10px] text-gray-500 block mb-1">Source reference</label>
1094
+ <input value={seedSource} onChange={e => setSeedSource(e.target.value)}
1095
+ placeholder="filename.md or URL"
1096
+ className="w-full text-xs bg-white/5 border border-white/10 rounded px-2 py-1 text-gray-300 placeholder-gray-600" />
1097
+ </div>
1098
+ </div>
1099
+ <label className="flex items-center gap-2 text-xs text-gray-400">
1100
+ <input type="checkbox" checked={seedDistill} onChange={e => setSeedDistill(e.target.checked)}
1101
+ className="accent-purple-500" />
1102
+ Run distillation after seeding
1103
+ </label>
1104
+ <button onClick={doSeed} disabled={loading || !seedText.trim()}
1105
+ className="px-5 py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg disabled:opacity-50">
1106
+ {loading ? <><Loader2 className="w-3.5 h-3.5 inline animate-spin mr-1" /> Processing...</> : 'Seed Documents'}
1107
+ </button>
1108
+ {result && (
1109
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-4 text-xs text-gray-300">
1110
+ <div>Chunks created: <span className="text-green-400">{result.chunksCreated}</span></div>
1111
+ <div>Chunks skipped: <span className="text-gray-500">{result.chunksSkipped}</span></div>
1112
+ {result.errors?.length > 0 && (
1113
+ <div className="text-red-400 mt-1">{result.errors.join(', ')}</div>
1114
+ )}
1115
+ </div>
1116
+ )}
1117
+ </div>
1118
+ )}
1119
+
1120
+ {step === 'assess' && (
1121
+ <div className="space-y-4">
1122
+ <button onClick={doAssess} disabled={loading}
1123
+ className="px-5 py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg disabled:opacity-50">
1124
+ {loading ? <><Loader2 className="w-3.5 h-3.5 inline animate-spin mr-1" /> Assessing...</> : 'Run Assessment'}
1125
+ </button>
1126
+ {result && (
1127
+ <div className="space-y-4">
1128
+ <div className="grid grid-cols-3 gap-3">
1129
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-3">
1130
+ <div className="text-[10px] text-gray-500 uppercase">Coverage</div>
1131
+ <div className={`text-xl font-semibold ${
1132
+ result.coverage_score > 0.7 ? 'text-green-400' : result.coverage_score > 0.3 ? 'text-amber-400' : 'text-red-400'
1133
+ }`}>{result.coverage_score?.toFixed(2)}</div>
1134
+ </div>
1135
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-3">
1136
+ <div className="text-[10px] text-gray-500 uppercase">Total Units</div>
1137
+ <div className="text-xl font-semibold text-white">{result.total_units}</div>
1138
+ </div>
1139
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-3">
1140
+ <div className="text-[10px] text-gray-500 uppercase">Stale</div>
1141
+ <div className="text-xl font-semibold text-amber-400">{result.stale_count}</div>
1142
+ </div>
1143
+ </div>
1144
+ {result.type_distribution && (
1145
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-4">
1146
+ <div className="text-[10px] text-gray-500 uppercase mb-2">Type Distribution</div>
1147
+ <div className="space-y-1.5">
1148
+ {Object.entries(result.type_distribution as Record<string, number>)
1149
+ .sort((a, b) => b[1] - a[1])
1150
+ .map(([type, count]) => (
1151
+ <div key={type} className="flex items-center gap-2">
1152
+ <span className={`text-[10px] px-1.5 py-0.5 rounded font-medium w-24 text-center ${TYPE_COLORS[type] || TYPE_COLORS.context}`}>
1153
+ {type.replace('_', ' ')}
1154
+ </span>
1155
+ <div className="flex-1 h-2 bg-white/[0.03] rounded-full overflow-hidden">
1156
+ <div className="h-full bg-purple-500/50 rounded-full"
1157
+ style={{ width: `${(count / Math.max(result.total_units, 1)) * 100}%` }} />
1158
+ </div>
1159
+ <span className="text-[10px] text-gray-500 w-10 text-right tabular-nums">{count}</span>
1160
+ </div>
1161
+ ))}
1162
+ </div>
1163
+ </div>
1164
+ )}
1165
+ </div>
1166
+ )}
1167
+ </div>
1168
+ )}
1169
+
1170
+ {step === 'review' && (
1171
+ <div className="space-y-4">
1172
+ <div className="flex gap-3">
1173
+ <input value={reviewTopic} onChange={e => setReviewTopic(e.target.value)}
1174
+ onKeyDown={e => e.key === 'Enter' && doReview()}
1175
+ placeholder="Enter topic to review..."
1176
+ className="flex-1 text-sm bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-gray-300 placeholder-gray-600 focus:outline-none focus:border-purple-500/50" />
1177
+ <select value={reviewLimit} onChange={e => setReviewLimit(parseInt(e.target.value, 10))}
1178
+ className="text-xs bg-white/5 border border-white/10 rounded px-2 py-1 text-gray-300">
1179
+ <option value={10}>10</option>
1180
+ <option value={25}>25</option>
1181
+ <option value={50}>50</option>
1182
+ </select>
1183
+ <button onClick={doReview} disabled={loading || !reviewTopic.trim()}
1184
+ className="px-5 py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg disabled:opacity-50">
1185
+ {loading ? 'Reviewing...' : 'Review'}
1186
+ </button>
1187
+ </div>
1188
+ {result?.by_type && (
1189
+ <div className="space-y-3">
1190
+ <div className="text-xs text-gray-400">{result.total_matches} matches for &ldquo;{result.topic}&rdquo;</div>
1191
+ {Object.entries(result.by_type as Record<string, any[]>).map(([type, items]) => (
1192
+ <details key={type} open className="bg-white/[0.02] border border-white/[0.06] rounded-lg">
1193
+ <summary className="px-4 py-2 text-xs text-gray-300 cursor-pointer hover:bg-white/[0.02]">
1194
+ <span className={`inline-block px-1.5 py-0.5 rounded font-medium mr-2 ${TYPE_COLORS[type] || TYPE_COLORS.context}`}>
1195
+ {type.replace('_', ' ')}
1196
+ </span>
1197
+ ({items.length})
1198
+ </summary>
1199
+ <div className="px-4 pb-3 space-y-2">
1200
+ {items.map((item: any, i: number) => (
1201
+ <div key={i} className="text-[11px] text-gray-400 border-l-2 border-white/5 pl-3 py-1">
1202
+ <div>{item.text}</div>
1203
+ <div className="text-[10px] text-gray-600 mt-0.5">
1204
+ confidence: {item.confidence?.toFixed(2)} · similarity: {item.similarity?.toFixed(3)}
1205
+ </div>
1206
+ </div>
1207
+ ))}
1208
+ </div>
1209
+ </details>
1210
+ ))}
1211
+ </div>
1212
+ )}
1213
+ </div>
1214
+ )}
1215
+
1216
+ {step === 'refine' && (
1217
+ <div className="space-y-4">
1218
+ {!result && (
1219
+ <div className="px-4 py-2 bg-amber-500/10 border border-amber-500/20 rounded-lg text-xs text-amber-400">
1220
+ Refine requires an LLM API key for distillation. If not configured, go to{' '}
1221
+ <button onClick={() => { /* parent would need to expose setTab — or use a link */ }}
1222
+ className="underline">Settings</button> to add one.
1223
+ </div>
1224
+ )}
1225
+ <div>
1226
+ <label className="text-xs text-gray-400 block mb-1">Domain Context</label>
1227
+ <textarea value={domainContext} onChange={e => setDomainContext(e.target.value)}
1228
+ placeholder="Describe the domain this lobe should focus on..."
1229
+ rows={3}
1230
+ className="w-full text-sm bg-white/5 border border-white/10 rounded-lg p-3 text-gray-300 placeholder-gray-600 focus:outline-none focus:border-purple-500/50 resize-y" />
1231
+ </div>
1232
+ <div>
1233
+ <label className="text-xs text-gray-400 block mb-2">Distillation passes</label>
1234
+ <div className="flex gap-3">
1235
+ {['decisions', 'patterns', 'preferences', 'error_fixes'].map(t => (
1236
+ <label key={t} className="flex items-center gap-1.5 text-xs text-gray-400">
1237
+ <input type="checkbox" checked={refineTypes.includes(t)}
1238
+ onChange={e => setRefineTypes(prev =>
1239
+ e.target.checked ? [...prev, t] : prev.filter(x => x !== t)
1240
+ )}
1241
+ className="accent-purple-500" />
1242
+ {t.replace('_', ' ')}
1243
+ </label>
1244
+ ))}
1245
+ </div>
1246
+ </div>
1247
+ <button onClick={doRefine} disabled={loading}
1248
+ className="px-5 py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg disabled:opacity-50">
1249
+ {loading ? <><Loader2 className="w-3.5 h-3.5 inline animate-spin mr-1" /> Refining...</> : 'Refine Lobe'}
1250
+ </button>
1251
+ {result && (
1252
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-4 text-xs text-gray-300 space-y-1">
1253
+ <div>Source units found: {result.source_units_found}</div>
1254
+ <div>Old distilled purged: {result.distilled_purged}</div>
1255
+ <div>New units created: <span className="text-green-400">{result.new_units_created}</span></div>
1256
+ {result.errors?.length > 0 && (
1257
+ <div className="text-red-400 mt-1">{result.errors.join(', ')}</div>
1258
+ )}
1259
+ </div>
1260
+ )}
1261
+ </div>
1262
+ )}
1263
+
1264
+ {step === 'publish' && (
1265
+ <div className="space-y-4">
1266
+ <div className="grid grid-cols-2 gap-3">
1267
+ <div>
1268
+ <label className="text-[10px] text-gray-500 block mb-1">Name *</label>
1269
+ <input value={pubName} onChange={e => setPubName(e.target.value)}
1270
+ placeholder="My Knowledge Pack"
1271
+ className="w-full text-xs bg-white/5 border border-white/10 rounded px-2 py-1.5 text-gray-300 placeholder-gray-600" />
1272
+ </div>
1273
+ <div>
1274
+ <label className="text-[10px] text-gray-500 block mb-1">Author *</label>
1275
+ <input value={pubAuthor} onChange={e => setPubAuthor(e.target.value)}
1276
+ placeholder="Your name"
1277
+ className="w-full text-xs bg-white/5 border border-white/10 rounded px-2 py-1.5 text-gray-300 placeholder-gray-600" />
1278
+ </div>
1279
+ </div>
1280
+ <div>
1281
+ <label className="text-[10px] text-gray-500 block mb-1">Description</label>
1282
+ <textarea value={pubDesc} onChange={e => setPubDesc(e.target.value)}
1283
+ placeholder="What this knowledge pack contains..."
1284
+ rows={2}
1285
+ className="w-full text-xs bg-white/5 border border-white/10 rounded p-2 text-gray-300 placeholder-gray-600 resize-y" />
1286
+ </div>
1287
+ <div className="grid grid-cols-3 gap-3">
1288
+ <div>
1289
+ <label className="text-[10px] text-gray-500 block mb-1">Tags (comma-separated)</label>
1290
+ <input value={pubTags} onChange={e => setPubTags(e.target.value)}
1291
+ placeholder="engineering, patterns"
1292
+ className="w-full text-xs bg-white/5 border border-white/10 rounded px-2 py-1.5 text-gray-300 placeholder-gray-600" />
1293
+ </div>
1294
+ <div>
1295
+ <label className="text-[10px] text-gray-500 block mb-1">Version</label>
1296
+ <input value={pubVersion} onChange={e => setPubVersion(e.target.value)}
1297
+ className="w-full text-xs bg-white/5 border border-white/10 rounded px-2 py-1.5 text-gray-300" />
1298
+ </div>
1299
+ <div>
1300
+ <label className="text-[10px] text-gray-500 block mb-1">License</label>
1301
+ <select value={pubLicense} onChange={e => setPubLicense(e.target.value)}
1302
+ className="w-full text-xs bg-white/5 border border-white/10 rounded px-2 py-1.5 text-gray-300">
1303
+ <option value="cc-by">CC-BY</option>
1304
+ <option value="cc-by-sa">CC-BY-SA</option>
1305
+ <option value="commercial">Commercial</option>
1306
+ <option value="free">Free</option>
1307
+ </select>
1308
+ </div>
1309
+ </div>
1310
+ <button onClick={doPublish} disabled={loading || !pubName || !pubAuthor}
1311
+ className="px-5 py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg disabled:opacity-50">
1312
+ {loading ? <><Loader2 className="w-3.5 h-3.5 inline animate-spin mr-1" /> Publishing...</> : 'Publish to Marketplace'}
1313
+ </button>
1314
+ {result && (
1315
+ <div className="space-y-2">
1316
+ {result.quality_warning && (
1317
+ <div className="px-4 py-2 bg-amber-500/10 border border-amber-500/20 rounded-lg text-xs text-amber-400">
1318
+ Coverage score is low ({result.quality?.coverage_score?.toFixed(2)}). Consider seeding more documents or refining.
1319
+ </div>
1320
+ )}
1321
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-4 text-xs text-gray-300 space-y-1">
1322
+ <div>Output: <span className="text-gray-400 font-mono">{result.path}</span></div>
1323
+ <div>Units: {result.total_before} total, {result.excluded_sensitivity} excluded (sensitivity), {result.pii_scrubbed} PII-scrubbed</div>
1324
+ <div>Final pack: <span className="text-green-400">{result.final_units} units</span></div>
1325
+ </div>
1326
+ </div>
1327
+ )}
1328
+ </div>
1329
+ )}
1330
+ </div>
1331
+ </div>
1332
+ );
1333
+ }
1334
+ ```
1335
+
1336
+ - [ ] **Step 2: Verify build**
1337
+
1338
+ Run: `npx next build 2>&1 | tail -5`
1339
+ Expected: Build succeeds (component not yet imported by page)
1340
+
1341
+ - [ ] **Step 3: Commit**
1342
+
1343
+ ```bash
1344
+ git add src/components/cortex/curation-tab.tsx
1345
+ git commit -m "feat(cortex): add curation tab component with pipeline UI"
1346
+ ```
1347
+
1348
+ ---
1349
+
1350
+ ### Task 10: Build Marketplace Tab Components
1351
+
1352
+ **Files:**
1353
+ - Create: `src/components/cortex/marketplace-card.tsx`
1354
+ - Create: `src/components/cortex/import-dialog.tsx`
1355
+ - Create: `src/components/cortex/marketplace-tab.tsx`
1356
+
1357
+ - [ ] **Step 1: Create marketplace card**
1358
+
1359
+ ```typescript
1360
+ // src/components/cortex/marketplace-card.tsx
1361
+ 'use client';
1362
+
1363
+ import { useState } from 'react';
1364
+ import { Package, ChevronDown, ChevronUp } from 'lucide-react';
1365
+ import { TYPE_COLORS } from './constants';
1366
+
1367
+ interface PackManifest {
1368
+ version: string;
1369
+ exportDate: string;
1370
+ unitCount: number;
1371
+ marketplace?: {
1372
+ name: string;
1373
+ author: string;
1374
+ description: string;
1375
+ tags: string[];
1376
+ packageVersion: string;
1377
+ license: string;
1378
+ domain_context?: string;
1379
+ quality: {
1380
+ coverage_score: number;
1381
+ avg_confidence: number;
1382
+ type_distribution: Record<string, number>;
1383
+ total_units: number;
1384
+ };
1385
+ preview: Array<{ text: string; type: string }>;
1386
+ };
1387
+ }
1388
+
1389
+ interface Props {
1390
+ filename: string;
1391
+ manifest: PackManifest;
1392
+ onImport: (filename: string, manifest: PackManifest) => void;
1393
+ }
1394
+
1395
+ export function MarketplaceCard({ filename, manifest, onImport }: Props) {
1396
+ const [showPreview, setShowPreview] = useState(false);
1397
+ const mp = manifest.marketplace;
1398
+
1399
+ const coverageColor = mp
1400
+ ? mp.quality.coverage_score > 0.7 ? 'text-green-400'
1401
+ : mp.quality.coverage_score > 0.3 ? 'text-amber-400'
1402
+ : 'text-red-400'
1403
+ : 'text-gray-500';
1404
+
1405
+ return (
1406
+ <div className="bg-white/[0.02] border border-white/[0.06] rounded-lg p-4 hover:border-white/10 transition-colors">
1407
+ <div className="flex items-start justify-between gap-3">
1408
+ <div className="flex-1 min-w-0">
1409
+ <div className="flex items-center gap-2">
1410
+ <Package className="w-4 h-4 text-purple-400 shrink-0" />
1411
+ <h3 className="text-sm font-medium text-gray-200 truncate">
1412
+ {mp?.name || filename}
1413
+ </h3>
1414
+ {mp && <span className="text-[10px] text-gray-600 shrink-0">v{mp.packageVersion}</span>}
1415
+ </div>
1416
+ {mp && <div className="text-[10px] text-gray-500 mt-0.5">by {mp.author}</div>}
1417
+ <p className="text-xs text-gray-400 mt-1 line-clamp-2">
1418
+ {mp?.description || `Exported ${new Date(manifest.exportDate).toLocaleDateString()}`}
1419
+ </p>
1420
+ </div>
1421
+ <div className="text-right shrink-0">
1422
+ <div className={`text-lg font-semibold tabular-nums ${coverageColor}`}>
1423
+ {mp ? mp.quality.coverage_score.toFixed(2) : '—'}
1424
+ </div>
1425
+ <div className="text-[10px] text-gray-600">{manifest.unitCount} units</div>
1426
+ </div>
1427
+ </div>
1428
+
1429
+ {mp?.tags && mp.tags.length > 0 && (
1430
+ <div className="flex flex-wrap gap-1 mt-2">
1431
+ {mp.tags.map(tag => (
1432
+ <span key={tag} className="text-[9px] px-1.5 py-0.5 bg-white/5 border border-white/[0.06] rounded text-gray-500">
1433
+ {tag}
1434
+ </span>
1435
+ ))}
1436
+ {mp.license && (
1437
+ <span className="text-[9px] px-1.5 py-0.5 bg-purple-500/10 border border-purple-500/20 rounded text-purple-400">
1438
+ {mp.license}
1439
+ </span>
1440
+ )}
1441
+ </div>
1442
+ )}
1443
+
1444
+ {mp?.preview && mp.preview.length > 0 && (
1445
+ <div className="mt-2">
1446
+ <button onClick={() => setShowPreview(!showPreview)}
1447
+ className="flex items-center gap-1 text-[10px] text-gray-600 hover:text-gray-400">
1448
+ Preview {showPreview ? <ChevronUp className="w-3 h-3" /> : <ChevronDown className="w-3 h-3" />}
1449
+ </button>
1450
+ {showPreview && (
1451
+ <div className="mt-1 space-y-1">
1452
+ {mp.preview.map((p, i) => (
1453
+ <div key={i} className="text-[10px] text-gray-500 border-l-2 border-white/5 pl-2 py-0.5">
1454
+ <span className={`inline-block px-1 py-0 rounded mr-1 ${TYPE_COLORS[p.type] || TYPE_COLORS.context}`}>
1455
+ {p.type}
1456
+ </span>
1457
+ {p.text.slice(0, 100)}
1458
+ </div>
1459
+ ))}
1460
+ </div>
1461
+ )}
1462
+ </div>
1463
+ )}
1464
+
1465
+ <button onClick={() => onImport(filename, manifest)}
1466
+ className="mt-3 w-full py-1.5 text-xs bg-purple-600 hover:bg-purple-500 text-white rounded-lg">
1467
+ Import
1468
+ </button>
1469
+ </div>
1470
+ );
1471
+ }
1472
+ ```
1473
+
1474
+ - [ ] **Step 2: Create import dialog**
1475
+
1476
+ ```typescript
1477
+ // src/components/cortex/import-dialog.tsx
1478
+ 'use client';
1479
+
1480
+ import { useState, useEffect } from 'react';
1481
+ import { X, Loader2 } from 'lucide-react';
1482
+ import { api } from '@/lib/api';
1483
+
1484
+ interface Props {
1485
+ filename: string;
1486
+ hasDomainContext: boolean;
1487
+ onClose: () => void;
1488
+ onComplete: () => void;
1489
+ }
1490
+
1491
+ export function ImportDialog({ filename, hasDomainContext, onClose, onComplete }: Props) {
1492
+ const [targetLayer, setTargetLayer] = useState('workspace');
1493
+ const [workspaceId, setWorkspaceId] = useState('');
1494
+ const [mergeStrategy, setMergeStrategy] = useState('merge');
1495
+ const [reEmbed, setReEmbed] = useState(false);
1496
+ const [applyDomainCtx, setApplyDomainCtx] = useState(false);
1497
+ const [workspaces, setWorkspaces] = useState<{ id: number; name: string }[]>([]);
1498
+ const [importing, setImporting] = useState(false);
1499
+ const [error, setError] = useState<string | null>(null);
1500
+
1501
+ useEffect(() => {
1502
+ fetch(api('/api/workspaces'))
1503
+ .then(r => r.json())
1504
+ .then(data => {
1505
+ const list = Array.isArray(data) ? data : data.local || [];
1506
+ setWorkspaces(list);
1507
+ if (list.length > 0) setWorkspaceId(String(list[0].id));
1508
+ })
1509
+ .catch(() => {});
1510
+ }, []);
1511
+
1512
+ const handleImport = async () => {
1513
+ setImporting(true);
1514
+ setError(null);
1515
+ try {
1516
+ // Fetch the file from marketplace dir and upload it
1517
+ const formData = new FormData();
1518
+ const res = await fetch(api(`/api/cortex/marketplace/preview?file=${encodeURIComponent(filename)}`));
1519
+ // We need to send the file — fetch it as blob from the server
1520
+ // Actually, the import route expects a file upload. We'll pass the filename to a modified import.
1521
+ // For now, use a server-side import that reads from marketplace dir directly.
1522
+ const importRes = await fetch(api('/api/cortex/import'), {
1523
+ method: 'POST',
1524
+ headers: { 'Content-Type': 'application/json' },
1525
+ body: JSON.stringify({
1526
+ marketplace_file: filename,
1527
+ target_layer: targetLayer,
1528
+ workspace_id: targetLayer === 'workspace' ? workspaceId : undefined,
1529
+ merge_strategy: mergeStrategy,
1530
+ re_embed: reEmbed,
1531
+ }),
1532
+ });
1533
+ if (!importRes.ok) {
1534
+ const data = await importRes.json();
1535
+ throw new Error(data.error || 'Import failed');
1536
+ }
1537
+ onComplete();
1538
+ } catch (e: any) {
1539
+ setError(e.message);
1540
+ }
1541
+ setImporting(false);
1542
+ };
1543
+
1544
+ return (
1545
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60">
1546
+ <div className="bg-gray-900 border border-white/10 rounded-xl p-6 w-full max-w-md shadow-xl">
1547
+ <div className="flex items-center justify-between mb-4">
1548
+ <h3 className="text-sm font-medium text-gray-200">Import {filename}</h3>
1549
+ <button onClick={onClose} className="text-gray-500 hover:text-gray-300"><X className="w-4 h-4" /></button>
1550
+ </div>
1551
+
1552
+ <div className="space-y-4">
1553
+ <div>
1554
+ <label className="text-[10px] text-gray-500 block mb-1">Target layer</label>
1555
+ <div className="flex gap-2">
1556
+ {['personal', 'workspace', 'team'].map(l => (
1557
+ <button key={l} onClick={() => setTargetLayer(l)}
1558
+ className={`px-3 py-1 text-xs rounded ${
1559
+ targetLayer === l ? 'bg-purple-500/20 text-purple-400 border border-purple-500/30' : 'bg-white/5 text-gray-500 border border-white/[0.06]'
1560
+ }`}>{l}</button>
1561
+ ))}
1562
+ </div>
1563
+ </div>
1564
+
1565
+ {targetLayer === 'workspace' && (
1566
+ <div>
1567
+ <label className="text-[10px] text-gray-500 block mb-1">Workspace</label>
1568
+ <select value={workspaceId} onChange={e => setWorkspaceId(e.target.value)}
1569
+ className="w-full text-xs bg-white/5 border border-white/10 rounded px-2 py-1.5 text-gray-300">
1570
+ {workspaces.map(ws => <option key={ws.id} value={ws.id}>{ws.name}</option>)}
1571
+ </select>
1572
+ </div>
1573
+ )}
1574
+
1575
+ <div>
1576
+ <label className="text-[10px] text-gray-500 block mb-1">Merge strategy</label>
1577
+ <div className="flex gap-2">
1578
+ {['append', 'merge', 'replace'].map(s => (
1579
+ <button key={s} onClick={() => setMergeStrategy(s)}
1580
+ className={`px-3 py-1 text-xs rounded ${
1581
+ mergeStrategy === s ? 'bg-purple-500/20 text-purple-400 border border-purple-500/30' : 'bg-white/5 text-gray-500 border border-white/[0.06]'
1582
+ }`}>{s}</button>
1583
+ ))}
1584
+ </div>
1585
+ </div>
1586
+
1587
+ <label className="flex items-center gap-2 text-xs text-gray-400">
1588
+ <input type="checkbox" checked={reEmbed} onChange={e => setReEmbed(e.target.checked)} className="accent-purple-500" />
1589
+ Re-generate embeddings (slower, matches your provider)
1590
+ </label>
1591
+
1592
+ {hasDomainContext && (
1593
+ <label className="flex items-center gap-2 text-xs text-gray-400">
1594
+ <input type="checkbox" checked={applyDomainCtx} onChange={e => setApplyDomainCtx(e.target.checked)} className="accent-purple-500" />
1595
+ Apply pack&apos;s domain context to target workspace
1596
+ </label>
1597
+ )}
1598
+
1599
+ {error && <div className="text-xs text-red-400">{error}</div>}
1600
+
1601
+ <button onClick={handleImport} disabled={importing}
1602
+ className="w-full py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg disabled:opacity-50">
1603
+ {importing ? <><Loader2 className="w-3.5 h-3.5 inline animate-spin mr-1" /> Importing...</> : 'Start Import'}
1604
+ </button>
1605
+ </div>
1606
+ </div>
1607
+ </div>
1608
+ );
1609
+ }
1610
+ ```
1611
+
1612
+ - [ ] **Step 3: Create marketplace tab**
1613
+
1614
+ ```typescript
1615
+ // src/components/cortex/marketplace-tab.tsx
1616
+ 'use client';
1617
+
1618
+ import { useState, useEffect } from 'react';
1619
+ import { FolderOpen, RefreshCw } from 'lucide-react';
1620
+ import { api } from '@/lib/api';
1621
+ import { MarketplaceCard } from './marketplace-card';
1622
+ import { ImportDialog } from './import-dialog';
1623
+
1624
+ export function MarketplaceTab() {
1625
+ const [packs, setPacks] = useState<any[]>([]);
1626
+ const [directory, setDirectory] = useState('');
1627
+ const [loading, setLoading] = useState(true);
1628
+ const [importTarget, setImportTarget] = useState<{ filename: string; manifest: any } | null>(null);
1629
+
1630
+ const fetchPacks = async () => {
1631
+ setLoading(true);
1632
+ try {
1633
+ const res = await fetch(api('/api/cortex/marketplace/browse'));
1634
+ if (res.ok) {
1635
+ const data = await res.json();
1636
+ setPacks(data.packs || []);
1637
+ setDirectory(data.directory || '');
1638
+ }
1639
+ } catch {}
1640
+ setLoading(false);
1641
+ };
1642
+
1643
+ useEffect(() => { fetchPacks(); }, []);
1644
+
1645
+ return (
1646
+ <div className="p-6 max-w-4xl">
1647
+ <div className="flex items-center justify-between mb-6">
1648
+ <div>
1649
+ <h2 className="text-sm font-medium text-gray-200">Marketplace</h2>
1650
+ {directory && <div className="text-[10px] text-gray-600 font-mono mt-0.5">{directory}</div>}
1651
+ </div>
1652
+ <button onClick={fetchPacks} disabled={loading}
1653
+ className="flex items-center gap-1.5 px-3 py-1.5 text-xs bg-white/5 border border-white/[0.06] rounded-lg text-gray-400 hover:text-gray-300 disabled:opacity-50">
1654
+ <RefreshCw className={`w-3 h-3 ${loading ? 'animate-spin' : ''}`} />
1655
+ Refresh
1656
+ </button>
1657
+ </div>
1658
+
1659
+ {loading && <p className="text-sm text-gray-500 text-center py-12">Scanning marketplace...</p>}
1660
+
1661
+ {!loading && packs.length === 0 && (
1662
+ <div className="text-center py-16">
1663
+ <FolderOpen className="w-8 h-8 text-gray-700 mx-auto mb-3" />
1664
+ <p className="text-sm text-gray-500">No .cortexpack files found</p>
1665
+ <p className="text-[10px] text-gray-600 mt-1">
1666
+ Publish a lobe from the Curation tab, or drop .cortexpack files into the marketplace directory.
1667
+ </p>
1668
+ </div>
1669
+ )}
1670
+
1671
+ {!loading && packs.length > 0 && (
1672
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
1673
+ {packs.map(pack => (
1674
+ <MarketplaceCard
1675
+ key={pack.filename}
1676
+ filename={pack.filename}
1677
+ manifest={pack.manifest}
1678
+ onImport={(f, m) => setImportTarget({ filename: f, manifest: m })}
1679
+ />
1680
+ ))}
1681
+ </div>
1682
+ )}
1683
+
1684
+ {importTarget && (
1685
+ <ImportDialog
1686
+ filename={importTarget.filename}
1687
+ hasDomainContext={!!importTarget.manifest.marketplace?.domain_context}
1688
+ onClose={() => setImportTarget(null)}
1689
+ onComplete={() => { setImportTarget(null); fetchPacks(); }}
1690
+ />
1691
+ )}
1692
+ </div>
1693
+ );
1694
+ }
1695
+ ```
1696
+
1697
+ - [ ] **Step 4: Verify build**
1698
+
1699
+ Run: `npx next build 2>&1 | tail -5`
1700
+ Expected: Build succeeds
1701
+
1702
+ - [ ] **Step 5: Commit**
1703
+
1704
+ ```bash
1705
+ git add src/components/cortex/marketplace-card.tsx src/components/cortex/import-dialog.tsx src/components/cortex/marketplace-tab.tsx
1706
+ git commit -m "feat(cortex): add marketplace tab with card grid and import dialog"
1707
+ ```
1708
+
1709
+ ---
1710
+
1711
+ ### Task 11: Wire Up 6-Tab Cortex Page
1712
+
1713
+ **Files:**
1714
+ - Modify: `src/app/(desktop)/cortex/page.tsx`
1715
+ - Delete: `src/components/cortex/context-tab.tsx` (deferred from Task 6)
1716
+
1717
+ - [ ] **Step 1: Delete context-tab.tsx**
1718
+
1719
+ ```bash
1720
+ rm src/components/cortex/context-tab.tsx
1721
+ ```
1722
+
1723
+ - [ ] **Step 2: Update the page to use 6 tabs**
1724
+
1725
+ Replace the entire file:
1726
+
1727
+ ```typescript
1728
+ 'use client';
1729
+
1730
+ import { useState, useEffect } from 'react';
1731
+ import dynamic from 'next/dynamic';
1732
+ import { api } from '@/lib/api';
1733
+ import { KnowledgeTab } from '@/components/cortex/knowledge-tab';
1734
+ import { CortexSettings } from '@/components/cortex/cortex-settings';
1735
+ import { CortexDashboard } from '@/components/cortex/cortex-dashboard';
1736
+ import { CurationTab } from '@/components/cortex/curation-tab';
1737
+ import { MarketplaceTab } from '@/components/cortex/marketplace-tab';
1738
+
1739
+ const EntityGraphView = dynamic(
1740
+ () => import('@/components/cortex/entity-graph').then(m => ({ default: m.EntityGraphView })),
1741
+ { ssr: false, loading: () => <div className="flex-1 flex items-center justify-center text-gray-500 text-sm">Loading graph...</div> }
1742
+ );
1743
+
1744
+ type Tab = 'dashboard' | 'graph' | 'knowledge' | 'curation' | 'marketplace' | 'settings';
1745
+
1746
+ export default function CortexPage() {
1747
+ const [tab, setTab] = useState<Tab>('dashboard');
1748
+ const [stats, setStats] = useState<any>(null);
1749
+ useEffect(() => {
1750
+ fetch(api('/api/cortex/status'))
1751
+ .then(r => r.json())
1752
+ .then(setStats)
1753
+ .catch(() => {});
1754
+ }, []);
1755
+
1756
+ const tabs: { key: Tab; label: string }[] = [
1757
+ { key: 'dashboard', label: 'Dashboard' },
1758
+ { key: 'graph', label: 'Graph' },
1759
+ { key: 'knowledge', label: 'Knowledge' },
1760
+ { key: 'curation', label: 'Curation' },
1761
+ { key: 'marketplace', label: 'Marketplace' },
1762
+ { key: 'settings', label: 'Settings' },
1763
+ ];
1764
+
1765
+ const totalKnowledge = stats
1766
+ ? Object.values(stats.layers || {}).reduce((sum: number, l: any) => sum + (l.count || 0), 0)
1767
+ : 0;
1768
+
1769
+ return (
1770
+ <div className="flex flex-col h-screen bg-gray-950">
1771
+ <div className="flex items-center border-b border-white/5 px-4 shrink-0">
1772
+ <div className="flex">
1773
+ {tabs.map(t => (
1774
+ <button
1775
+ key={t.key}
1776
+ onClick={() => setTab(t.key)}
1777
+ className={`px-5 py-3 text-sm font-medium transition-colors border-b-2 ${
1778
+ tab === t.key
1779
+ ? 'text-purple-400 border-purple-400'
1780
+ : 'text-gray-500 border-transparent hover:text-gray-300'
1781
+ }`}
1782
+ >
1783
+ {t.label}
1784
+ </button>
1785
+ ))}
1786
+ </div>
1787
+ <div className="ml-auto text-xs text-gray-600">
1788
+ {totalKnowledge} knowledge units
1789
+ </div>
1790
+ </div>
1791
+ <div className="flex-1 overflow-y-auto">
1792
+ {tab === 'dashboard' && <CortexDashboard />}
1793
+ {tab === 'graph' && <EntityGraphView />}
1794
+ {tab === 'knowledge' && <KnowledgeTab />}
1795
+ {tab === 'curation' && <CurationTab />}
1796
+ {tab === 'marketplace' && <MarketplaceTab />}
1797
+ {tab === 'settings' && (
1798
+ <div className="p-6 max-w-2xl space-y-8">
1799
+ <CortexSettings />
1800
+ </div>
1801
+ )}
1802
+ </div>
1803
+ </div>
1804
+ );
1805
+ }
1806
+ ```
1807
+
1808
+ - [ ] **Step 3: Verify build**
1809
+
1810
+ Run: `npx next build 2>&1 | tail -5`
1811
+ Expected: Build succeeds with no errors
1812
+
1813
+ - [ ] **Step 4: Commit**
1814
+
1815
+ ```bash
1816
+ git rm src/components/cortex/context-tab.tsx
1817
+ git add src/app/(desktop)/cortex/page.tsx
1818
+ git commit -m "feat(cortex): wire 6-tab layout, remove context tab"
1819
+ ```
1820
+
1821
+ ---
1822
+
1823
+ ### Task 12: Final Build Verification
1824
+
1825
+ - [ ] **Step 1: Full build**
1826
+
1827
+ Run: `npx next build 2>&1 | tail -20`
1828
+ Expected: Build succeeds, all routes compiled
1829
+
1830
+ - [ ] **Step 2: Verify all new routes are compiled**
1831
+
1832
+ Look for these in the build output:
1833
+ - `/api/cortex/curation/seed`
1834
+ - `/api/cortex/curation/assess`
1835
+ - `/api/cortex/curation/review`
1836
+ - `/api/cortex/curation/refine`
1837
+ - `/api/cortex/curation/publish`
1838
+ - `/api/cortex/marketplace/browse`
1839
+ - `/api/cortex/marketplace/preview`
1840
+
1841
+ - [ ] **Step 3: Commit any build fixes if needed**
1842
+
1843
+ ```bash
1844
+ git add -A
1845
+ git commit -m "fix(cortex): resolve build issues from UI integration"
1846
+ ```