@jlongo78/agent-spaces 0.7.3 → 0.7.5

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 (597) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +7 -0
  3. package/.next/standalone/.next/build-manifest.json +2 -2
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +19 -19
  6. package/.next/standalone/.next/routes-manifest.json +42 -0
  7. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page.js +1 -1
  8. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page.js.nft.json +1 -1
  9. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/.next/server/app/(desktop)/admin/users/page.js +1 -1
  11. package/.next/standalone/.next/server/app/(desktop)/admin/users/page.js.nft.json +1 -1
  12. package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/(desktop)/analytics/page.js +1 -1
  14. package/.next/standalone/.next/server/app/(desktop)/analytics/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/(desktop)/cortex/page.js +1 -1
  17. package/.next/standalone/.next/server/app/(desktop)/cortex/page.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/(desktop)/cortex/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/(desktop)/network/page.js +1 -1
  20. package/.next/standalone/.next/server/app/(desktop)/network/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/(desktop)/page.js +1 -1
  23. package/.next/standalone/.next/server/app/(desktop)/page.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/(desktop)/projects/page.js +1 -1
  26. package/.next/standalone/.next/server/app/(desktop)/projects/page.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
  28. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js +1 -1
  29. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
  31. package/.next/standalone/.next/server/app/(desktop)/sessions/page.js +1 -1
  32. package/.next/standalone/.next/server/app/(desktop)/sessions/page.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
  34. package/.next/standalone/.next/server/app/(desktop)/settings/page.js +1 -1
  35. package/.next/standalone/.next/server/app/(desktop)/settings/page.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
  37. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js +1 -1
  38. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js +1 -1
  41. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js +1 -1
  44. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/(desktop)/workspaces/page.js +1 -1
  47. package/.next/standalone/.next/server/app/(desktop)/workspaces/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  50. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  51. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  52. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  53. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  54. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  55. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  56. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  58. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  59. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  60. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  61. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  62. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  63. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  64. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  65. package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
  66. package/.next/standalone/.next/server/app/admin/analytics.rsc +17 -16
  67. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +2 -2
  68. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
  69. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  70. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  71. package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +17 -16
  72. package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
  73. package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +2 -2
  74. package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
  75. package/.next/standalone/.next/server/app/admin/users.html +1 -1
  76. package/.next/standalone/.next/server/app/admin/users.rsc +17 -16
  77. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +2 -2
  78. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
  79. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  80. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  81. package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +17 -16
  82. package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
  83. package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +2 -2
  84. package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
  85. package/.next/standalone/.next/server/app/analytics.html +1 -1
  86. package/.next/standalone/.next/server/app/analytics.rsc +17 -16
  87. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +2 -2
  88. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
  89. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  90. package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +17 -16
  91. package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
  92. package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +2 -2
  93. package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  94. package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/chat/route.js +1 -1
  97. package/.next/standalone/.next/server/app/api/chat/route.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/cortex/context/route.js.nft.json +1 -1
  100. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/app-paths-manifest.json +3 -0
  101. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/build-manifest.json +11 -0
  102. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/server-reference-manifest.json +4 -0
  103. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js +7 -0
  104. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.map +5 -0
  105. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.nft.json +1 -0
  106. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route_client-reference-manifest.js +2 -0
  107. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/app-paths-manifest.json +3 -0
  108. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/build-manifest.json +11 -0
  109. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/server-reference-manifest.json +4 -0
  110. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js +7 -0
  111. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.map +5 -0
  112. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.nft.json +1 -0
  113. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route_client-reference-manifest.js +2 -0
  114. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/app-paths-manifest.json +3 -0
  115. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/build-manifest.json +11 -0
  116. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/server-reference-manifest.json +4 -0
  117. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js +7 -0
  118. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.map +5 -0
  119. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.nft.json +1 -0
  120. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route_client-reference-manifest.js +2 -0
  121. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/app-paths-manifest.json +3 -0
  122. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/build-manifest.json +11 -0
  123. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/server-reference-manifest.json +4 -0
  124. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js +7 -0
  125. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.map +5 -0
  126. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.nft.json +1 -0
  127. package/.next/standalone/.next/server/app/api/cortex/curation/review/route_client-reference-manifest.js +2 -0
  128. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/app-paths-manifest.json +3 -0
  129. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/build-manifest.json +11 -0
  130. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/server-reference-manifest.json +4 -0
  131. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js +7 -0
  132. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.map +5 -0
  133. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.nft.json +1 -0
  134. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route_client-reference-manifest.js +2 -0
  135. package/.next/standalone/.next/server/app/api/cortex/export/route.js.nft.json +1 -1
  136. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js.nft.json +1 -1
  137. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js.nft.json +1 -1
  138. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js.nft.json +1 -1
  139. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js.nft.json +1 -1
  140. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js.nft.json +1 -1
  141. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js.nft.json +1 -1
  142. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js.nft.json +1 -1
  143. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/cortex/import/route.js.nft.json +1 -1
  145. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js.nft.json +1 -1
  147. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js.nft.json +1 -1
  149. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js.nft.json +1 -1
  151. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js.nft.json +1 -1
  152. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js.nft.json +1 -1
  153. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/app-paths-manifest.json +3 -0
  154. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/build-manifest.json +11 -0
  155. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/server-reference-manifest.json +4 -0
  156. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js +7 -0
  157. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.map +5 -0
  158. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.nft.json +1 -0
  159. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route_client-reference-manifest.js +2 -0
  160. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/app-paths-manifest.json +3 -0
  161. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/build-manifest.json +11 -0
  162. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/server-reference-manifest.json +4 -0
  163. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js +7 -0
  164. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.map +5 -0
  165. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.nft.json +1 -0
  166. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route_client-reference-manifest.js +2 -0
  167. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js.nft.json +1 -1
  168. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js.nft.json +1 -1
  169. package/.next/standalone/.next/server/app/api/cortex/search/route.js.nft.json +1 -1
  170. package/.next/standalone/.next/server/app/api/cortex/settings/route.js.nft.json +1 -1
  171. package/.next/standalone/.next/server/app/api/cortex/status/route.js.nft.json +1 -1
  172. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js.nft.json +1 -1
  173. package/.next/standalone/.next/server/app/api/cortex/usage/route.js.nft.json +1 -1
  174. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js.nft.json +1 -1
  175. package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
  176. package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
  177. package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
  178. package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
  179. package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
  180. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
  181. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
  183. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
  184. package/.next/standalone/.next/server/app/api/network/workspaces/route.js +1 -1
  185. package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
  186. package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
  187. package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
  188. package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  189. package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  190. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
  191. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
  192. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  193. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  194. package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
  195. package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
  196. package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
  197. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
  198. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
  199. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
  200. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
  201. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
  202. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
  203. package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  204. package/.next/standalone/.next/server/app/cortex.html +1 -1
  205. package/.next/standalone/.next/server/app/cortex.rsc +17 -16
  206. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex/__PAGE__.segment.rsc +2 -2
  207. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex.segment.rsc +1 -1
  208. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  209. package/.next/standalone/.next/server/app/cortex.segments/_full.segment.rsc +17 -16
  210. package/.next/standalone/.next/server/app/cortex.segments/_head.segment.rsc +1 -1
  211. package/.next/standalone/.next/server/app/cortex.segments/_index.segment.rsc +2 -2
  212. package/.next/standalone/.next/server/app/cortex.segments/_tree.segment.rsc +2 -2
  213. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  214. package/.next/standalone/.next/server/app/login.html +1 -1
  215. package/.next/standalone/.next/server/app/login.rsc +2 -2
  216. package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
  217. package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
  218. package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +2 -2
  219. package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  220. package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  221. package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
  222. package/.next/standalone/.next/server/app/m/page.js.nft.json +1 -1
  223. package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
  224. package/.next/standalone/.next/server/app/m/projects/page.js.nft.json +1 -1
  225. package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
  226. package/.next/standalone/.next/server/app/m/projects.html +1 -1
  227. package/.next/standalone/.next/server/app/m/projects.rsc +4 -4
  228. package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +4 -4
  229. package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
  230. package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +2 -2
  231. package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
  232. package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +2 -2
  233. package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
  234. package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +2 -2
  235. package/.next/standalone/.next/server/app/m/sessions/[id]/page.js.nft.json +1 -1
  236. package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
  237. package/.next/standalone/.next/server/app/m/sessions/page.js.nft.json +1 -1
  238. package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
  239. package/.next/standalone/.next/server/app/m/sessions.html +1 -1
  240. package/.next/standalone/.next/server/app/m/sessions.rsc +4 -4
  241. package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +4 -4
  242. package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
  243. package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +2 -2
  244. package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
  245. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +2 -2
  246. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
  247. package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +2 -2
  248. package/.next/standalone/.next/server/app/m/settings/page.js.nft.json +1 -1
  249. package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
  250. package/.next/standalone/.next/server/app/m/settings.html +1 -1
  251. package/.next/standalone/.next/server/app/m/settings.rsc +4 -4
  252. package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +4 -4
  253. package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
  254. package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +2 -2
  255. package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
  256. package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +2 -2
  257. package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
  258. package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +2 -2
  259. package/.next/standalone/.next/server/app/m/terminal/page.js.nft.json +1 -1
  260. package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
  261. package/.next/standalone/.next/server/app/m/terminal.html +1 -1
  262. package/.next/standalone/.next/server/app/m/terminal.rsc +4 -4
  263. package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +4 -4
  264. package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
  265. package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +2 -2
  266. package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
  267. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
  268. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
  269. package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +2 -2
  270. package/.next/standalone/.next/server/app/m.html +1 -1
  271. package/.next/standalone/.next/server/app/m.rsc +4 -4
  272. package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +4 -4
  273. package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
  274. package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +2 -2
  275. package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
  276. package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +2 -2
  277. package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +2 -2
  278. package/.next/standalone/.next/server/app/network.html +1 -1
  279. package/.next/standalone/.next/server/app/network.rsc +17 -16
  280. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +2 -2
  281. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
  282. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  283. package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +17 -16
  284. package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
  285. package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +2 -2
  286. package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
  287. package/.next/standalone/.next/server/app/projects.html +1 -1
  288. package/.next/standalone/.next/server/app/projects.rsc +17 -16
  289. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +2 -2
  290. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
  291. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  292. package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +17 -16
  293. package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  294. package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +2 -2
  295. package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  296. package/.next/standalone/.next/server/app/sessions.html +1 -1
  297. package/.next/standalone/.next/server/app/sessions.rsc +17 -16
  298. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +2 -2
  299. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
  300. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  301. package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +17 -16
  302. package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
  303. package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +2 -2
  304. package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
  305. package/.next/standalone/.next/server/app/settings.html +1 -1
  306. package/.next/standalone/.next/server/app/settings.rsc +17 -16
  307. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +2 -2
  308. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
  309. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  310. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +17 -16
  311. package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  312. package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  313. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  314. package/.next/standalone/.next/server/app/terminal.html +1 -1
  315. package/.next/standalone/.next/server/app/terminal.rsc +17 -16
  316. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
  317. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
  318. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  319. package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +17 -16
  320. package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
  321. package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +2 -2
  322. package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
  323. package/.next/standalone/.next/server/app/workspaces.html +1 -1
  324. package/.next/standalone/.next/server/app/workspaces.rsc +17 -16
  325. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +2 -2
  326. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
  327. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  328. package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +17 -16
  329. package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
  330. package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +2 -2
  331. package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
  332. package/.next/standalone/.next/server/app-paths-manifest.json +7 -0
  333. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0041efe4._.js +98 -0
  334. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00bf0ace._.js +2 -2
  335. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e71d908._.js +2 -2
  336. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e9142f3._.js +2 -2
  337. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10e47926._.js +1 -1
  338. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1665dc78._.js +2 -2
  339. package/.next/standalone/.next/server/chunks/[root-of-the-server]__175cbabf._.js +2 -2
  340. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adae357._.js +2 -2
  341. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d359752._.js +2 -2
  342. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1e8fabeb._.js +3 -3
  343. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1f8deca0._.js +8 -8
  344. package/.next/standalone/.next/server/chunks/[root-of-the-server]__253fdda1._.js +2 -2
  345. package/.next/standalone/.next/server/chunks/[root-of-the-server]__28e6434f._.js +2 -2
  346. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2a386564._.js +1 -1
  347. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2c20fb38._.js +2 -2
  348. package/.next/standalone/.next/server/chunks/[root-of-the-server]__309132cd._.js +1 -1
  349. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__cf3c60c2._.js → [root-of-the-server]__33fec964._.js} +4 -4
  350. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3786d8ae._.js +1 -1
  351. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3ae92407._.js +2 -2
  352. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3beda9fe._.js +2 -2
  353. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4619e9bd._.js +1 -1
  354. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4a051043._.js +1 -1
  355. package/.next/standalone/.next/server/chunks/[root-of-the-server]__508002e4._.js +2 -2
  356. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5086c373._.js +2 -2
  357. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5913e097._.js +2 -2
  358. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5b5f68d2._.js +2 -2
  359. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c1f2459._.js +2 -2
  360. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5ec8c977._.js +2 -2
  361. package/.next/standalone/.next/server/chunks/[root-of-the-server]__63cebc6c._.js +98 -0
  362. package/.next/standalone/.next/server/chunks/[root-of-the-server]__64d30d4d._.js +2 -2
  363. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c54fc2e._.js +2 -2
  364. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6dc1fb7e._.js +1 -1
  365. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6e568102._.js +1 -1
  366. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6faa04c0._.js +2 -2
  367. package/.next/standalone/.next/server/chunks/[root-of-the-server]__74a34dc3._.js +98 -0
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e7250a4._.js +3 -3
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8309e0a4._.js +2 -2
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__86cc0e2b._.js +6 -6
  371. package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c2565a._.js +2 -2
  372. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8d178ad9._.js +2 -2
  373. package/.next/standalone/.next/server/chunks/[root-of-the-server]__93ee06f3._.js +3 -3
  374. package/.next/standalone/.next/server/chunks/[root-of-the-server]__9e4c154a._.js +2 -2
  375. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9d2e1d3._.js +2 -2
  376. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ae53d343._.js +2 -2
  377. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b3a04cef._.js +2 -2
  378. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b4270b77._.js +3 -0
  379. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b6b6ce60._.js +1 -1
  380. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b9545dd9._.js +1 -1
  381. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c88b63f7._.js +98 -0
  382. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__eee4c5e8._.js → [root-of-the-server]__cba5f007._.js} +2 -2
  383. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cbf4ceb0._.js +2 -2
  384. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cefdba2f._.js +2 -2
  385. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cf9e82bb._.js +2 -2
  386. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d2897392._.js +2 -2
  387. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d3b2d856._.js +2 -2
  388. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d73273ca._.js +1 -1
  389. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8417eb6._.js +2 -2
  390. package/.next/standalone/.next/server/chunks/[root-of-the-server]__dc2a55de._.js +2 -2
  391. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e0d4690b._.js +3 -3
  392. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e678dd53._.js +3 -0
  393. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e9223f55._.js +2 -2
  394. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ea630076._.js +3 -3
  395. package/.next/standalone/.next/server/chunks/[root-of-the-server]__eb8acb65._.js +1 -1
  396. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f26ca49d._.js +1 -1
  397. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f33e1101._.js +1 -1
  398. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f515f865._.js +2 -2
  399. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fceb5d60._.js +98 -0
  400. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fed41403._.js +2 -2
  401. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ff2e98c2._.js +2 -2
  402. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_assess_route_actions_3e8ef2a6.js +3 -0
  403. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_publish_route_actions_49238be3.js +3 -0
  404. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_refine_route_actions_05675688.js +3 -0
  405. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_review_route_actions_5cbb5f6b.js +3 -0
  406. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_seed_route_actions_21084bdb.js +3 -0
  407. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_marketplace_browse_route_actions_7ed0768c.js +3 -0
  408. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_marketplace_preview_route_actions_38d4cc17.js +3 -0
  409. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19afc53d._.js +3 -0
  410. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
  411. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__efef0a06._.js → [root-of-the-server]__ca5beb09._.js} +2 -2
  412. package/.next/standalone/.next/server/chunks/ssr/{_7dd2ac82._.js → _078dd64d._.js} +1 -1
  413. package/.next/standalone/.next/server/chunks/ssr/_163d0838._.js +3 -0
  414. package/.next/standalone/.next/server/chunks/ssr/{_a4eeff0d._.js → _2230ad2d._.js} +2 -2
  415. package/.next/standalone/.next/server/chunks/ssr/{_9303a965._.js → _701606d5._.js} +1 -1
  416. package/.next/standalone/.next/server/chunks/ssr/_72b1de37._.js +3 -0
  417. package/.next/standalone/.next/server/chunks/ssr/{_d39bcfda._.js → _93ef0f79._.js} +2 -2
  418. package/.next/standalone/.next/server/chunks/ssr/_950142a4._.js +1 -1
  419. package/.next/standalone/.next/server/chunks/ssr/_a22b5eb0._.js +3 -0
  420. package/.next/standalone/.next/server/chunks/ssr/_aeeff784._.js +3 -0
  421. package/.next/standalone/.next/server/chunks/ssr/_c1cfdd09._.js +3 -0
  422. package/.next/standalone/.next/server/chunks/ssr/_c2d3f6de._.js +3 -0
  423. package/.next/standalone/.next/server/chunks/ssr/{_8167090e._.js → _db2fec84._.js} +2 -2
  424. package/.next/standalone/.next/server/chunks/ssr/src_02bae6e5._.js +3 -0
  425. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_terminal_page_tsx_de5e8d85._.js +2 -2
  426. package/.next/standalone/.next/server/chunks/ssr/src_components_terminal_terminal-pane_tsx_803c5e2c._.js +2 -2
  427. package/.next/standalone/.next/server/edge/chunks/_d73df637._.js +1 -1
  428. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  429. package/.next/standalone/.next/server/pages/404.html +1 -1
  430. package/.next/standalone/.next/server/pages/500.html +2 -2
  431. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  432. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  433. package/.next/standalone/.next/static/chunks/25b7a243a404a1a7.js +1 -0
  434. package/.next/standalone/.next/static/chunks/2b997e211a5d547b.js +1 -0
  435. package/.next/standalone/.next/static/chunks/5e08abb00653754a.js +1 -0
  436. package/.next/standalone/.next/static/chunks/61f2ed39b75b1efc.js +1 -0
  437. package/.next/standalone/.next/static/chunks/6c78a1dfa7ec2959.css +3 -0
  438. package/.next/standalone/.next/static/chunks/7246f1ee445f7024.js +1 -0
  439. package/.next/standalone/.next/static/chunks/7424664c6ffa94bd.js +1 -0
  440. package/.next/standalone/.next/static/chunks/7e0091ab6c5ee8bd.js +1 -0
  441. package/.next/standalone/.next/static/chunks/8b3f4572fec83caa.js +5 -0
  442. package/.next/standalone/.next/static/chunks/{a7b2795949a6c63e.js → 9899cf4c2bdbe61d.js} +2 -2
  443. package/.next/standalone/.next/static/chunks/ac339e970df82fa5.js +5 -0
  444. package/.next/standalone/.next/static/chunks/{0e61e67b7b8fc3f3.js → c418112e102673ce.js} +1 -1
  445. package/.next/standalone/.next/static/chunks/e2f0a2330dedff4b.js +85 -0
  446. package/.next/standalone/.next/static/chunks/f0c8b3f8cc1939ec.js +1 -0
  447. package/.next/standalone/.next/static/chunks/f9f2628207848ac2.js +1 -0
  448. package/.next/standalone/bin/cortex-hook.sh +62 -62
  449. package/.next/standalone/bin/cortex-mcp.js +60 -60
  450. package/.next/standalone/docs/superpowers/plans/2026-03-13-cortex-wiring.md +1387 -1387
  451. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-entity-graph.md +1923 -1923
  452. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-knowledge-evolution.md +1113 -1113
  453. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-boundary-engine.md +853 -853
  454. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-context-engine.md +1274 -1274
  455. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-signal-ingestion.md +933 -933
  456. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-lobes.md +1080 -1080
  457. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-gravity-system.md +768 -768
  458. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-ui.md +1108 -1108
  459. package/.next/standalone/docs/superpowers/plans/2026-03-18-cortex-ui-integration.md +1846 -0
  460. package/.next/standalone/docs/superpowers/specs/2026-03-13-cortex-wiring-design.md +268 -268
  461. package/.next/standalone/docs/superpowers/specs/2026-03-14-cortex-v2-design.md +623 -623
  462. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-lobes-design.md +263 -263
  463. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md +240 -240
  464. package/.next/standalone/docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md +341 -0
  465. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/README.md +46 -0
  466. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +221 -0
  467. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/index.js +1 -0
  468. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  469. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/package.json +42 -0
  470. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +46 -0
  471. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +221 -0
  472. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +1 -0
  473. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  474. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +42 -0
  475. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +30 -0
  476. package/.next/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  477. package/.next/standalone/node_modules/@img/{sharp-win32-x64 → sharp-linux-x64}/package.json +46 -39
  478. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  479. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +46 -0
  480. package/.next/standalone/package.json +102 -102
  481. package/.next/standalone/server.js +1 -1
  482. package/.next/standalone/src/app/(desktop)/cortex/page.tsx +78 -75
  483. package/.next/standalone/src/app/api/cortex/context/route.ts +78 -78
  484. package/.next/standalone/src/app/api/cortex/curation/assess/route.ts +27 -0
  485. package/.next/standalone/src/app/api/cortex/curation/publish/route.ts +23 -0
  486. package/.next/standalone/src/app/api/cortex/curation/refine/route.ts +23 -0
  487. package/.next/standalone/src/app/api/cortex/curation/review/route.ts +29 -0
  488. package/.next/standalone/src/app/api/cortex/curation/seed/route.ts +23 -0
  489. package/.next/standalone/src/app/api/cortex/export/route.ts +40 -40
  490. package/.next/standalone/src/app/api/cortex/federation/pending/route.ts +20 -20
  491. package/.next/standalone/src/app/api/cortex/federation/resolve/route.ts +43 -43
  492. package/.next/standalone/src/app/api/cortex/federation/search/route.ts +35 -35
  493. package/.next/standalone/src/app/api/cortex/federation/teach/route.ts +76 -76
  494. package/.next/standalone/src/app/api/cortex/graph/edges/route.ts +112 -112
  495. package/.next/standalone/src/app/api/cortex/graph/entities/[id]/route.ts +73 -73
  496. package/.next/standalone/src/app/api/cortex/graph/entities/route.ts +75 -75
  497. package/.next/standalone/src/app/api/cortex/graph/populate/route.ts +203 -203
  498. package/.next/standalone/src/app/api/cortex/import/route.ts +75 -43
  499. package/.next/standalone/src/app/api/cortex/import/status/route.ts +15 -15
  500. package/.next/standalone/src/app/api/cortex/ingest/bootstrap/route.ts +29 -29
  501. package/.next/standalone/src/app/api/cortex/ingest/status/route.ts +15 -15
  502. package/.next/standalone/src/app/api/cortex/knowledge/[id]/route.ts +91 -91
  503. package/.next/standalone/src/app/api/cortex/knowledge/route.ts +93 -93
  504. package/.next/standalone/src/app/api/cortex/lobes/[id]/route.ts +67 -67
  505. package/.next/standalone/src/app/api/cortex/lobes/route.ts +22 -22
  506. package/.next/standalone/src/app/api/cortex/lobes/share/route.ts +80 -80
  507. package/.next/standalone/src/app/api/cortex/marketplace/browse/route.ts +43 -0
  508. package/.next/standalone/src/app/api/cortex/marketplace/preview/route.ts +46 -0
  509. package/.next/standalone/src/app/api/cortex/mcp/call/route.ts +11 -11
  510. package/.next/standalone/src/app/api/cortex/mcp/tools/route.ts +6 -6
  511. package/.next/standalone/src/app/api/cortex/search/route.ts +43 -43
  512. package/.next/standalone/src/app/api/cortex/settings/route.ts +33 -33
  513. package/.next/standalone/src/app/api/cortex/status/route.ts +169 -129
  514. package/.next/standalone/src/app/api/cortex/timeline/route.ts +42 -42
  515. package/.next/standalone/src/app/api/cortex/usage/route.ts +31 -31
  516. package/.next/standalone/src/app/api/cortex/workspace/[id]/context/route.ts +41 -41
  517. package/.next/standalone/src/components/cortex/constants.ts +29 -0
  518. package/.next/standalone/src/components/cortex/cortex-dashboard.tsx +304 -228
  519. package/.next/standalone/src/components/cortex/cortex-indicator.tsx +44 -44
  520. package/.next/standalone/src/components/cortex/cortex-panel.tsx +140 -140
  521. package/.next/standalone/src/components/cortex/cortex-settings.tsx +221 -221
  522. package/.next/standalone/src/components/cortex/curation-tab.tsx +810 -0
  523. package/.next/standalone/src/components/cortex/entity-detail.tsx +101 -101
  524. package/.next/standalone/src/components/cortex/entity-graph.tsx +382 -382
  525. package/.next/standalone/src/components/cortex/import-dialog.tsx +212 -0
  526. package/.next/standalone/src/components/cortex/injection-badge.tsx +72 -72
  527. package/.next/standalone/src/components/cortex/knowledge-card.tsx +109 -127
  528. package/.next/standalone/src/components/cortex/knowledge-tab.tsx +158 -56
  529. package/.next/standalone/src/components/cortex/lobe-settings.tsx +215 -199
  530. package/.next/standalone/src/components/cortex/marketplace-card.tsx +126 -0
  531. package/.next/standalone/src/components/cortex/marketplace-tab.tsx +113 -0
  532. package/.next/standalone/src/lib/cortex/config.ts +40 -40
  533. package/.next/standalone/src/lib/cortex/debug.ts +10 -10
  534. package/.next/standalone/src/lib/cortex/distillation/usage-store.ts +18 -18
  535. package/.next/standalone/src/lib/cortex/graph/resolver.ts +10 -10
  536. package/.next/standalone/src/lib/cortex/graph/types.ts +22 -22
  537. package/.next/standalone/src/lib/cortex/index.ts +56 -56
  538. package/.next/standalone/src/lib/cortex/ingestion/bootstrap.ts +14 -14
  539. package/.next/standalone/src/lib/cortex/knowledge/compat.ts +14 -14
  540. package/.next/standalone/src/lib/cortex/knowledge/contradiction.ts +10 -10
  541. package/.next/standalone/src/lib/cortex/knowledge/types.ts +67 -67
  542. package/.next/standalone/src/lib/cortex/lobes/config.ts +16 -16
  543. package/.next/standalone/src/lib/cortex/lobes/resolver.ts +8 -8
  544. package/.next/standalone/src/lib/cortex/lobes/shares.ts +14 -14
  545. package/.next/standalone/src/lib/cortex/mcp/server.ts +8 -8
  546. package/.next/standalone/src/lib/cortex/portability/exporter.ts +6 -6
  547. package/.next/standalone/src/lib/cortex/portability/importer.ts +10 -10
  548. package/.next/standalone/src/lib/cortex/retrieval/context-engine.ts +10 -10
  549. package/.next/standalone/src/lib/cortex/types.ts +39 -38
  550. package/.next/standalone/tsconfig.json +34 -34
  551. package/LICENSE +661 -661
  552. package/README.md +131 -131
  553. package/bin/cortex-hook.sh +62 -62
  554. package/bin/cortex-mcp.js +60 -60
  555. package/bin/fix-standalone-externals.js +79 -79
  556. package/bin/lib/auto-setup.js +110 -110
  557. package/bin/mdns-service.js +171 -171
  558. package/bin/postinstall.js +35 -35
  559. package/bin/setup-admin.js +195 -195
  560. package/bin/spaces-dev.js +208 -208
  561. package/bin/spaces-install.js +599 -599
  562. package/bin/spaces-reset-totp.js +50 -50
  563. package/bin/spaces-service.js +1020 -1020
  564. package/bin/spaces-setup.js +253 -253
  565. package/bin/spaces.js +776 -728
  566. package/bin/ssh-auth-keys.sh +68 -68
  567. package/bin/terminal-server.js +1649 -1646
  568. package/package.json +102 -102
  569. package/.next/standalone/.claude/settings.local.json +0 -55
  570. package/.next/standalone/.claude/spaces-env.json +0 -1
  571. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ecce08b._.js +0 -3
  572. package/.next/standalone/.next/server/chunks/ssr/_7e63066a._.js +0 -3
  573. package/.next/standalone/.next/server/chunks/ssr/_a012c43b._.js +0 -3
  574. package/.next/standalone/.next/server/chunks/ssr/_b4db3983._.js +0 -3
  575. package/.next/standalone/.next/server/chunks/ssr/_cd50a174._.js +0 -3
  576. package/.next/standalone/.next/server/chunks/ssr/_e7a9e2b0._.js +0 -3
  577. package/.next/standalone/.next/server/chunks/ssr/_ed6c285b._.js +0 -3
  578. package/.next/standalone/.next/server/chunks/ssr/src_133a7c8a._.js +0 -3
  579. package/.next/standalone/.next/static/chunks/17d164c01fa1aaa9.js +0 -5
  580. package/.next/standalone/.next/static/chunks/19da759dde107f02.js +0 -1
  581. package/.next/standalone/.next/static/chunks/58d78765e5140dcb.js +0 -1
  582. package/.next/standalone/.next/static/chunks/596bd56e0ad09173.js +0 -5
  583. package/.next/standalone/.next/static/chunks/78dd908e70bf8c4b.js +0 -85
  584. package/.next/standalone/.next/static/chunks/79aacab676df80c4.js +0 -1
  585. package/.next/standalone/.next/static/chunks/846d6ef408f69390.js +0 -1
  586. package/.next/standalone/.next/static/chunks/8de5e432a2fc563a.js +0 -1
  587. package/.next/standalone/.next/static/chunks/9196173f0d081f2c.js +0 -1
  588. package/.next/standalone/.next/static/chunks/9bd8a119aaeafc9e.js +0 -1
  589. package/.next/standalone/.next/static/chunks/e35e863c09511a51.js +0 -1
  590. package/.next/standalone/.next/static/chunks/f644c11ace7a0d9d.css +0 -3
  591. package/.next/standalone/.spaces/cortex-context.md +0 -70
  592. package/.next/standalone/node_modules/@img/sharp-win32-x64/lib/sharp-win32-x64.node +0 -0
  593. package/.next/standalone/src/components/cortex/context-tab.tsx +0 -171
  594. /package/.next/standalone/.next/static/{B207XFa7QvXAYS7Sqq2_4 → 77VYbwIoyxFNr5xevTrCu}/_buildManifest.js +0 -0
  595. /package/.next/standalone/.next/static/{B207XFa7QvXAYS7Sqq2_4 → 77VYbwIoyxFNr5xevTrCu}/_clientMiddlewareManifest.json +0 -0
  596. /package/.next/standalone/.next/static/{B207XFa7QvXAYS7Sqq2_4 → 77VYbwIoyxFNr5xevTrCu}/_ssgManifest.js +0 -0
  597. /package/.next/standalone/node_modules/@img/{sharp-win32-x64 → sharp-libvips-linux-x64}/versions.json +0 -0
@@ -1,1108 +1,1108 @@
1
- # Cortex v2 UI Implementation Plan
2
-
3
- > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
4
-
5
- **Goal:** Add a dedicated `/cortex` page with interactive entity graph visualization, enhanced knowledge cards with v2 fields, and a context assembly dashboard — plus sidebar navigation and panel enhancements.
6
-
7
- **Architecture:** New `/app/(desktop)/cortex/page.tsx` with tab navigation (Graph | Knowledge | Context | Settings). Force graph rendered via `force-graph` npm package with `nodeCanvasObject` for custom shapes. Small backend tweaks to expose `listAllEdges()`, entities/conflicts/sourceWeights in context API. Existing right panel gets "Open full view" link.
8
-
9
- **Tech Stack:** React 19, Next.js 16, Tailwind CSS 4, force-graph, Lucide icons, TanStack React Query
10
-
11
- **Spec:** `docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md`
12
-
13
- ---
14
-
15
- ## File Structure
16
-
17
- ```
18
- New files:
19
- ├── src/app/(desktop)/cortex/page.tsx — Main /cortex page with tabs
20
- ├── src/components/cortex/entity-graph.tsx — Force graph canvas (dynamic, ssr:false)
21
- ├── src/components/cortex/entity-detail.tsx — Right-side entity detail panel
22
- ├── src/components/cortex/context-tab.tsx — Context assembly inspector tab
23
- ├── src/components/cortex/knowledge-tab.tsx — Knowledge list tab (reuses cards)
24
-
25
- Modified files:
26
- ├── src/components/cortex/knowledge-card.tsx — Add v2 badges + evidence bar
27
- ├── src/components/cortex/cortex-panel.tsx — Add "Open full view" link
28
- ├── src/components/layout/sidebar.tsx — Add Cortex nav item
29
- ├── src/lib/cortex/graph/entity-graph.ts — Add listAllEdges()
30
- ├── src/app/api/cortex/graph/edges/route.ts — Support all=true
31
- ├── src/lib/cortex/retrieval/context-engine.ts — Expose sourceWeights
32
- ├── src/app/api/cortex/context/route.ts — Return entities, conflicts, sourceWeights
33
- ```
34
-
35
- ---
36
-
37
- ## Chunk 1: Backend Tweaks + Enhanced Knowledge Card
38
-
39
- ### Task 1: Add listAllEdges() and edges `all=true` support
40
-
41
- **Files:**
42
- - Modify: `src/lib/cortex/graph/entity-graph.ts`
43
- - Modify: `src/app/api/cortex/graph/edges/route.ts`
44
-
45
- - [ ] **Step 1: Add listAllEdges() to EntityGraph**
46
-
47
- Read `src/lib/cortex/graph/entity-graph.ts`, find the edge methods section, add:
48
-
49
- ```typescript
50
- listAllEdges(): Edge[] {
51
- return (this.db.prepare('SELECT * FROM edges ORDER BY source_id').all() as any[])
52
- .map(r => this.rowToEdge(r));
53
- }
54
- ```
55
-
56
- - [ ] **Step 2: Update edges route GET handler**
57
-
58
- Read `src/app/api/cortex/graph/edges/route.ts`. At the top of the GET handler, before the `from`/`to` check, add:
59
-
60
- ```typescript
61
- const all = url.searchParams.get('all');
62
- if (all === 'true') {
63
- const edges = cortex.graph.listAllEdges();
64
- return NextResponse.json({ edges });
65
- }
66
- ```
67
-
68
- - [ ] **Step 3: Commit**
69
-
70
- ```bash
71
- git add src/lib/cortex/graph/entity-graph.ts src/app/api/cortex/graph/edges/route.ts
72
- git commit -m "feat(cortex): add listAllEdges() and edges all=true endpoint"
73
- ```
74
-
75
- ---
76
-
77
- ### Task 2: Expose sourceWeights in context API
78
-
79
- **Files:**
80
- - Modify: `src/lib/cortex/retrieval/context-engine.ts`
81
- - Modify: `src/app/api/cortex/context/route.ts`
82
-
83
- - [ ] **Step 1: Add sourceWeights to AssemblyResult**
84
-
85
- Read `src/lib/cortex/retrieval/context-engine.ts`. Find the `AssemblyResult` interface and add:
86
-
87
- ```typescript
88
- sourceWeights: Array<{ layerKey: string; scopeLevel: string; weight: number }>;
89
- ```
90
-
91
- Find the `assemble()` method. After `computeSourceWeights()` is called (the `sources` variable), map it into the result:
92
-
93
- ```typescript
94
- // In the return object, add:
95
- sourceWeights: sources.map(s => ({
96
- layerKey: s.layerKey,
97
- scopeLevel: s.layerKey === 'personal' ? 'personal' : s.layerKey.startsWith('workspace') ? 'team' : 'organization',
98
- weight: s.weight,
99
- })),
100
- ```
101
-
102
- - [ ] **Step 2: Update context route response**
103
-
104
- Read `src/app/api/cortex/context/route.ts`. In the `NextResponse.json()` call, change:
105
-
106
- ```typescript
107
- // From:
108
- conflicts: result.conflicts.length,
109
- // To:
110
- entities: result.entities,
111
- conflicts: result.conflicts,
112
- sourceWeights: result.sourceWeights,
113
- ```
114
-
115
- - [ ] **Step 3: Commit**
116
-
117
- ```bash
118
- git add src/lib/cortex/retrieval/context-engine.ts src/app/api/cortex/context/route.ts
119
- git commit -m "feat(cortex): expose entities, conflicts, sourceWeights in context API"
120
- ```
121
-
122
- ---
123
-
124
- ### Task 3: Enhanced knowledge card
125
-
126
- **Files:**
127
- - Modify: `src/components/cortex/knowledge-card.tsx`
128
-
129
- - [ ] **Step 1: Read the current knowledge-card.tsx**
130
-
131
- - [ ] **Step 2: Extend the props interface and add v2 display**
132
-
133
- Replace the entire file. The changes:
134
- - Extend `unit` props with optional v2 fields
135
- - Add sensitivity badge (color-coded)
136
- - Add scope badge
137
- - Add attribution row (creator, source, corroborations)
138
- - Replace confidence bar with evidence bar when available
139
- - Add conflict indicator
140
-
141
- ```typescript
142
- 'use client';
143
-
144
- import { Trash2, AlertTriangle } from 'lucide-react';
145
- import { api } from '@/lib/api';
146
-
147
- const TYPE_COLORS: Record<string, string> = {
148
- decision: 'bg-blue-500/20 text-blue-400',
149
- preference: 'bg-pink-500/20 text-pink-400',
150
- pattern: 'bg-green-500/20 text-green-400',
151
- error_fix: 'bg-amber-500/20 text-amber-400',
152
- context: 'bg-gray-500/20 text-gray-400',
153
- code_pattern: 'bg-cyan-500/20 text-cyan-400',
154
- command: 'bg-orange-500/20 text-orange-400',
155
- conversation: 'bg-slate-500/20 text-slate-400',
156
- summary: 'bg-violet-500/20 text-violet-400',
157
- };
158
-
159
- const SENSITIVITY_COLORS: Record<string, string> = {
160
- public: 'bg-green-500/20 text-green-400',
161
- internal: 'bg-indigo-500/20 text-indigo-400',
162
- restricted: 'bg-amber-500/20 text-amber-400',
163
- confidential: 'bg-red-500/20 text-red-400',
164
- };
165
-
166
- interface KnowledgeCardProps {
167
- unit: {
168
- id: string;
169
- text: string;
170
- type: string;
171
- confidence: number;
172
- created: string;
173
- session_id?: string | null;
174
- layer: string;
175
- stale_score?: number;
176
- // v2 fields
177
- scope?: { level: string; entity_id: string };
178
- sensitivity?: string;
179
- evidence_score?: number;
180
- corroborations?: number;
181
- contradiction_refs?: string[];
182
- origin?: { source_type: string; source_ref: string; creator_entity_id: string };
183
- };
184
- onDelete?: (id: string) => void;
185
- compact?: boolean;
186
- }
187
-
188
- export function KnowledgeCard({ unit, onDelete, compact }: KnowledgeCardProps) {
189
- const colorClass = TYPE_COLORS[unit.type] || TYPE_COLORS.context;
190
- const age = getRelativeAge(unit.created);
191
- const hasConflicts = (unit.contradiction_refs?.length ?? 0) > 0;
192
-
193
- // Use evidence_score if available, else confidence
194
- const score = unit.evidence_score ?? unit.confidence;
195
- const scoreLabel = unit.evidence_score != null
196
- ? `${score.toFixed(2)} evidence`
197
- : `${Math.round(score * 100)}%`;
198
-
199
- const handleDelete = async () => {
200
- await fetch(api(`/api/cortex/knowledge/${unit.id}`), { method: 'DELETE' });
201
- onDelete?.(unit.id);
202
- };
203
-
204
- return (
205
- <div className="group border border-white/5 rounded-lg p-3 hover:border-white/10 transition-colors">
206
- {/* Badge row */}
207
- <div className="flex items-start justify-between gap-2">
208
- <div className="flex items-center gap-1 flex-wrap">
209
- <span className={`text-[10px] px-1.5 py-0.5 rounded font-medium ${colorClass}`}>
210
- {unit.type.replace('_', ' ')}
211
- </span>
212
- {unit.sensitivity && (
213
- <span className={`text-[10px] px-1.5 py-0.5 rounded font-medium ${SENSITIVITY_COLORS[unit.sensitivity] || SENSITIVITY_COLORS.internal}`}>
214
- {unit.sensitivity}
215
- </span>
216
- )}
217
- {unit.scope && (
218
- <span className="text-[10px] px-1.5 py-0.5 rounded font-medium bg-purple-500/10 text-purple-400">
219
- {unit.scope.level}
220
- </span>
221
- )}
222
- {(unit.stale_score ?? 0) > 0.3 && (
223
- <span className="text-[10px] px-1.5 py-0.5 rounded font-medium bg-amber-500/20 text-amber-400">
224
- stale
225
- </span>
226
- )}
227
- {hasConflicts && (
228
- <span className="text-[10px] px-1.5 py-0.5 rounded font-medium bg-amber-500/20 text-amber-400 flex items-center gap-0.5">
229
- <AlertTriangle className="w-2.5 h-2.5" />
230
- contested
231
- </span>
232
- )}
233
- </div>
234
- <div className="flex items-center gap-2 text-[10px] text-gray-500 shrink-0">
235
- <span>{age}</span>
236
- {onDelete && (
237
- <button
238
- onClick={handleDelete}
239
- className="opacity-0 group-hover:opacity-100 transition-opacity text-red-400 hover:text-red-300"
240
- >
241
- <Trash2 className="w-3 h-3" />
242
- </button>
243
- )}
244
- </div>
245
- </div>
246
-
247
- {/* Text */}
248
- <p className="text-xs text-gray-300 mt-1.5 leading-relaxed line-clamp-3">{unit.text}</p>
249
-
250
- {/* Attribution row (v2) */}
251
- {!compact && unit.origin && (
252
- <div className="flex items-center gap-1.5 mt-1.5 text-[10px] text-gray-500 flex-wrap">
253
- <span>by {unit.origin.creator_entity_id.replace('person-', '')}</span>
254
- <span>&middot;</span>
255
- <span>via {unit.origin.source_type.replace('_', ' ')}</span>
256
- {(unit.corroborations ?? 0) > 0 && (
257
- <>
258
- <span>&middot;</span>
259
- <span className="text-green-400">{unit.corroborations} corr.</span>
260
- </>
261
- )}
262
- </div>
263
- )}
264
-
265
- {/* Evidence/confidence bar */}
266
- <div className="flex items-center gap-2 mt-2">
267
- <div className="flex-1 h-1 bg-white/5 rounded-full overflow-hidden">
268
- <div
269
- className="h-full bg-purple-500/50 rounded-full"
270
- style={{ width: `${Math.round(score * 100)}%` }}
271
- />
272
- </div>
273
- <span className="text-[10px] text-gray-500 tabular-nums">{scoreLabel}</span>
274
- </div>
275
- </div>
276
- );
277
- }
278
-
279
- function getRelativeAge(iso: string): string {
280
- const diff = Date.now() - new Date(iso).getTime();
281
- const days = Math.floor(diff / (1000 * 60 * 60 * 24));
282
- if (days === 0) return 'today';
283
- if (days === 1) return '1d ago';
284
- if (days < 30) return `${days}d ago`;
285
- if (days < 365) return `${Math.floor(days / 30)}mo ago`;
286
- return `${Math.floor(days / 365)}y ago`;
287
- }
288
- ```
289
-
290
- - [ ] **Step 3: Commit**
291
-
292
- ```bash
293
- git add src/components/cortex/knowledge-card.tsx
294
- git commit -m "feat(cortex): enhance knowledge card with v2 fields display"
295
- ```
296
-
297
- ---
298
-
299
- ## Chunk 2: Cortex Page + Sidebar
300
-
301
- ### Task 4: Sidebar navigation
302
-
303
- **Files:**
304
- - Modify: `src/components/layout/sidebar.tsx`
305
-
306
- - [ ] **Step 1: Read sidebar.tsx**
307
-
308
- - [ ] **Step 2: Add Cortex to nav array and imports**
309
-
310
- Add `Brain` to the lucide-react import. Add a Cortex entry to the `nav` array (after Network, before Settings):
311
-
312
- ```typescript
313
- // Add to imports:
314
- import { ..., Brain } from 'lucide-react';
315
-
316
- // Add to nav array (before Settings):
317
- { href: '/cortex', label: 'Cortex', icon: Brain },
318
-
319
- // Add to routeNames:
320
- '/cortex': 'cortex',
321
- ```
322
-
323
- In the nav filter, gate it like Network:
324
- ```typescript
325
- if (href === '/cortex') return hasCortex;
326
- ```
327
-
328
- - [ ] **Step 3: Commit**
329
-
330
- ```bash
331
- git add src/components/layout/sidebar.tsx
332
- git commit -m "feat(cortex): add Cortex nav item to sidebar"
333
- ```
334
-
335
- ---
336
-
337
- ### Task 5: Cortex page with tabs
338
-
339
- **Files:**
340
- - Create: `src/app/(desktop)/cortex/page.tsx`
341
-
342
- - [ ] **Step 1: Create the page**
343
-
344
- ```typescript
345
- 'use client';
346
-
347
- import { useState, useEffect } from 'react';
348
- import dynamic from 'next/dynamic';
349
- import { api } from '@/lib/api';
350
- import { KnowledgeTab } from '@/components/cortex/knowledge-tab';
351
- import { ContextTab } from '@/components/cortex/context-tab';
352
- import { CortexSettings } from '@/components/cortex/cortex-settings';
353
-
354
- const EntityGraphView = dynamic(
355
- () => import('@/components/cortex/entity-graph').then(m => ({ default: m.EntityGraphView })),
356
- { ssr: false, loading: () => <div className="flex-1 flex items-center justify-center text-gray-500 text-sm">Loading graph...</div> }
357
- );
358
-
359
- type Tab = 'graph' | 'knowledge' | 'context' | 'settings';
360
-
361
- export default function CortexPage() {
362
- const [tab, setTab] = useState<Tab>('graph');
363
- const [stats, setStats] = useState<any>(null);
364
-
365
- useEffect(() => {
366
- fetch(api('/api/cortex/status'))
367
- .then(r => r.json())
368
- .then(setStats)
369
- .catch(() => {});
370
- }, []);
371
-
372
- const tabs: { key: Tab; label: string }[] = [
373
- { key: 'graph', label: 'Graph' },
374
- { key: 'knowledge', label: 'Knowledge' },
375
- { key: 'context', label: 'Context' },
376
- { key: 'settings', label: 'Settings' },
377
- ];
378
-
379
- const totalKnowledge = stats
380
- ? Object.values(stats.layers || {}).reduce((sum: number, l: any) => sum + (l.count || 0), 0)
381
- : 0;
382
-
383
- return (
384
- <div className="flex flex-col h-screen bg-gray-950">
385
- {/* Tab bar */}
386
- <div className="flex items-center border-b border-white/5 px-4 shrink-0">
387
- <div className="flex">
388
- {tabs.map(t => (
389
- <button
390
- key={t.key}
391
- onClick={() => setTab(t.key)}
392
- className={`px-5 py-3 text-sm font-medium transition-colors border-b-2 ${
393
- tab === t.key
394
- ? 'text-purple-400 border-purple-400'
395
- : 'text-gray-500 border-transparent hover:text-gray-300'
396
- }`}
397
- >
398
- {t.label}
399
- </button>
400
- ))}
401
- </div>
402
- <div className="ml-auto text-xs text-gray-600">
403
- {totalKnowledge} knowledge units
404
- </div>
405
- </div>
406
-
407
- {/* Tab content */}
408
- <div className="flex-1 overflow-hidden">
409
- {tab === 'graph' && <EntityGraphView />}
410
- {tab === 'knowledge' && <KnowledgeTab />}
411
- {tab === 'context' && <ContextTab />}
412
- {tab === 'settings' && (
413
- <div className="p-6 max-w-2xl">
414
- <CortexSettings />
415
- </div>
416
- )}
417
- </div>
418
- </div>
419
- );
420
- }
421
- ```
422
-
423
- - [ ] **Step 2: Commit**
424
-
425
- ```bash
426
- git add src/app/(desktop)/cortex/page.tsx
427
- git commit -m "feat(cortex): add /cortex page with tab navigation"
428
- ```
429
-
430
- ---
431
-
432
- ### Task 6: Panel "Open full view" link
433
-
434
- **Files:**
435
- - Modify: `src/components/cortex/cortex-panel.tsx`
436
-
437
- - [ ] **Step 1: Add link to panel header**
438
-
439
- Read `src/components/cortex/cortex-panel.tsx`. In the header div (between the "Cortex" heading and the close button), add:
440
-
441
- ```typescript
442
- import Link from 'next/link';
443
- import { ExternalLink } from 'lucide-react';
444
-
445
- // In the header, after the h2:
446
- <Link
447
- href="/cortex"
448
- className="text-[10px] text-purple-400 hover:text-purple-300 flex items-center gap-1"
449
- onClick={onClose}
450
- >
451
- Full view <ExternalLink className="w-2.5 h-2.5" />
452
- </Link>
453
- ```
454
-
455
- - [ ] **Step 2: Commit**
456
-
457
- ```bash
458
- git add src/components/cortex/cortex-panel.tsx
459
- git commit -m "feat(cortex): add 'Full view' link to cortex panel"
460
- ```
461
-
462
- ---
463
-
464
- ## Chunk 3: Graph + Detail Components
465
-
466
- ### Task 7: Entity graph canvas component
467
-
468
- **Files:**
469
- - Create: `src/components/cortex/entity-graph.tsx`
470
-
471
- - [ ] **Step 1: Install force-graph**
472
-
473
- ```bash
474
- npm install force-graph
475
- ```
476
-
477
- - [ ] **Step 2: Create the graph component**
478
-
479
- ```typescript
480
- 'use client';
481
-
482
- import { useEffect, useRef, useState, useCallback } from 'react';
483
- import ForceGraph2D from 'force-graph';
484
- import { api } from '@/lib/api';
485
- import { EntityDetail } from './entity-detail';
486
-
487
- const NODE_COLORS: Record<string, string> = {
488
- person: '#7c3aed',
489
- team: '#10b981',
490
- project: '#10b981',
491
- department: '#3b82f6',
492
- organization: '#3b82f6',
493
- system: '#f59e0b',
494
- module: '#f59e0b',
495
- topic: '#06b6d4',
496
- };
497
-
498
- interface GraphNode {
499
- id: string;
500
- name: string;
501
- type: string;
502
- metadata: Record<string, unknown>;
503
- // force-graph adds x, y, vx, vy
504
- x?: number;
505
- y?: number;
506
- }
507
-
508
- interface GraphLink {
509
- source: string;
510
- target: string;
511
- relation: string;
512
- weight: number;
513
- }
514
-
515
- export function EntityGraphView() {
516
- const containerRef = useRef<HTMLDivElement>(null);
517
- const graphRef = useRef<any>(null);
518
- const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);
519
- const [graphData, setGraphData] = useState<{ nodes: GraphNode[]; links: GraphLink[] }>({ nodes: [], links: [] });
520
-
521
- // Fetch graph data
522
- useEffect(() => {
523
- Promise.all([
524
- fetch(api('/api/cortex/graph/entities')).then(r => r.json()),
525
- fetch(api('/api/cortex/graph/edges?all=true')).then(r => r.json()),
526
- ]).then(([entData, edgeData]) => {
527
- const nodes: GraphNode[] = (entData.entities || []).map((e: any) => ({
528
- id: e.id,
529
- name: e.name,
530
- type: e.type,
531
- metadata: e.metadata || {},
532
- }));
533
- const nodeIds = new Set(nodes.map(n => n.id));
534
- const links: GraphLink[] = (edgeData.edges || [])
535
- .filter((e: any) => nodeIds.has(e.source_id) && nodeIds.has(e.target_id))
536
- .map((e: any) => ({
537
- source: e.source_id,
538
- target: e.target_id,
539
- relation: e.relation,
540
- weight: e.weight,
541
- }));
542
- setGraphData({ nodes, links });
543
- }).catch(() => {});
544
- }, []);
545
-
546
- // Initialize force-graph
547
- useEffect(() => {
548
- if (!containerRef.current || graphData.nodes.length === 0) return;
549
-
550
- const width = containerRef.current.clientWidth;
551
- const height = containerRef.current.clientHeight;
552
-
553
- const graph = ForceGraph2D()(containerRef.current)
554
- .width(width)
555
- .height(height)
556
- .graphData(graphData)
557
- .nodeId('id')
558
- .nodeLabel((node: any) => `${node.name} (${node.type})`)
559
- .nodeCanvasObject((node: any, ctx: CanvasRenderingContext2D, globalScale: number) => {
560
- const color = NODE_COLORS[node.type] || '#666';
561
- const size = node.type === 'person' ? 8 : node.type === 'topic' ? 5 : 6;
562
- const x = node.x ?? 0;
563
- const y = node.y ?? 0;
564
-
565
- ctx.beginPath();
566
- if (node.type === 'system' || node.type === 'module') {
567
- // Diamond
568
- ctx.moveTo(x, y - size);
569
- ctx.lineTo(x + size, y);
570
- ctx.lineTo(x, y + size);
571
- ctx.lineTo(x - size, y);
572
- ctx.closePath();
573
- } else if (node.type === 'team' || node.type === 'project' || node.type === 'department' || node.type === 'organization') {
574
- // Rounded rect
575
- const w = size * 2;
576
- const h = size * 1.5;
577
- const r = 2;
578
- ctx.roundRect(x - w / 2, y - h / 2, w, h, r);
579
- } else {
580
- // Circle (person, topic)
581
- ctx.arc(x, y, size, 0, 2 * Math.PI);
582
- }
583
-
584
- ctx.fillStyle = color + '33';
585
- ctx.fill();
586
- ctx.strokeStyle = color;
587
- ctx.lineWidth = 1.5 / globalScale;
588
- ctx.stroke();
589
-
590
- // Label
591
- const fontSize = Math.max(10 / globalScale, 3);
592
- ctx.font = `${fontSize}px sans-serif`;
593
- ctx.textAlign = 'center';
594
- ctx.textBaseline = 'middle';
595
- ctx.fillStyle = color;
596
- ctx.fillText(node.name, x, y + size + fontSize);
597
- })
598
- .nodePointerAreaPaint((node: any, color: string, ctx: CanvasRenderingContext2D) => {
599
- const size = 10;
600
- ctx.fillStyle = color;
601
- ctx.beginPath();
602
- ctx.arc(node.x ?? 0, node.y ?? 0, size, 0, 2 * Math.PI);
603
- ctx.fill();
604
- })
605
- .linkColor(() => 'rgba(124, 58, 237, 0.2)')
606
- .linkWidth((link: any) => Math.max(0.5, link.weight * 2))
607
- .onNodeClick((node: any) => setSelectedNode(node))
608
- .onBackgroundClick(() => setSelectedNode(null))
609
- .backgroundColor('#06060c');
610
-
611
- graphRef.current = graph;
612
-
613
- const handleResize = () => {
614
- if (!containerRef.current) return;
615
- graph.width(containerRef.current.clientWidth);
616
- graph.height(containerRef.current.clientHeight);
617
- };
618
- window.addEventListener('resize', handleResize);
619
-
620
- return () => {
621
- window.removeEventListener('resize', handleResize);
622
- graph._destructor?.();
623
- };
624
- }, [graphData]);
625
-
626
- const handleRecenter = useCallback(() => {
627
- graphRef.current?.zoomToFit(400, 40);
628
- }, []);
629
-
630
- return (
631
- <div className="flex h-full">
632
- {/* Graph canvas */}
633
- <div className="flex-1 relative">
634
- <div ref={containerRef} className="w-full h-full" />
635
-
636
- {/* Controls overlay */}
637
- <div className="absolute bottom-3 left-3 flex gap-2">
638
- <button
639
- onClick={handleRecenter}
640
- className="px-3 py-1.5 text-xs bg-gray-900/80 border border-white/10 rounded text-gray-400 hover:text-gray-200"
641
- >
642
- Recenter
643
- </button>
644
- </div>
645
-
646
- {/* Legend overlay */}
647
- <div className="absolute top-3 right-3 bg-gray-950/90 border border-white/10 rounded-lg p-3 text-[10px] space-y-1">
648
- {Object.entries(NODE_COLORS).filter(([type]) =>
649
- ['person', 'team', 'system', 'topic'].includes(type)
650
- ).map(([type, color]) => (
651
- <div key={type} className="flex items-center gap-2">
652
- <span style={{ color }} className="text-sm">
653
- {type === 'system' ? '◆' : type === 'team' ? '■' : '●'}
654
- </span>
655
- <span className="text-gray-400 capitalize">{type}</span>
656
- </div>
657
- ))}
658
- </div>
659
-
660
- {graphData.nodes.length === 0 && (
661
- <div className="absolute inset-0 flex items-center justify-center text-gray-600 text-sm">
662
- No entities yet. Add entities via the API to see the graph.
663
- </div>
664
- )}
665
- </div>
666
-
667
- {/* Detail panel */}
668
- <div className="w-72 border-l border-white/5 bg-gray-950 overflow-y-auto">
669
- <EntityDetail
670
- node={selectedNode}
671
- onClose={() => setSelectedNode(null)}
672
- />
673
- </div>
674
- </div>
675
- );
676
- }
677
- ```
678
-
679
- - [ ] **Step 3: Commit**
680
-
681
- ```bash
682
- git add src/components/cortex/entity-graph.tsx
683
- git commit -m "feat(cortex): add force-graph entity visualization component"
684
- ```
685
-
686
- ---
687
-
688
- ### Task 8: Entity detail panel
689
-
690
- **Files:**
691
- - Create: `src/components/cortex/entity-detail.tsx`
692
-
693
- - [ ] **Step 1: Create the component**
694
-
695
- ```typescript
696
- 'use client';
697
-
698
- import { useState, useEffect } from 'react';
699
- import { api } from '@/lib/api';
700
-
701
- const RELATION_COLORS: Record<string, string> = {
702
- member_of: 'text-purple-400',
703
- expert_in: 'text-cyan-400',
704
- owns: 'text-green-400',
705
- contains: 'text-green-400',
706
- part_of: 'text-blue-400',
707
- works_on: 'text-purple-400',
708
- touches: 'text-amber-400',
709
- depends_on: 'text-red-400',
710
- relates_to: 'text-cyan-400',
711
- };
712
-
713
- interface EntityDetailProps {
714
- node: { id: string; name: string; type: string; metadata: Record<string, unknown> } | null;
715
- onClose: () => void;
716
- }
717
-
718
- export function EntityDetail({ node, onClose }: EntityDetailProps) {
719
- const [edges, setEdges] = useState<any[]>([]);
720
-
721
- useEffect(() => {
722
- if (!node) { setEdges([]); return; }
723
-
724
- Promise.all([
725
- fetch(api(`/api/cortex/graph/edges?from=${node.id}`)).then(r => r.json()),
726
- fetch(api(`/api/cortex/graph/edges?to=${node.id}`)).then(r => r.json()),
727
- ]).then(([fromData, toData]) => {
728
- const allEdges = [
729
- ...(fromData.edges || []).map((e: any) => ({ ...e, direction: 'out' })),
730
- ...(toData.edges || []).map((e: any) => ({ ...e, direction: 'in' })),
731
- ];
732
- setEdges(allEdges);
733
- }).catch(() => {});
734
- }, [node?.id]);
735
-
736
- if (!node) {
737
- return (
738
- <div className="p-4 text-center text-gray-600 text-xs mt-8">
739
- Click a node to see details
740
- </div>
741
- );
742
- }
743
-
744
- const firstLetter = node.name.charAt(0).toUpperCase();
745
- const color = node.type === 'person' ? '#7c3aed'
746
- : node.type === 'system' ? '#f59e0b'
747
- : node.type === 'topic' ? '#06b6d4'
748
- : '#10b981';
749
-
750
- return (
751
- <div className="p-4">
752
- {/* Header */}
753
- <div className="flex items-center gap-3 mb-4">
754
- <div
755
- className="w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold"
756
- style={{ backgroundColor: color + '33', color, border: `2px solid ${color}` }}
757
- >
758
- {firstLetter}
759
- </div>
760
- <div>
761
- <div className="text-sm font-medium text-gray-200">{node.name}</div>
762
- <div className="text-[10px] text-gray-500">{node.type}</div>
763
- </div>
764
- </div>
765
-
766
- {/* Metadata */}
767
- {Object.keys(node.metadata).length > 0 && (
768
- <div className="mb-4">
769
- <div className="text-[10px] text-gray-600 uppercase tracking-wider mb-1">Metadata</div>
770
- {Object.entries(node.metadata).map(([k, v]) => (
771
- <div key={k} className="text-[11px] text-gray-400">
772
- <span className="text-gray-600">{k}:</span> {String(v)}
773
- </div>
774
- ))}
775
- </div>
776
- )}
777
-
778
- {/* Relationships */}
779
- <div className="text-[10px] text-gray-600 uppercase tracking-wider mb-2">
780
- Relationships ({edges.length})
781
- </div>
782
- <div className="space-y-1 mb-4">
783
- {edges.map((e, i) => {
784
- const relColor = RELATION_COLORS[e.relation] || 'text-gray-400';
785
- const target = e.direction === 'out' ? e.target_id : e.source_id;
786
- const arrow = e.direction === 'out' ? '→' : '←';
787
- return (
788
- <div key={i} className="flex items-center gap-1.5 text-[11px] bg-white/[0.02] rounded px-2 py-1.5">
789
- <span className={relColor}>{e.relation}</span>
790
- <span className="text-gray-600">{arrow}</span>
791
- <span className="text-gray-300 truncate">{target.replace(/^(person|team|system|topic|project|department|organization|module)-/, '')}</span>
792
- {e.weight < 1 && (
793
- <span className="text-gray-600 ml-auto text-[9px]">{e.weight.toFixed(2)}</span>
794
- )}
795
- </div>
796
- );
797
- })}
798
- {edges.length === 0 && (
799
- <div className="text-[11px] text-gray-600 py-2">No relationships</div>
800
- )}
801
- </div>
802
- </div>
803
- );
804
- }
805
- ```
806
-
807
- - [ ] **Step 2: Commit**
808
-
809
- ```bash
810
- git add src/components/cortex/entity-detail.tsx
811
- git commit -m "feat(cortex): add entity detail panel for graph view"
812
- ```
813
-
814
- ---
815
-
816
- ## Chunk 4: Knowledge Tab, Context Tab, Final Wiring
817
-
818
- ### Task 9: Knowledge tab component
819
-
820
- **Files:**
821
- - Create: `src/components/cortex/knowledge-tab.tsx`
822
-
823
- - [ ] **Step 1: Create the component**
824
-
825
- A search + list view that reuses `KnowledgeCard`. Fetches from `/api/cortex/search`.
826
-
827
- ```typescript
828
- 'use client';
829
-
830
- import { useState, useCallback, useEffect } from 'react';
831
- import { Search } from 'lucide-react';
832
- import { api } from '@/lib/api';
833
- import { KnowledgeCard } from './knowledge-card';
834
-
835
- export function KnowledgeTab() {
836
- const [query, setQuery] = useState('');
837
- const [results, setResults] = useState<any[]>([]);
838
- const [loading, setLoading] = useState(false);
839
-
840
- const fetchResults = useCallback(async (q?: string) => {
841
- setLoading(true);
842
- try {
843
- const params = new URLSearchParams({ limit: '30' });
844
- if (q) params.set('q', q);
845
- const res = await fetch(api(`/api/cortex/search?${params}`));
846
- if (res.ok) setResults((await res.json()).results || []);
847
- } catch {}
848
- setLoading(false);
849
- }, []);
850
-
851
- useEffect(() => { fetchResults(); }, [fetchResults]);
852
-
853
- const handleSearch = () => fetchResults(query.trim() || undefined);
854
- const handleDelete = (id: string) => setResults(prev => prev.filter(r => r.id !== id));
855
-
856
- return (
857
- <div className="flex flex-col h-full">
858
- <div className="p-4 border-b border-white/5">
859
- <div className="relative max-w-md">
860
- <Search className="absolute left-3 top-2.5 w-4 h-4 text-gray-500" />
861
- <input
862
- value={query}
863
- onChange={e => setQuery(e.target.value)}
864
- onKeyDown={e => e.key === 'Enter' && handleSearch()}
865
- placeholder="Search knowledge..."
866
- className="w-full pl-9 pr-4 py-2 text-sm bg-white/5 border border-white/10 rounded-lg text-gray-300 placeholder-gray-600 focus:outline-none focus:border-purple-500/50"
867
- />
868
- </div>
869
- </div>
870
- <div className="flex-1 overflow-y-auto p-4">
871
- <div className="max-w-2xl space-y-2">
872
- {loading && <p className="text-sm text-gray-500 text-center py-8">Loading...</p>}
873
- {!loading && results.length === 0 && (
874
- <p className="text-sm text-gray-500 text-center py-8">No knowledge found</p>
875
- )}
876
- {results.map(unit => (
877
- <KnowledgeCard key={unit.id} unit={unit} onDelete={handleDelete} />
878
- ))}
879
- </div>
880
- </div>
881
- </div>
882
- );
883
- }
884
- ```
885
-
886
- - [ ] **Step 2: Commit**
887
-
888
- ```bash
889
- git add src/components/cortex/knowledge-tab.tsx
890
- git commit -m "feat(cortex): add knowledge tab with search and v2 cards"
891
- ```
892
-
893
- ---
894
-
895
- ### Task 10: Context assembly tab
896
-
897
- **Files:**
898
- - Create: `src/components/cortex/context-tab.tsx`
899
-
900
- - [ ] **Step 1: Create the component**
901
-
902
- ```typescript
903
- 'use client';
904
-
905
- import { useState } from 'react';
906
- import { Search, ChevronDown, ChevronUp } from 'lucide-react';
907
- import { api } from '@/lib/api';
908
-
909
- const INTENT_COLORS: Record<string, string> = {
910
- debugging: 'text-red-400',
911
- architecture: 'text-blue-400',
912
- onboarding: 'text-green-400',
913
- policy: 'text-purple-400',
914
- 'how-to': 'text-amber-400',
915
- review: 'text-pink-400',
916
- security: 'text-red-500',
917
- general: 'text-gray-400',
918
- };
919
-
920
- export function ContextTab() {
921
- const [query, setQuery] = useState('');
922
- const [result, setResult] = useState<any>(null);
923
- const [loading, setLoading] = useState(false);
924
- const [showRaw, setShowRaw] = useState(false);
925
-
926
- const handleAnalyze = async () => {
927
- if (!query.trim()) return;
928
- setLoading(true);
929
- try {
930
- const res = await fetch(api(`/api/cortex/context?q=${encodeURIComponent(query)}&limit=5`));
931
- if (res.ok) setResult(await res.json());
932
- } catch {}
933
- setLoading(false);
934
- };
935
-
936
- return (
937
- <div className="p-6 max-w-3xl mx-auto">
938
- {/* Query input */}
939
- <div className="flex gap-3 mb-6">
940
- <div className="flex-1 relative">
941
- <Search className="absolute left-3 top-2.5 w-4 h-4 text-gray-500" />
942
- <input
943
- value={query}
944
- onChange={e => setQuery(e.target.value)}
945
- onKeyDown={e => e.key === 'Enter' && handleAnalyze()}
946
- placeholder="Enter a query to analyze..."
947
- className="w-full pl-9 pr-4 py-2 text-sm bg-white/5 border border-white/10 rounded-lg text-gray-300 placeholder-gray-600 focus:outline-none focus:border-purple-500/50"
948
- />
949
- </div>
950
- <button
951
- onClick={handleAnalyze}
952
- disabled={loading}
953
- className="px-5 py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg disabled:opacity-50"
954
- >
955
- {loading ? 'Analyzing...' : 'Analyze'}
956
- </button>
957
- </div>
958
-
959
- {!result && !loading && (
960
- <p className="text-sm text-gray-600 text-center py-12">
961
- Enter a query to see how the Context Assembly Engine processes it
962
- </p>
963
- )}
964
-
965
- {result && (
966
- <>
967
- {/* Pipeline summary */}
968
- <div className="grid grid-cols-3 gap-3 mb-6">
969
- <div className="bg-white/[0.02] border border-white/5 rounded-lg p-3">
970
- <div className="text-[10px] text-gray-600 uppercase mb-1">Intent</div>
971
- <div className={`text-lg font-semibold ${INTENT_COLORS[result.intent?.intent] || 'text-gray-400'}`}>
972
- {result.intent?.intent || '?'}
973
- </div>
974
- <div className="text-[10px] text-gray-600">
975
- confidence: {(result.intent?.confidence ?? 0).toFixed(2)}
976
- </div>
977
- </div>
978
- <div className="bg-white/[0.02] border border-white/5 rounded-lg p-3">
979
- <div className="text-[10px] text-gray-600 uppercase mb-1">Entities</div>
980
- <div className="flex flex-wrap gap-1 mt-1">
981
- {(result.entities || []).map((e: any, i: number) => (
982
- <span key={i} className="text-[10px] px-1.5 py-0.5 bg-white/5 border border-white/10 rounded text-gray-300">
983
- {e.entity?.type}:{e.entity?.name}
984
- </span>
985
- ))}
986
- {(!result.entities || result.entities.length === 0) && (
987
- <span className="text-[10px] text-gray-600">none detected</span>
988
- )}
989
- </div>
990
- </div>
991
- <div className="bg-white/[0.02] border border-white/5 rounded-lg p-3">
992
- <div className="text-[10px] text-gray-600 uppercase mb-1">Timing</div>
993
- <div className="text-lg font-semibold text-green-400">
994
- {result.timing?.totalMs ?? '?'}ms
995
- </div>
996
- <div className="text-[10px] text-gray-600">
997
- intent {result.timing?.intentMs}ms · search {result.timing?.searchMs}ms
998
- </div>
999
- </div>
1000
- </div>
1001
-
1002
- {/* Source weights */}
1003
- {result.sourceWeights && (
1004
- <div className="mb-6">
1005
- <div className="text-[10px] text-gray-600 uppercase mb-2">Source Weights</div>
1006
- <div className="flex gap-3">
1007
- {result.sourceWeights.map((sw: any, i: number) => (
1008
- <div key={i} className="flex-1 bg-white/[0.02] rounded-lg p-3">
1009
- <div className="flex justify-between text-[11px] mb-1">
1010
- <span className="text-gray-300 capitalize">{sw.scopeLevel}</span>
1011
- <span className="text-gray-500">{sw.weight.toFixed(2)}</span>
1012
- </div>
1013
- <div className="h-1.5 bg-white/5 rounded-full overflow-hidden">
1014
- <div
1015
- className="h-full bg-purple-500/60 rounded-full"
1016
- style={{ width: `${Math.min(100, sw.weight * 100)}%` }}
1017
- />
1018
- </div>
1019
- </div>
1020
- ))}
1021
- </div>
1022
- </div>
1023
- )}
1024
-
1025
- {/* Results */}
1026
- <div className="mb-6">
1027
- <div className="text-[10px] text-gray-600 uppercase mb-2">
1028
- Results ({(result.results || []).length})
1029
- </div>
1030
- <div className="space-y-1">
1031
- {(result.results || []).map((r: any, i: number) => (
1032
- <div key={i} className="flex items-center gap-2 bg-white/[0.02] border border-white/5 rounded-lg px-3 py-2">
1033
- <span className={`text-[10px] px-1.5 py-0.5 rounded font-medium ${
1034
- r.type === 'error_fix' ? 'bg-amber-500/20 text-amber-400'
1035
- : r.type === 'decision' ? 'bg-blue-500/20 text-blue-400'
1036
- : 'bg-gray-500/20 text-gray-400'
1037
- }`}>{r.type?.replace('_', ' ')}</span>
1038
- <span className="text-xs text-gray-300 truncate flex-1">{r.text}</span>
1039
- <span className="text-[10px] text-gray-600 tabular-nums shrink-0">
1040
- {(r.relevance_score ?? 0).toFixed(3)}
1041
- </span>
1042
- </div>
1043
- ))}
1044
- </div>
1045
- </div>
1046
-
1047
- {/* Conflicts */}
1048
- {Array.isArray(result.conflicts) && result.conflicts.length > 0 && (
1049
- <div className="mb-6 border border-amber-500/20 bg-amber-500/5 rounded-lg p-3">
1050
- <div className="text-[10px] text-amber-400 uppercase font-medium mb-1">
1051
- Conflicts ({result.conflicts.length})
1052
- </div>
1053
- {result.conflicts.map((c: any, i: number) => (
1054
- <div key={i} className="text-xs text-gray-400 mt-1">
1055
- &ldquo;{c.unitA?.text?.slice(0, 60)}...&rdquo; vs &ldquo;{c.unitB?.text?.slice(0, 60)}...&rdquo;
1056
- </div>
1057
- ))}
1058
- </div>
1059
- )}
1060
-
1061
- {/* Raw context */}
1062
- <div>
1063
- <button
1064
- onClick={() => setShowRaw(!showRaw)}
1065
- className="flex items-center gap-1 text-[10px] text-gray-600 hover:text-gray-400 uppercase"
1066
- >
1067
- Raw context {showRaw ? <ChevronUp className="w-3 h-3" /> : <ChevronDown className="w-3 h-3" />}
1068
- </button>
1069
- {showRaw && result.context && (
1070
- <pre className="mt-2 p-3 bg-white/[0.02] border border-white/5 rounded-lg text-[11px] text-gray-400 overflow-x-auto whitespace-pre-wrap">
1071
- {result.context}
1072
- </pre>
1073
- )}
1074
- </div>
1075
- </>
1076
- )}
1077
- </div>
1078
- );
1079
- }
1080
- ```
1081
-
1082
- - [ ] **Step 2: Commit**
1083
-
1084
- ```bash
1085
- git add src/components/cortex/context-tab.tsx
1086
- git commit -m "feat(cortex): add context assembly inspector tab"
1087
- ```
1088
-
1089
- ---
1090
-
1091
- ## Summary
1092
-
1093
- | Task | Component | Status |
1094
- |------|-----------|--------|
1095
- | 1 | listAllEdges() + edges all=true | |
1096
- | 2 | Context API expansion (entities, conflicts, sourceWeights) | |
1097
- | 3 | Enhanced knowledge card (v2 fields) | |
1098
- | 4 | Sidebar Cortex nav item | |
1099
- | 5 | /cortex page with tabs | |
1100
- | 6 | Panel "Open full view" link | |
1101
- | 7 | Entity graph canvas (force-graph) | |
1102
- | 8 | Entity detail panel | |
1103
- | 9 | Knowledge tab | |
1104
- | 10 | Context assembly tab | |
1105
-
1106
- **Total: 10 tasks, 4 chunks**
1107
-
1108
- **No tests in this plan** — these are UI components that render from existing tested APIs. The backend changes (Tasks 1-2) are trivial additions to already-tested modules.
1
+ # Cortex v2 UI Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Add a dedicated `/cortex` page with interactive entity graph visualization, enhanced knowledge cards with v2 fields, and a context assembly dashboard — plus sidebar navigation and panel enhancements.
6
+
7
+ **Architecture:** New `/app/(desktop)/cortex/page.tsx` with tab navigation (Graph | Knowledge | Context | Settings). Force graph rendered via `force-graph` npm package with `nodeCanvasObject` for custom shapes. Small backend tweaks to expose `listAllEdges()`, entities/conflicts/sourceWeights in context API. Existing right panel gets "Open full view" link.
8
+
9
+ **Tech Stack:** React 19, Next.js 16, Tailwind CSS 4, force-graph, Lucide icons, TanStack React Query
10
+
11
+ **Spec:** `docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md`
12
+
13
+ ---
14
+
15
+ ## File Structure
16
+
17
+ ```
18
+ New files:
19
+ ├── src/app/(desktop)/cortex/page.tsx — Main /cortex page with tabs
20
+ ├── src/components/cortex/entity-graph.tsx — Force graph canvas (dynamic, ssr:false)
21
+ ├── src/components/cortex/entity-detail.tsx — Right-side entity detail panel
22
+ ├── src/components/cortex/context-tab.tsx — Context assembly inspector tab
23
+ ├── src/components/cortex/knowledge-tab.tsx — Knowledge list tab (reuses cards)
24
+
25
+ Modified files:
26
+ ├── src/components/cortex/knowledge-card.tsx — Add v2 badges + evidence bar
27
+ ├── src/components/cortex/cortex-panel.tsx — Add "Open full view" link
28
+ ├── src/components/layout/sidebar.tsx — Add Cortex nav item
29
+ ├── src/lib/cortex/graph/entity-graph.ts — Add listAllEdges()
30
+ ├── src/app/api/cortex/graph/edges/route.ts — Support all=true
31
+ ├── src/lib/cortex/retrieval/context-engine.ts — Expose sourceWeights
32
+ ├── src/app/api/cortex/context/route.ts — Return entities, conflicts, sourceWeights
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Chunk 1: Backend Tweaks + Enhanced Knowledge Card
38
+
39
+ ### Task 1: Add listAllEdges() and edges `all=true` support
40
+
41
+ **Files:**
42
+ - Modify: `src/lib/cortex/graph/entity-graph.ts`
43
+ - Modify: `src/app/api/cortex/graph/edges/route.ts`
44
+
45
+ - [ ] **Step 1: Add listAllEdges() to EntityGraph**
46
+
47
+ Read `src/lib/cortex/graph/entity-graph.ts`, find the edge methods section, add:
48
+
49
+ ```typescript
50
+ listAllEdges(): Edge[] {
51
+ return (this.db.prepare('SELECT * FROM edges ORDER BY source_id').all() as any[])
52
+ .map(r => this.rowToEdge(r));
53
+ }
54
+ ```
55
+
56
+ - [ ] **Step 2: Update edges route GET handler**
57
+
58
+ Read `src/app/api/cortex/graph/edges/route.ts`. At the top of the GET handler, before the `from`/`to` check, add:
59
+
60
+ ```typescript
61
+ const all = url.searchParams.get('all');
62
+ if (all === 'true') {
63
+ const edges = cortex.graph.listAllEdges();
64
+ return NextResponse.json({ edges });
65
+ }
66
+ ```
67
+
68
+ - [ ] **Step 3: Commit**
69
+
70
+ ```bash
71
+ git add src/lib/cortex/graph/entity-graph.ts src/app/api/cortex/graph/edges/route.ts
72
+ git commit -m "feat(cortex): add listAllEdges() and edges all=true endpoint"
73
+ ```
74
+
75
+ ---
76
+
77
+ ### Task 2: Expose sourceWeights in context API
78
+
79
+ **Files:**
80
+ - Modify: `src/lib/cortex/retrieval/context-engine.ts`
81
+ - Modify: `src/app/api/cortex/context/route.ts`
82
+
83
+ - [ ] **Step 1: Add sourceWeights to AssemblyResult**
84
+
85
+ Read `src/lib/cortex/retrieval/context-engine.ts`. Find the `AssemblyResult` interface and add:
86
+
87
+ ```typescript
88
+ sourceWeights: Array<{ layerKey: string; scopeLevel: string; weight: number }>;
89
+ ```
90
+
91
+ Find the `assemble()` method. After `computeSourceWeights()` is called (the `sources` variable), map it into the result:
92
+
93
+ ```typescript
94
+ // In the return object, add:
95
+ sourceWeights: sources.map(s => ({
96
+ layerKey: s.layerKey,
97
+ scopeLevel: s.layerKey === 'personal' ? 'personal' : s.layerKey.startsWith('workspace') ? 'team' : 'organization',
98
+ weight: s.weight,
99
+ })),
100
+ ```
101
+
102
+ - [ ] **Step 2: Update context route response**
103
+
104
+ Read `src/app/api/cortex/context/route.ts`. In the `NextResponse.json()` call, change:
105
+
106
+ ```typescript
107
+ // From:
108
+ conflicts: result.conflicts.length,
109
+ // To:
110
+ entities: result.entities,
111
+ conflicts: result.conflicts,
112
+ sourceWeights: result.sourceWeights,
113
+ ```
114
+
115
+ - [ ] **Step 3: Commit**
116
+
117
+ ```bash
118
+ git add src/lib/cortex/retrieval/context-engine.ts src/app/api/cortex/context/route.ts
119
+ git commit -m "feat(cortex): expose entities, conflicts, sourceWeights in context API"
120
+ ```
121
+
122
+ ---
123
+
124
+ ### Task 3: Enhanced knowledge card
125
+
126
+ **Files:**
127
+ - Modify: `src/components/cortex/knowledge-card.tsx`
128
+
129
+ - [ ] **Step 1: Read the current knowledge-card.tsx**
130
+
131
+ - [ ] **Step 2: Extend the props interface and add v2 display**
132
+
133
+ Replace the entire file. The changes:
134
+ - Extend `unit` props with optional v2 fields
135
+ - Add sensitivity badge (color-coded)
136
+ - Add scope badge
137
+ - Add attribution row (creator, source, corroborations)
138
+ - Replace confidence bar with evidence bar when available
139
+ - Add conflict indicator
140
+
141
+ ```typescript
142
+ 'use client';
143
+
144
+ import { Trash2, AlertTriangle } from 'lucide-react';
145
+ import { api } from '@/lib/api';
146
+
147
+ const TYPE_COLORS: Record<string, string> = {
148
+ decision: 'bg-blue-500/20 text-blue-400',
149
+ preference: 'bg-pink-500/20 text-pink-400',
150
+ pattern: 'bg-green-500/20 text-green-400',
151
+ error_fix: 'bg-amber-500/20 text-amber-400',
152
+ context: 'bg-gray-500/20 text-gray-400',
153
+ code_pattern: 'bg-cyan-500/20 text-cyan-400',
154
+ command: 'bg-orange-500/20 text-orange-400',
155
+ conversation: 'bg-slate-500/20 text-slate-400',
156
+ summary: 'bg-violet-500/20 text-violet-400',
157
+ };
158
+
159
+ const SENSITIVITY_COLORS: Record<string, string> = {
160
+ public: 'bg-green-500/20 text-green-400',
161
+ internal: 'bg-indigo-500/20 text-indigo-400',
162
+ restricted: 'bg-amber-500/20 text-amber-400',
163
+ confidential: 'bg-red-500/20 text-red-400',
164
+ };
165
+
166
+ interface KnowledgeCardProps {
167
+ unit: {
168
+ id: string;
169
+ text: string;
170
+ type: string;
171
+ confidence: number;
172
+ created: string;
173
+ session_id?: string | null;
174
+ layer: string;
175
+ stale_score?: number;
176
+ // v2 fields
177
+ scope?: { level: string; entity_id: string };
178
+ sensitivity?: string;
179
+ evidence_score?: number;
180
+ corroborations?: number;
181
+ contradiction_refs?: string[];
182
+ origin?: { source_type: string; source_ref: string; creator_entity_id: string };
183
+ };
184
+ onDelete?: (id: string) => void;
185
+ compact?: boolean;
186
+ }
187
+
188
+ export function KnowledgeCard({ unit, onDelete, compact }: KnowledgeCardProps) {
189
+ const colorClass = TYPE_COLORS[unit.type] || TYPE_COLORS.context;
190
+ const age = getRelativeAge(unit.created);
191
+ const hasConflicts = (unit.contradiction_refs?.length ?? 0) > 0;
192
+
193
+ // Use evidence_score if available, else confidence
194
+ const score = unit.evidence_score ?? unit.confidence;
195
+ const scoreLabel = unit.evidence_score != null
196
+ ? `${score.toFixed(2)} evidence`
197
+ : `${Math.round(score * 100)}%`;
198
+
199
+ const handleDelete = async () => {
200
+ await fetch(api(`/api/cortex/knowledge/${unit.id}`), { method: 'DELETE' });
201
+ onDelete?.(unit.id);
202
+ };
203
+
204
+ return (
205
+ <div className="group border border-white/5 rounded-lg p-3 hover:border-white/10 transition-colors">
206
+ {/* Badge row */}
207
+ <div className="flex items-start justify-between gap-2">
208
+ <div className="flex items-center gap-1 flex-wrap">
209
+ <span className={`text-[10px] px-1.5 py-0.5 rounded font-medium ${colorClass}`}>
210
+ {unit.type.replace('_', ' ')}
211
+ </span>
212
+ {unit.sensitivity && (
213
+ <span className={`text-[10px] px-1.5 py-0.5 rounded font-medium ${SENSITIVITY_COLORS[unit.sensitivity] || SENSITIVITY_COLORS.internal}`}>
214
+ {unit.sensitivity}
215
+ </span>
216
+ )}
217
+ {unit.scope && (
218
+ <span className="text-[10px] px-1.5 py-0.5 rounded font-medium bg-purple-500/10 text-purple-400">
219
+ {unit.scope.level}
220
+ </span>
221
+ )}
222
+ {(unit.stale_score ?? 0) > 0.3 && (
223
+ <span className="text-[10px] px-1.5 py-0.5 rounded font-medium bg-amber-500/20 text-amber-400">
224
+ stale
225
+ </span>
226
+ )}
227
+ {hasConflicts && (
228
+ <span className="text-[10px] px-1.5 py-0.5 rounded font-medium bg-amber-500/20 text-amber-400 flex items-center gap-0.5">
229
+ <AlertTriangle className="w-2.5 h-2.5" />
230
+ contested
231
+ </span>
232
+ )}
233
+ </div>
234
+ <div className="flex items-center gap-2 text-[10px] text-gray-500 shrink-0">
235
+ <span>{age}</span>
236
+ {onDelete && (
237
+ <button
238
+ onClick={handleDelete}
239
+ className="opacity-0 group-hover:opacity-100 transition-opacity text-red-400 hover:text-red-300"
240
+ >
241
+ <Trash2 className="w-3 h-3" />
242
+ </button>
243
+ )}
244
+ </div>
245
+ </div>
246
+
247
+ {/* Text */}
248
+ <p className="text-xs text-gray-300 mt-1.5 leading-relaxed line-clamp-3">{unit.text}</p>
249
+
250
+ {/* Attribution row (v2) */}
251
+ {!compact && unit.origin && (
252
+ <div className="flex items-center gap-1.5 mt-1.5 text-[10px] text-gray-500 flex-wrap">
253
+ <span>by {unit.origin.creator_entity_id.replace('person-', '')}</span>
254
+ <span>&middot;</span>
255
+ <span>via {unit.origin.source_type.replace('_', ' ')}</span>
256
+ {(unit.corroborations ?? 0) > 0 && (
257
+ <>
258
+ <span>&middot;</span>
259
+ <span className="text-green-400">{unit.corroborations} corr.</span>
260
+ </>
261
+ )}
262
+ </div>
263
+ )}
264
+
265
+ {/* Evidence/confidence bar */}
266
+ <div className="flex items-center gap-2 mt-2">
267
+ <div className="flex-1 h-1 bg-white/5 rounded-full overflow-hidden">
268
+ <div
269
+ className="h-full bg-purple-500/50 rounded-full"
270
+ style={{ width: `${Math.round(score * 100)}%` }}
271
+ />
272
+ </div>
273
+ <span className="text-[10px] text-gray-500 tabular-nums">{scoreLabel}</span>
274
+ </div>
275
+ </div>
276
+ );
277
+ }
278
+
279
+ function getRelativeAge(iso: string): string {
280
+ const diff = Date.now() - new Date(iso).getTime();
281
+ const days = Math.floor(diff / (1000 * 60 * 60 * 24));
282
+ if (days === 0) return 'today';
283
+ if (days === 1) return '1d ago';
284
+ if (days < 30) return `${days}d ago`;
285
+ if (days < 365) return `${Math.floor(days / 30)}mo ago`;
286
+ return `${Math.floor(days / 365)}y ago`;
287
+ }
288
+ ```
289
+
290
+ - [ ] **Step 3: Commit**
291
+
292
+ ```bash
293
+ git add src/components/cortex/knowledge-card.tsx
294
+ git commit -m "feat(cortex): enhance knowledge card with v2 fields display"
295
+ ```
296
+
297
+ ---
298
+
299
+ ## Chunk 2: Cortex Page + Sidebar
300
+
301
+ ### Task 4: Sidebar navigation
302
+
303
+ **Files:**
304
+ - Modify: `src/components/layout/sidebar.tsx`
305
+
306
+ - [ ] **Step 1: Read sidebar.tsx**
307
+
308
+ - [ ] **Step 2: Add Cortex to nav array and imports**
309
+
310
+ Add `Brain` to the lucide-react import. Add a Cortex entry to the `nav` array (after Network, before Settings):
311
+
312
+ ```typescript
313
+ // Add to imports:
314
+ import { ..., Brain } from 'lucide-react';
315
+
316
+ // Add to nav array (before Settings):
317
+ { href: '/cortex', label: 'Cortex', icon: Brain },
318
+
319
+ // Add to routeNames:
320
+ '/cortex': 'cortex',
321
+ ```
322
+
323
+ In the nav filter, gate it like Network:
324
+ ```typescript
325
+ if (href === '/cortex') return hasCortex;
326
+ ```
327
+
328
+ - [ ] **Step 3: Commit**
329
+
330
+ ```bash
331
+ git add src/components/layout/sidebar.tsx
332
+ git commit -m "feat(cortex): add Cortex nav item to sidebar"
333
+ ```
334
+
335
+ ---
336
+
337
+ ### Task 5: Cortex page with tabs
338
+
339
+ **Files:**
340
+ - Create: `src/app/(desktop)/cortex/page.tsx`
341
+
342
+ - [ ] **Step 1: Create the page**
343
+
344
+ ```typescript
345
+ 'use client';
346
+
347
+ import { useState, useEffect } from 'react';
348
+ import dynamic from 'next/dynamic';
349
+ import { api } from '@/lib/api';
350
+ import { KnowledgeTab } from '@/components/cortex/knowledge-tab';
351
+ import { ContextTab } from '@/components/cortex/context-tab';
352
+ import { CortexSettings } from '@/components/cortex/cortex-settings';
353
+
354
+ const EntityGraphView = dynamic(
355
+ () => import('@/components/cortex/entity-graph').then(m => ({ default: m.EntityGraphView })),
356
+ { ssr: false, loading: () => <div className="flex-1 flex items-center justify-center text-gray-500 text-sm">Loading graph...</div> }
357
+ );
358
+
359
+ type Tab = 'graph' | 'knowledge' | 'context' | 'settings';
360
+
361
+ export default function CortexPage() {
362
+ const [tab, setTab] = useState<Tab>('graph');
363
+ const [stats, setStats] = useState<any>(null);
364
+
365
+ useEffect(() => {
366
+ fetch(api('/api/cortex/status'))
367
+ .then(r => r.json())
368
+ .then(setStats)
369
+ .catch(() => {});
370
+ }, []);
371
+
372
+ const tabs: { key: Tab; label: string }[] = [
373
+ { key: 'graph', label: 'Graph' },
374
+ { key: 'knowledge', label: 'Knowledge' },
375
+ { key: 'context', label: 'Context' },
376
+ { key: 'settings', label: 'Settings' },
377
+ ];
378
+
379
+ const totalKnowledge = stats
380
+ ? Object.values(stats.layers || {}).reduce((sum: number, l: any) => sum + (l.count || 0), 0)
381
+ : 0;
382
+
383
+ return (
384
+ <div className="flex flex-col h-screen bg-gray-950">
385
+ {/* Tab bar */}
386
+ <div className="flex items-center border-b border-white/5 px-4 shrink-0">
387
+ <div className="flex">
388
+ {tabs.map(t => (
389
+ <button
390
+ key={t.key}
391
+ onClick={() => setTab(t.key)}
392
+ className={`px-5 py-3 text-sm font-medium transition-colors border-b-2 ${
393
+ tab === t.key
394
+ ? 'text-purple-400 border-purple-400'
395
+ : 'text-gray-500 border-transparent hover:text-gray-300'
396
+ }`}
397
+ >
398
+ {t.label}
399
+ </button>
400
+ ))}
401
+ </div>
402
+ <div className="ml-auto text-xs text-gray-600">
403
+ {totalKnowledge} knowledge units
404
+ </div>
405
+ </div>
406
+
407
+ {/* Tab content */}
408
+ <div className="flex-1 overflow-hidden">
409
+ {tab === 'graph' && <EntityGraphView />}
410
+ {tab === 'knowledge' && <KnowledgeTab />}
411
+ {tab === 'context' && <ContextTab />}
412
+ {tab === 'settings' && (
413
+ <div className="p-6 max-w-2xl">
414
+ <CortexSettings />
415
+ </div>
416
+ )}
417
+ </div>
418
+ </div>
419
+ );
420
+ }
421
+ ```
422
+
423
+ - [ ] **Step 2: Commit**
424
+
425
+ ```bash
426
+ git add src/app/(desktop)/cortex/page.tsx
427
+ git commit -m "feat(cortex): add /cortex page with tab navigation"
428
+ ```
429
+
430
+ ---
431
+
432
+ ### Task 6: Panel "Open full view" link
433
+
434
+ **Files:**
435
+ - Modify: `src/components/cortex/cortex-panel.tsx`
436
+
437
+ - [ ] **Step 1: Add link to panel header**
438
+
439
+ Read `src/components/cortex/cortex-panel.tsx`. In the header div (between the "Cortex" heading and the close button), add:
440
+
441
+ ```typescript
442
+ import Link from 'next/link';
443
+ import { ExternalLink } from 'lucide-react';
444
+
445
+ // In the header, after the h2:
446
+ <Link
447
+ href="/cortex"
448
+ className="text-[10px] text-purple-400 hover:text-purple-300 flex items-center gap-1"
449
+ onClick={onClose}
450
+ >
451
+ Full view <ExternalLink className="w-2.5 h-2.5" />
452
+ </Link>
453
+ ```
454
+
455
+ - [ ] **Step 2: Commit**
456
+
457
+ ```bash
458
+ git add src/components/cortex/cortex-panel.tsx
459
+ git commit -m "feat(cortex): add 'Full view' link to cortex panel"
460
+ ```
461
+
462
+ ---
463
+
464
+ ## Chunk 3: Graph + Detail Components
465
+
466
+ ### Task 7: Entity graph canvas component
467
+
468
+ **Files:**
469
+ - Create: `src/components/cortex/entity-graph.tsx`
470
+
471
+ - [ ] **Step 1: Install force-graph**
472
+
473
+ ```bash
474
+ npm install force-graph
475
+ ```
476
+
477
+ - [ ] **Step 2: Create the graph component**
478
+
479
+ ```typescript
480
+ 'use client';
481
+
482
+ import { useEffect, useRef, useState, useCallback } from 'react';
483
+ import ForceGraph2D from 'force-graph';
484
+ import { api } from '@/lib/api';
485
+ import { EntityDetail } from './entity-detail';
486
+
487
+ const NODE_COLORS: Record<string, string> = {
488
+ person: '#7c3aed',
489
+ team: '#10b981',
490
+ project: '#10b981',
491
+ department: '#3b82f6',
492
+ organization: '#3b82f6',
493
+ system: '#f59e0b',
494
+ module: '#f59e0b',
495
+ topic: '#06b6d4',
496
+ };
497
+
498
+ interface GraphNode {
499
+ id: string;
500
+ name: string;
501
+ type: string;
502
+ metadata: Record<string, unknown>;
503
+ // force-graph adds x, y, vx, vy
504
+ x?: number;
505
+ y?: number;
506
+ }
507
+
508
+ interface GraphLink {
509
+ source: string;
510
+ target: string;
511
+ relation: string;
512
+ weight: number;
513
+ }
514
+
515
+ export function EntityGraphView() {
516
+ const containerRef = useRef<HTMLDivElement>(null);
517
+ const graphRef = useRef<any>(null);
518
+ const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);
519
+ const [graphData, setGraphData] = useState<{ nodes: GraphNode[]; links: GraphLink[] }>({ nodes: [], links: [] });
520
+
521
+ // Fetch graph data
522
+ useEffect(() => {
523
+ Promise.all([
524
+ fetch(api('/api/cortex/graph/entities')).then(r => r.json()),
525
+ fetch(api('/api/cortex/graph/edges?all=true')).then(r => r.json()),
526
+ ]).then(([entData, edgeData]) => {
527
+ const nodes: GraphNode[] = (entData.entities || []).map((e: any) => ({
528
+ id: e.id,
529
+ name: e.name,
530
+ type: e.type,
531
+ metadata: e.metadata || {},
532
+ }));
533
+ const nodeIds = new Set(nodes.map(n => n.id));
534
+ const links: GraphLink[] = (edgeData.edges || [])
535
+ .filter((e: any) => nodeIds.has(e.source_id) && nodeIds.has(e.target_id))
536
+ .map((e: any) => ({
537
+ source: e.source_id,
538
+ target: e.target_id,
539
+ relation: e.relation,
540
+ weight: e.weight,
541
+ }));
542
+ setGraphData({ nodes, links });
543
+ }).catch(() => {});
544
+ }, []);
545
+
546
+ // Initialize force-graph
547
+ useEffect(() => {
548
+ if (!containerRef.current || graphData.nodes.length === 0) return;
549
+
550
+ const width = containerRef.current.clientWidth;
551
+ const height = containerRef.current.clientHeight;
552
+
553
+ const graph = ForceGraph2D()(containerRef.current)
554
+ .width(width)
555
+ .height(height)
556
+ .graphData(graphData)
557
+ .nodeId('id')
558
+ .nodeLabel((node: any) => `${node.name} (${node.type})`)
559
+ .nodeCanvasObject((node: any, ctx: CanvasRenderingContext2D, globalScale: number) => {
560
+ const color = NODE_COLORS[node.type] || '#666';
561
+ const size = node.type === 'person' ? 8 : node.type === 'topic' ? 5 : 6;
562
+ const x = node.x ?? 0;
563
+ const y = node.y ?? 0;
564
+
565
+ ctx.beginPath();
566
+ if (node.type === 'system' || node.type === 'module') {
567
+ // Diamond
568
+ ctx.moveTo(x, y - size);
569
+ ctx.lineTo(x + size, y);
570
+ ctx.lineTo(x, y + size);
571
+ ctx.lineTo(x - size, y);
572
+ ctx.closePath();
573
+ } else if (node.type === 'team' || node.type === 'project' || node.type === 'department' || node.type === 'organization') {
574
+ // Rounded rect
575
+ const w = size * 2;
576
+ const h = size * 1.5;
577
+ const r = 2;
578
+ ctx.roundRect(x - w / 2, y - h / 2, w, h, r);
579
+ } else {
580
+ // Circle (person, topic)
581
+ ctx.arc(x, y, size, 0, 2 * Math.PI);
582
+ }
583
+
584
+ ctx.fillStyle = color + '33';
585
+ ctx.fill();
586
+ ctx.strokeStyle = color;
587
+ ctx.lineWidth = 1.5 / globalScale;
588
+ ctx.stroke();
589
+
590
+ // Label
591
+ const fontSize = Math.max(10 / globalScale, 3);
592
+ ctx.font = `${fontSize}px sans-serif`;
593
+ ctx.textAlign = 'center';
594
+ ctx.textBaseline = 'middle';
595
+ ctx.fillStyle = color;
596
+ ctx.fillText(node.name, x, y + size + fontSize);
597
+ })
598
+ .nodePointerAreaPaint((node: any, color: string, ctx: CanvasRenderingContext2D) => {
599
+ const size = 10;
600
+ ctx.fillStyle = color;
601
+ ctx.beginPath();
602
+ ctx.arc(node.x ?? 0, node.y ?? 0, size, 0, 2 * Math.PI);
603
+ ctx.fill();
604
+ })
605
+ .linkColor(() => 'rgba(124, 58, 237, 0.2)')
606
+ .linkWidth((link: any) => Math.max(0.5, link.weight * 2))
607
+ .onNodeClick((node: any) => setSelectedNode(node))
608
+ .onBackgroundClick(() => setSelectedNode(null))
609
+ .backgroundColor('#06060c');
610
+
611
+ graphRef.current = graph;
612
+
613
+ const handleResize = () => {
614
+ if (!containerRef.current) return;
615
+ graph.width(containerRef.current.clientWidth);
616
+ graph.height(containerRef.current.clientHeight);
617
+ };
618
+ window.addEventListener('resize', handleResize);
619
+
620
+ return () => {
621
+ window.removeEventListener('resize', handleResize);
622
+ graph._destructor?.();
623
+ };
624
+ }, [graphData]);
625
+
626
+ const handleRecenter = useCallback(() => {
627
+ graphRef.current?.zoomToFit(400, 40);
628
+ }, []);
629
+
630
+ return (
631
+ <div className="flex h-full">
632
+ {/* Graph canvas */}
633
+ <div className="flex-1 relative">
634
+ <div ref={containerRef} className="w-full h-full" />
635
+
636
+ {/* Controls overlay */}
637
+ <div className="absolute bottom-3 left-3 flex gap-2">
638
+ <button
639
+ onClick={handleRecenter}
640
+ className="px-3 py-1.5 text-xs bg-gray-900/80 border border-white/10 rounded text-gray-400 hover:text-gray-200"
641
+ >
642
+ Recenter
643
+ </button>
644
+ </div>
645
+
646
+ {/* Legend overlay */}
647
+ <div className="absolute top-3 right-3 bg-gray-950/90 border border-white/10 rounded-lg p-3 text-[10px] space-y-1">
648
+ {Object.entries(NODE_COLORS).filter(([type]) =>
649
+ ['person', 'team', 'system', 'topic'].includes(type)
650
+ ).map(([type, color]) => (
651
+ <div key={type} className="flex items-center gap-2">
652
+ <span style={{ color }} className="text-sm">
653
+ {type === 'system' ? '◆' : type === 'team' ? '■' : '●'}
654
+ </span>
655
+ <span className="text-gray-400 capitalize">{type}</span>
656
+ </div>
657
+ ))}
658
+ </div>
659
+
660
+ {graphData.nodes.length === 0 && (
661
+ <div className="absolute inset-0 flex items-center justify-center text-gray-600 text-sm">
662
+ No entities yet. Add entities via the API to see the graph.
663
+ </div>
664
+ )}
665
+ </div>
666
+
667
+ {/* Detail panel */}
668
+ <div className="w-72 border-l border-white/5 bg-gray-950 overflow-y-auto">
669
+ <EntityDetail
670
+ node={selectedNode}
671
+ onClose={() => setSelectedNode(null)}
672
+ />
673
+ </div>
674
+ </div>
675
+ );
676
+ }
677
+ ```
678
+
679
+ - [ ] **Step 3: Commit**
680
+
681
+ ```bash
682
+ git add src/components/cortex/entity-graph.tsx
683
+ git commit -m "feat(cortex): add force-graph entity visualization component"
684
+ ```
685
+
686
+ ---
687
+
688
+ ### Task 8: Entity detail panel
689
+
690
+ **Files:**
691
+ - Create: `src/components/cortex/entity-detail.tsx`
692
+
693
+ - [ ] **Step 1: Create the component**
694
+
695
+ ```typescript
696
+ 'use client';
697
+
698
+ import { useState, useEffect } from 'react';
699
+ import { api } from '@/lib/api';
700
+
701
+ const RELATION_COLORS: Record<string, string> = {
702
+ member_of: 'text-purple-400',
703
+ expert_in: 'text-cyan-400',
704
+ owns: 'text-green-400',
705
+ contains: 'text-green-400',
706
+ part_of: 'text-blue-400',
707
+ works_on: 'text-purple-400',
708
+ touches: 'text-amber-400',
709
+ depends_on: 'text-red-400',
710
+ relates_to: 'text-cyan-400',
711
+ };
712
+
713
+ interface EntityDetailProps {
714
+ node: { id: string; name: string; type: string; metadata: Record<string, unknown> } | null;
715
+ onClose: () => void;
716
+ }
717
+
718
+ export function EntityDetail({ node, onClose }: EntityDetailProps) {
719
+ const [edges, setEdges] = useState<any[]>([]);
720
+
721
+ useEffect(() => {
722
+ if (!node) { setEdges([]); return; }
723
+
724
+ Promise.all([
725
+ fetch(api(`/api/cortex/graph/edges?from=${node.id}`)).then(r => r.json()),
726
+ fetch(api(`/api/cortex/graph/edges?to=${node.id}`)).then(r => r.json()),
727
+ ]).then(([fromData, toData]) => {
728
+ const allEdges = [
729
+ ...(fromData.edges || []).map((e: any) => ({ ...e, direction: 'out' })),
730
+ ...(toData.edges || []).map((e: any) => ({ ...e, direction: 'in' })),
731
+ ];
732
+ setEdges(allEdges);
733
+ }).catch(() => {});
734
+ }, [node?.id]);
735
+
736
+ if (!node) {
737
+ return (
738
+ <div className="p-4 text-center text-gray-600 text-xs mt-8">
739
+ Click a node to see details
740
+ </div>
741
+ );
742
+ }
743
+
744
+ const firstLetter = node.name.charAt(0).toUpperCase();
745
+ const color = node.type === 'person' ? '#7c3aed'
746
+ : node.type === 'system' ? '#f59e0b'
747
+ : node.type === 'topic' ? '#06b6d4'
748
+ : '#10b981';
749
+
750
+ return (
751
+ <div className="p-4">
752
+ {/* Header */}
753
+ <div className="flex items-center gap-3 mb-4">
754
+ <div
755
+ className="w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold"
756
+ style={{ backgroundColor: color + '33', color, border: `2px solid ${color}` }}
757
+ >
758
+ {firstLetter}
759
+ </div>
760
+ <div>
761
+ <div className="text-sm font-medium text-gray-200">{node.name}</div>
762
+ <div className="text-[10px] text-gray-500">{node.type}</div>
763
+ </div>
764
+ </div>
765
+
766
+ {/* Metadata */}
767
+ {Object.keys(node.metadata).length > 0 && (
768
+ <div className="mb-4">
769
+ <div className="text-[10px] text-gray-600 uppercase tracking-wider mb-1">Metadata</div>
770
+ {Object.entries(node.metadata).map(([k, v]) => (
771
+ <div key={k} className="text-[11px] text-gray-400">
772
+ <span className="text-gray-600">{k}:</span> {String(v)}
773
+ </div>
774
+ ))}
775
+ </div>
776
+ )}
777
+
778
+ {/* Relationships */}
779
+ <div className="text-[10px] text-gray-600 uppercase tracking-wider mb-2">
780
+ Relationships ({edges.length})
781
+ </div>
782
+ <div className="space-y-1 mb-4">
783
+ {edges.map((e, i) => {
784
+ const relColor = RELATION_COLORS[e.relation] || 'text-gray-400';
785
+ const target = e.direction === 'out' ? e.target_id : e.source_id;
786
+ const arrow = e.direction === 'out' ? '→' : '←';
787
+ return (
788
+ <div key={i} className="flex items-center gap-1.5 text-[11px] bg-white/[0.02] rounded px-2 py-1.5">
789
+ <span className={relColor}>{e.relation}</span>
790
+ <span className="text-gray-600">{arrow}</span>
791
+ <span className="text-gray-300 truncate">{target.replace(/^(person|team|system|topic|project|department|organization|module)-/, '')}</span>
792
+ {e.weight < 1 && (
793
+ <span className="text-gray-600 ml-auto text-[9px]">{e.weight.toFixed(2)}</span>
794
+ )}
795
+ </div>
796
+ );
797
+ })}
798
+ {edges.length === 0 && (
799
+ <div className="text-[11px] text-gray-600 py-2">No relationships</div>
800
+ )}
801
+ </div>
802
+ </div>
803
+ );
804
+ }
805
+ ```
806
+
807
+ - [ ] **Step 2: Commit**
808
+
809
+ ```bash
810
+ git add src/components/cortex/entity-detail.tsx
811
+ git commit -m "feat(cortex): add entity detail panel for graph view"
812
+ ```
813
+
814
+ ---
815
+
816
+ ## Chunk 4: Knowledge Tab, Context Tab, Final Wiring
817
+
818
+ ### Task 9: Knowledge tab component
819
+
820
+ **Files:**
821
+ - Create: `src/components/cortex/knowledge-tab.tsx`
822
+
823
+ - [ ] **Step 1: Create the component**
824
+
825
+ A search + list view that reuses `KnowledgeCard`. Fetches from `/api/cortex/search`.
826
+
827
+ ```typescript
828
+ 'use client';
829
+
830
+ import { useState, useCallback, useEffect } from 'react';
831
+ import { Search } from 'lucide-react';
832
+ import { api } from '@/lib/api';
833
+ import { KnowledgeCard } from './knowledge-card';
834
+
835
+ export function KnowledgeTab() {
836
+ const [query, setQuery] = useState('');
837
+ const [results, setResults] = useState<any[]>([]);
838
+ const [loading, setLoading] = useState(false);
839
+
840
+ const fetchResults = useCallback(async (q?: string) => {
841
+ setLoading(true);
842
+ try {
843
+ const params = new URLSearchParams({ limit: '30' });
844
+ if (q) params.set('q', q);
845
+ const res = await fetch(api(`/api/cortex/search?${params}`));
846
+ if (res.ok) setResults((await res.json()).results || []);
847
+ } catch {}
848
+ setLoading(false);
849
+ }, []);
850
+
851
+ useEffect(() => { fetchResults(); }, [fetchResults]);
852
+
853
+ const handleSearch = () => fetchResults(query.trim() || undefined);
854
+ const handleDelete = (id: string) => setResults(prev => prev.filter(r => r.id !== id));
855
+
856
+ return (
857
+ <div className="flex flex-col h-full">
858
+ <div className="p-4 border-b border-white/5">
859
+ <div className="relative max-w-md">
860
+ <Search className="absolute left-3 top-2.5 w-4 h-4 text-gray-500" />
861
+ <input
862
+ value={query}
863
+ onChange={e => setQuery(e.target.value)}
864
+ onKeyDown={e => e.key === 'Enter' && handleSearch()}
865
+ placeholder="Search knowledge..."
866
+ className="w-full pl-9 pr-4 py-2 text-sm bg-white/5 border border-white/10 rounded-lg text-gray-300 placeholder-gray-600 focus:outline-none focus:border-purple-500/50"
867
+ />
868
+ </div>
869
+ </div>
870
+ <div className="flex-1 overflow-y-auto p-4">
871
+ <div className="max-w-2xl space-y-2">
872
+ {loading && <p className="text-sm text-gray-500 text-center py-8">Loading...</p>}
873
+ {!loading && results.length === 0 && (
874
+ <p className="text-sm text-gray-500 text-center py-8">No knowledge found</p>
875
+ )}
876
+ {results.map(unit => (
877
+ <KnowledgeCard key={unit.id} unit={unit} onDelete={handleDelete} />
878
+ ))}
879
+ </div>
880
+ </div>
881
+ </div>
882
+ );
883
+ }
884
+ ```
885
+
886
+ - [ ] **Step 2: Commit**
887
+
888
+ ```bash
889
+ git add src/components/cortex/knowledge-tab.tsx
890
+ git commit -m "feat(cortex): add knowledge tab with search and v2 cards"
891
+ ```
892
+
893
+ ---
894
+
895
+ ### Task 10: Context assembly tab
896
+
897
+ **Files:**
898
+ - Create: `src/components/cortex/context-tab.tsx`
899
+
900
+ - [ ] **Step 1: Create the component**
901
+
902
+ ```typescript
903
+ 'use client';
904
+
905
+ import { useState } from 'react';
906
+ import { Search, ChevronDown, ChevronUp } from 'lucide-react';
907
+ import { api } from '@/lib/api';
908
+
909
+ const INTENT_COLORS: Record<string, string> = {
910
+ debugging: 'text-red-400',
911
+ architecture: 'text-blue-400',
912
+ onboarding: 'text-green-400',
913
+ policy: 'text-purple-400',
914
+ 'how-to': 'text-amber-400',
915
+ review: 'text-pink-400',
916
+ security: 'text-red-500',
917
+ general: 'text-gray-400',
918
+ };
919
+
920
+ export function ContextTab() {
921
+ const [query, setQuery] = useState('');
922
+ const [result, setResult] = useState<any>(null);
923
+ const [loading, setLoading] = useState(false);
924
+ const [showRaw, setShowRaw] = useState(false);
925
+
926
+ const handleAnalyze = async () => {
927
+ if (!query.trim()) return;
928
+ setLoading(true);
929
+ try {
930
+ const res = await fetch(api(`/api/cortex/context?q=${encodeURIComponent(query)}&limit=5`));
931
+ if (res.ok) setResult(await res.json());
932
+ } catch {}
933
+ setLoading(false);
934
+ };
935
+
936
+ return (
937
+ <div className="p-6 max-w-3xl mx-auto">
938
+ {/* Query input */}
939
+ <div className="flex gap-3 mb-6">
940
+ <div className="flex-1 relative">
941
+ <Search className="absolute left-3 top-2.5 w-4 h-4 text-gray-500" />
942
+ <input
943
+ value={query}
944
+ onChange={e => setQuery(e.target.value)}
945
+ onKeyDown={e => e.key === 'Enter' && handleAnalyze()}
946
+ placeholder="Enter a query to analyze..."
947
+ className="w-full pl-9 pr-4 py-2 text-sm bg-white/5 border border-white/10 rounded-lg text-gray-300 placeholder-gray-600 focus:outline-none focus:border-purple-500/50"
948
+ />
949
+ </div>
950
+ <button
951
+ onClick={handleAnalyze}
952
+ disabled={loading}
953
+ className="px-5 py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg disabled:opacity-50"
954
+ >
955
+ {loading ? 'Analyzing...' : 'Analyze'}
956
+ </button>
957
+ </div>
958
+
959
+ {!result && !loading && (
960
+ <p className="text-sm text-gray-600 text-center py-12">
961
+ Enter a query to see how the Context Assembly Engine processes it
962
+ </p>
963
+ )}
964
+
965
+ {result && (
966
+ <>
967
+ {/* Pipeline summary */}
968
+ <div className="grid grid-cols-3 gap-3 mb-6">
969
+ <div className="bg-white/[0.02] border border-white/5 rounded-lg p-3">
970
+ <div className="text-[10px] text-gray-600 uppercase mb-1">Intent</div>
971
+ <div className={`text-lg font-semibold ${INTENT_COLORS[result.intent?.intent] || 'text-gray-400'}`}>
972
+ {result.intent?.intent || '?'}
973
+ </div>
974
+ <div className="text-[10px] text-gray-600">
975
+ confidence: {(result.intent?.confidence ?? 0).toFixed(2)}
976
+ </div>
977
+ </div>
978
+ <div className="bg-white/[0.02] border border-white/5 rounded-lg p-3">
979
+ <div className="text-[10px] text-gray-600 uppercase mb-1">Entities</div>
980
+ <div className="flex flex-wrap gap-1 mt-1">
981
+ {(result.entities || []).map((e: any, i: number) => (
982
+ <span key={i} className="text-[10px] px-1.5 py-0.5 bg-white/5 border border-white/10 rounded text-gray-300">
983
+ {e.entity?.type}:{e.entity?.name}
984
+ </span>
985
+ ))}
986
+ {(!result.entities || result.entities.length === 0) && (
987
+ <span className="text-[10px] text-gray-600">none detected</span>
988
+ )}
989
+ </div>
990
+ </div>
991
+ <div className="bg-white/[0.02] border border-white/5 rounded-lg p-3">
992
+ <div className="text-[10px] text-gray-600 uppercase mb-1">Timing</div>
993
+ <div className="text-lg font-semibold text-green-400">
994
+ {result.timing?.totalMs ?? '?'}ms
995
+ </div>
996
+ <div className="text-[10px] text-gray-600">
997
+ intent {result.timing?.intentMs}ms · search {result.timing?.searchMs}ms
998
+ </div>
999
+ </div>
1000
+ </div>
1001
+
1002
+ {/* Source weights */}
1003
+ {result.sourceWeights && (
1004
+ <div className="mb-6">
1005
+ <div className="text-[10px] text-gray-600 uppercase mb-2">Source Weights</div>
1006
+ <div className="flex gap-3">
1007
+ {result.sourceWeights.map((sw: any, i: number) => (
1008
+ <div key={i} className="flex-1 bg-white/[0.02] rounded-lg p-3">
1009
+ <div className="flex justify-between text-[11px] mb-1">
1010
+ <span className="text-gray-300 capitalize">{sw.scopeLevel}</span>
1011
+ <span className="text-gray-500">{sw.weight.toFixed(2)}</span>
1012
+ </div>
1013
+ <div className="h-1.5 bg-white/5 rounded-full overflow-hidden">
1014
+ <div
1015
+ className="h-full bg-purple-500/60 rounded-full"
1016
+ style={{ width: `${Math.min(100, sw.weight * 100)}%` }}
1017
+ />
1018
+ </div>
1019
+ </div>
1020
+ ))}
1021
+ </div>
1022
+ </div>
1023
+ )}
1024
+
1025
+ {/* Results */}
1026
+ <div className="mb-6">
1027
+ <div className="text-[10px] text-gray-600 uppercase mb-2">
1028
+ Results ({(result.results || []).length})
1029
+ </div>
1030
+ <div className="space-y-1">
1031
+ {(result.results || []).map((r: any, i: number) => (
1032
+ <div key={i} className="flex items-center gap-2 bg-white/[0.02] border border-white/5 rounded-lg px-3 py-2">
1033
+ <span className={`text-[10px] px-1.5 py-0.5 rounded font-medium ${
1034
+ r.type === 'error_fix' ? 'bg-amber-500/20 text-amber-400'
1035
+ : r.type === 'decision' ? 'bg-blue-500/20 text-blue-400'
1036
+ : 'bg-gray-500/20 text-gray-400'
1037
+ }`}>{r.type?.replace('_', ' ')}</span>
1038
+ <span className="text-xs text-gray-300 truncate flex-1">{r.text}</span>
1039
+ <span className="text-[10px] text-gray-600 tabular-nums shrink-0">
1040
+ {(r.relevance_score ?? 0).toFixed(3)}
1041
+ </span>
1042
+ </div>
1043
+ ))}
1044
+ </div>
1045
+ </div>
1046
+
1047
+ {/* Conflicts */}
1048
+ {Array.isArray(result.conflicts) && result.conflicts.length > 0 && (
1049
+ <div className="mb-6 border border-amber-500/20 bg-amber-500/5 rounded-lg p-3">
1050
+ <div className="text-[10px] text-amber-400 uppercase font-medium mb-1">
1051
+ Conflicts ({result.conflicts.length})
1052
+ </div>
1053
+ {result.conflicts.map((c: any, i: number) => (
1054
+ <div key={i} className="text-xs text-gray-400 mt-1">
1055
+ &ldquo;{c.unitA?.text?.slice(0, 60)}...&rdquo; vs &ldquo;{c.unitB?.text?.slice(0, 60)}...&rdquo;
1056
+ </div>
1057
+ ))}
1058
+ </div>
1059
+ )}
1060
+
1061
+ {/* Raw context */}
1062
+ <div>
1063
+ <button
1064
+ onClick={() => setShowRaw(!showRaw)}
1065
+ className="flex items-center gap-1 text-[10px] text-gray-600 hover:text-gray-400 uppercase"
1066
+ >
1067
+ Raw context {showRaw ? <ChevronUp className="w-3 h-3" /> : <ChevronDown className="w-3 h-3" />}
1068
+ </button>
1069
+ {showRaw && result.context && (
1070
+ <pre className="mt-2 p-3 bg-white/[0.02] border border-white/5 rounded-lg text-[11px] text-gray-400 overflow-x-auto whitespace-pre-wrap">
1071
+ {result.context}
1072
+ </pre>
1073
+ )}
1074
+ </div>
1075
+ </>
1076
+ )}
1077
+ </div>
1078
+ );
1079
+ }
1080
+ ```
1081
+
1082
+ - [ ] **Step 2: Commit**
1083
+
1084
+ ```bash
1085
+ git add src/components/cortex/context-tab.tsx
1086
+ git commit -m "feat(cortex): add context assembly inspector tab"
1087
+ ```
1088
+
1089
+ ---
1090
+
1091
+ ## Summary
1092
+
1093
+ | Task | Component | Status |
1094
+ |------|-----------|--------|
1095
+ | 1 | listAllEdges() + edges all=true | |
1096
+ | 2 | Context API expansion (entities, conflicts, sourceWeights) | |
1097
+ | 3 | Enhanced knowledge card (v2 fields) | |
1098
+ | 4 | Sidebar Cortex nav item | |
1099
+ | 5 | /cortex page with tabs | |
1100
+ | 6 | Panel "Open full view" link | |
1101
+ | 7 | Entity graph canvas (force-graph) | |
1102
+ | 8 | Entity detail panel | |
1103
+ | 9 | Knowledge tab | |
1104
+ | 10 | Context assembly tab | |
1105
+
1106
+ **Total: 10 tasks, 4 chunks**
1107
+
1108
+ **No tests in this plan** — these are UI components that render from existing tested APIs. The backend changes (Tasks 1-2) are trivial additions to already-tested modules.