@jlongo78/agent-spaces 0.9.6 → 0.9.8

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 (917) hide show
  1. package/.next/standalone/.claude/settings.local.json +68 -0
  2. package/.next/standalone/.claude/spaces-env.json +1 -0
  3. package/.next/standalone/.next/BUILD_ID +1 -1
  4. package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
  5. package/.next/standalone/.next/build-manifest.json +2 -2
  6. package/.next/standalone/.next/prerender-manifest.json +3 -3
  7. package/.next/standalone/.next/required-server-files.json +19 -19
  8. package/.next/standalone/.next/routes-manifest.json +6 -0
  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_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/(desktop)/cortex/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
  14. package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
  24. package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  26. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  27. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  28. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  29. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  30. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  31. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  32. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  33. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  34. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  35. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  36. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  37. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  38. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  39. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  40. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  41. package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
  42. package/.next/standalone/.next/server/app/admin/analytics.rsc +2 -2
  43. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +1 -1
  44. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
  45. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  46. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  47. package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +2 -2
  48. package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
  49. package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +2 -2
  50. package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
  51. package/.next/standalone/.next/server/app/admin/users.html +1 -1
  52. package/.next/standalone/.next/server/app/admin/users.rsc +2 -2
  53. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +1 -1
  54. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
  55. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  56. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  57. package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
  59. package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +2 -2
  60. package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
  61. package/.next/standalone/.next/server/app/analytics.html +1 -1
  62. package/.next/standalone/.next/server/app/analytics.rsc +2 -2
  63. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +1 -1
  64. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
  65. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  66. package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +2 -2
  67. package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
  68. package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +2 -2
  69. package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  70. package/.next/standalone/.next/server/app/api/analytics/overview/route.js +1 -1
  71. package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
  72. package/.next/standalone/.next/server/app/api/benchmark/lobes/route.js +1 -1
  73. package/.next/standalone/.next/server/app/api/benchmark/lobes/route.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/api/benchmark/run/route.js +1 -1
  75. package/.next/standalone/.next/server/app/api/benchmark/run/route.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route.js +1 -1
  77. package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/api/benchmark/runs/route.js +1 -1
  79. package/.next/standalone/.next/server/app/api/benchmark/runs/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/benchmark/status/route.js +1 -1
  81. package/.next/standalone/.next/server/app/api/benchmark/status/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/bulk/route.js +1 -1
  83. package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/api/config/route.js +1 -1
  85. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  86. package/.next/standalone/.next/server/app/api/cortex/context/route.js +1 -1
  87. package/.next/standalone/.next/server/app/api/cortex/context/route.js.nft.json +1 -1
  88. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js +1 -1
  89. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js +1 -1
  91. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js +1 -1
  93. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js +1 -1
  95. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js +1 -1
  97. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/api/cortex/export/route.js +1 -1
  99. package/.next/standalone/.next/server/app/api/cortex/export/route.js.nft.json +1 -1
  100. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js +1 -1
  101. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js.nft.json +1 -1
  102. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js +1 -1
  103. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js +1 -1
  105. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js +1 -1
  107. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js.nft.json +1 -1
  108. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js +1 -1
  109. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js.nft.json +1 -1
  110. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js +1 -1
  111. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js +1 -1
  113. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js +1 -1
  115. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js.nft.json +1 -1
  116. package/.next/standalone/.next/server/app/api/cortex/import/route.js +1 -1
  117. package/.next/standalone/.next/server/app/api/cortex/import/route.js.nft.json +1 -1
  118. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js +1 -1
  119. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js +1 -1
  121. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js.nft.json +1 -1
  122. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js +1 -1
  123. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js +1 -1
  125. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js.nft.json +1 -1
  126. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js +1 -1
  127. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js.nft.json +1 -1
  128. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js +1 -1
  129. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js.nft.json +1 -1
  130. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js +1 -1
  131. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js.nft.json +1 -1
  132. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js +1 -1
  133. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js.nft.json +1 -1
  134. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js +1 -1
  135. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.nft.json +1 -1
  136. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js +1 -1
  137. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.nft.json +1 -1
  138. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js +1 -1
  139. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js.nft.json +1 -1
  140. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js +1 -1
  141. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js.nft.json +1 -1
  142. package/.next/standalone/.next/server/app/api/cortex/search/route.js +1 -1
  143. package/.next/standalone/.next/server/app/api/cortex/search/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/cortex/settings/route.js +1 -1
  145. package/.next/standalone/.next/server/app/api/cortex/settings/route.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/api/cortex/status/route.js +1 -1
  147. package/.next/standalone/.next/server/app/api/cortex/status/route.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js +1 -1
  149. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/api/cortex/usage/route.js +1 -1
  151. package/.next/standalone/.next/server/app/api/cortex/usage/route.js.nft.json +1 -1
  152. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js +1 -1
  153. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js.nft.json +1 -1
  154. package/.next/standalone/.next/server/app/api/events/route.js +1 -1
  155. package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
  156. package/.next/standalone/.next/server/app/api/files/route.js +1 -1
  157. package/.next/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  158. package/.next/standalone/.next/server/app/api/folders/route.js +1 -1
  159. package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
  160. package/.next/standalone/.next/server/app/api/network/handshake/route.js +1 -1
  161. package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
  162. package/.next/standalone/.next/server/app/api/network/panes/[id]/route.js +1 -1
  163. package/.next/standalone/.next/server/app/api/network/panes/[id]/route.js.nft.json +1 -1
  164. package/.next/standalone/.next/server/app/api/network/panes/route.js +1 -1
  165. package/.next/standalone/.next/server/app/api/network/panes/route.js.nft.json +1 -1
  166. package/.next/standalone/.next/server/app/api/network/projects/route.js +1 -1
  167. package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
  168. package/.next/standalone/.next/server/app/api/network/search/route.js +1 -1
  169. package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
  170. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js +1 -1
  171. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
  172. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js +1 -1
  173. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
  174. package/.next/standalone/.next/server/app/api/network/sessions/route.js +1 -1
  175. package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
  176. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js +1 -1
  177. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
  178. package/.next/standalone/.next/server/app/api/network/workspaces/route.js +1 -1
  179. package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
  180. package/.next/standalone/.next/server/app/api/panes/[id]/diff/route.js +1 -1
  181. package/.next/standalone/.next/server/app/api/panes/[id]/diff/route.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/app/api/panes/[id]/route.js +1 -1
  183. package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
  184. package/.next/standalone/.next/server/app/api/panes/route.js +1 -1
  185. package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
  186. package/.next/standalone/.next/server/app/api/projects/route.js +1 -1
  187. package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  188. package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/[...path]/route.js +1 -1
  189. package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/[...path]/route.js.nft.json +1 -1
  190. package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/status/route.js +1 -1
  191. package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/status/route.js.nft.json +1 -1
  192. package/.next/standalone/.next/server/app/api/search/route.js +2 -2
  193. package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  194. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js +1 -1
  195. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
  196. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js +1 -1
  197. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
  198. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js +1 -1
  199. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  200. package/.next/standalone/.next/server/app/api/sessions/route.js +2 -2
  201. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  202. package/.next/standalone/.next/server/app/api/sync/route.js +1 -1
  203. package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
  204. package/.next/standalone/.next/server/app/api/tags/route.js +1 -1
  205. package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
  206. package/.next/standalone/.next/server/app/api/tier/route.js +1 -1
  207. package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
  208. package/.next/standalone/.next/server/app/api/whisper/config/route.js +1 -1
  209. package/.next/standalone/.next/server/app/api/whisper/config/route.js.nft.json +1 -1
  210. package/.next/standalone/.next/server/app/api/whisper/route.js.nft.json +1 -1
  211. package/.next/standalone/.next/server/app/api/wizard/chart/route/app-paths-manifest.json +3 -0
  212. package/.next/standalone/.next/server/app/api/wizard/chart/route/build-manifest.json +11 -0
  213. package/.next/standalone/.next/server/app/api/wizard/chart/route/server-reference-manifest.json +4 -0
  214. package/.next/standalone/.next/server/app/api/wizard/chart/route.js +7 -0
  215. package/.next/standalone/.next/server/app/api/wizard/chart/route.js.map +5 -0
  216. package/.next/standalone/.next/server/app/api/wizard/chart/route.js.nft.json +1 -0
  217. package/.next/standalone/.next/server/app/api/wizard/chart/route_client-reference-manifest.js +2 -0
  218. package/.next/standalone/.next/server/app/api/wizard/chat/route.js +1 -1
  219. package/.next/standalone/.next/server/app/api/wizard/chat/route.js.nft.json +1 -1
  220. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js +1 -1
  221. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
  222. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js +1 -1
  223. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
  224. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js +1 -1
  225. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
  226. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js +1 -1
  227. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
  228. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js +1 -1
  229. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
  230. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js +1 -1
  231. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
  232. package/.next/standalone/.next/server/app/api/workspaces/route.js +2 -2
  233. package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  234. package/.next/standalone/.next/server/app/cortex.html +1 -1
  235. package/.next/standalone/.next/server/app/cortex.rsc +3 -3
  236. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex/__PAGE__.segment.rsc +2 -2
  237. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex.segment.rsc +1 -1
  238. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  239. package/.next/standalone/.next/server/app/cortex.segments/_full.segment.rsc +3 -3
  240. package/.next/standalone/.next/server/app/cortex.segments/_head.segment.rsc +1 -1
  241. package/.next/standalone/.next/server/app/cortex.segments/_index.segment.rsc +2 -2
  242. package/.next/standalone/.next/server/app/cortex.segments/_tree.segment.rsc +2 -2
  243. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  244. package/.next/standalone/.next/server/app/login.html +1 -1
  245. package/.next/standalone/.next/server/app/login.rsc +2 -2
  246. package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
  247. package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
  248. package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +2 -2
  249. package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  250. package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  251. package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
  252. package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
  253. package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
  254. package/.next/standalone/.next/server/app/m/projects.html +1 -1
  255. package/.next/standalone/.next/server/app/m/projects.rsc +2 -2
  256. package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +2 -2
  257. package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
  258. package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +2 -2
  259. package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
  260. package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +1 -1
  261. package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
  262. package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +1 -1
  263. package/.next/standalone/.next/server/app/m/sessions/[id]/page.js.nft.json +1 -1
  264. package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
  265. package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
  266. package/.next/standalone/.next/server/app/m/sessions.html +1 -1
  267. package/.next/standalone/.next/server/app/m/sessions.rsc +2 -2
  268. package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +2 -2
  269. package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
  270. package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +2 -2
  271. package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
  272. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +1 -1
  273. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
  274. package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +1 -1
  275. package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
  276. package/.next/standalone/.next/server/app/m/settings.html +1 -1
  277. package/.next/standalone/.next/server/app/m/settings.rsc +2 -2
  278. package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +2 -2
  279. package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
  280. package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +2 -2
  281. package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
  282. package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +1 -1
  283. package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
  284. package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +1 -1
  285. package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
  286. package/.next/standalone/.next/server/app/m/terminal.html +1 -1
  287. package/.next/standalone/.next/server/app/m/terminal.rsc +3 -3
  288. package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +3 -3
  289. package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
  290. package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +2 -2
  291. package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
  292. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
  293. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
  294. package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +1 -1
  295. package/.next/standalone/.next/server/app/m.html +1 -1
  296. package/.next/standalone/.next/server/app/m.rsc +2 -2
  297. package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +2 -2
  298. package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
  299. package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +2 -2
  300. package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
  301. package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +1 -1
  302. package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +1 -1
  303. package/.next/standalone/.next/server/app/network.html +1 -1
  304. package/.next/standalone/.next/server/app/network.rsc +2 -2
  305. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +1 -1
  306. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
  307. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  308. package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +2 -2
  309. package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
  310. package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +2 -2
  311. package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
  312. package/.next/standalone/.next/server/app/projects.html +1 -1
  313. package/.next/standalone/.next/server/app/projects.rsc +2 -2
  314. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +1 -1
  315. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
  316. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  317. package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +2 -2
  318. package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  319. package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +2 -2
  320. package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  321. package/.next/standalone/.next/server/app/sessions.html +1 -1
  322. package/.next/standalone/.next/server/app/sessions.rsc +2 -2
  323. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +1 -1
  324. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
  325. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  326. package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +2 -2
  327. package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
  328. package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +2 -2
  329. package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
  330. package/.next/standalone/.next/server/app/settings.html +1 -1
  331. package/.next/standalone/.next/server/app/settings.rsc +2 -2
  332. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +1 -1
  333. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
  334. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  335. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +2 -2
  336. package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  337. package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  338. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  339. package/.next/standalone/.next/server/app/terminal.html +1 -1
  340. package/.next/standalone/.next/server/app/terminal.rsc +3 -3
  341. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
  342. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
  343. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  344. package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +3 -3
  345. package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
  346. package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +2 -2
  347. package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
  348. package/.next/standalone/.next/server/app/vr/page/react-loadable-manifest.json +1 -1
  349. package/.next/standalone/.next/server/app/vr/page_client-reference-manifest.js +1 -1
  350. package/.next/standalone/.next/server/app/vr.html +1 -1
  351. package/.next/standalone/.next/server/app/vr.rsc +3 -3
  352. package/.next/standalone/.next/server/app/vr.segments/_full.segment.rsc +3 -3
  353. package/.next/standalone/.next/server/app/vr.segments/_head.segment.rsc +1 -1
  354. package/.next/standalone/.next/server/app/vr.segments/_index.segment.rsc +2 -2
  355. package/.next/standalone/.next/server/app/vr.segments/_tree.segment.rsc +2 -2
  356. package/.next/standalone/.next/server/app/vr.segments/vr/__PAGE__.segment.rsc +2 -2
  357. package/.next/standalone/.next/server/app/vr.segments/vr.segment.rsc +1 -1
  358. package/.next/standalone/.next/server/app/workspaces.html +1 -1
  359. package/.next/standalone/.next/server/app/workspaces.rsc +2 -2
  360. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +1 -1
  361. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
  362. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  363. package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +2 -2
  364. package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
  365. package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +2 -2
  366. package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
  367. package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00e90fc6._.js +98 -0
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01ab8675._.js +98 -0
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03974f05._.js +98 -0
  371. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__bb331da9._.js → [root-of-the-server]__046c9b91._.js} +3 -3
  372. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04ae6bf0._.js +98 -0
  373. package/.next/standalone/.next/server/chunks/[root-of-the-server]__056fa416._.js +1 -1
  374. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ac4ea3f._.js +3 -0
  375. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b8e64cb._.js +98 -0
  376. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__d95165f0._.js → [root-of-the-server]__0facd39e._.js} +3 -3
  377. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10bc76a3._.js +3 -0
  378. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__9d68157b._.js → [root-of-the-server]__115f3934._.js} +3 -3
  379. package/.next/standalone/.next/server/chunks/[root-of-the-server]__11f155f1._.js +3 -0
  380. package/.next/standalone/.next/server/chunks/[root-of-the-server]__160e7c73._.js +22 -33
  381. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__91e23c96._.js → [root-of-the-server]__17a3b966._.js} +3 -3
  382. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__277d9445._.js → [root-of-the-server]__17d3a2b2._.js} +3 -3
  383. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a86c055._.js +98 -0
  384. package/.next/standalone/.next/server/chunks/[root-of-the-server]__20b5e9c4._.js +3 -0
  385. package/.next/standalone/.next/server/chunks/[root-of-the-server]__28d6fbd8._.js +98 -0
  386. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__04f04898._.js → [root-of-the-server]__2a3f866b._.js} +2 -2
  387. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__a95bb38b._.js → [root-of-the-server]__316617e7._.js} +2 -2
  388. package/.next/standalone/.next/server/chunks/[root-of-the-server]__32ad8f71._.js +98 -0
  389. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__6fe5e6c8._.js → [root-of-the-server]__35457394._.js} +2 -2
  390. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1f054c65._.js → [root-of-the-server]__35de78e6._.js} +3 -3
  391. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3685ffcb._.js +98 -0
  392. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__614458b7._.js → [root-of-the-server]__38954988._.js} +3 -3
  393. package/.next/standalone/.next/server/chunks/[root-of-the-server]__426ad936._.js +106 -0
  394. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4985c034._.js +98 -0
  395. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c6ce9ed._.js +98 -0
  396. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5cebe58a._.js +98 -0
  397. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5d5e4789._.js +98 -0
  398. package/.next/standalone/.next/server/chunks/[root-of-the-server]__65676930._.js +3 -0
  399. package/.next/standalone/.next/server/chunks/[root-of-the-server]__67cab326._.js +58 -0
  400. package/.next/standalone/.next/server/chunks/[root-of-the-server]__698c6f01._.js +98 -0
  401. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c64af29._.js +131 -0
  402. package/.next/standalone/.next/server/chunks/[root-of-the-server]__73aed9f5._.js +98 -0
  403. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__ac84b704._.js → [root-of-the-server]__79b6a9bb._.js} +3 -3
  404. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__e56abacf._.js → [root-of-the-server]__7db704c6._.js} +4 -4
  405. package/.next/standalone/.next/server/chunks/[root-of-the-server]__812ca02b._.js +98 -0
  406. package/.next/standalone/.next/server/chunks/[root-of-the-server]__821f50fa._.js +98 -0
  407. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8716b86e._.js +98 -0
  408. package/.next/standalone/.next/server/chunks/[root-of-the-server]__884ef754._.js +98 -0
  409. package/.next/standalone/.next/server/chunks/[root-of-the-server]__88cdbd68._.js +98 -0
  410. package/.next/standalone/.next/server/chunks/[root-of-the-server]__89d9aba9._.js +98 -0
  411. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8d536cb5._.js +98 -0
  412. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8df8c5d1._.js +98 -0
  413. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2d7a454e._.js → [root-of-the-server]__8f2ccc41._.js} +3 -3
  414. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2a2c5fc5._.js → [root-of-the-server]__95c9d682._.js} +4 -4
  415. package/.next/standalone/.next/server/chunks/[root-of-the-server]__9e5d7774._.js +98 -0
  416. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__cc6e2885._.js → [root-of-the-server]__9edcff87._.js} +2 -2
  417. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a049dfc2._.js +98 -0
  418. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a5b4bb9a._.js +98 -0
  419. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__929ea03a._.js → [root-of-the-server]__a83262a1._.js} +2 -2
  420. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9cd1240._.js +98 -0
  421. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9d7f822._.js +98 -0
  422. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ad08c221._.js +98 -0
  423. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ad585f2f._.js +98 -0
  424. package/.next/standalone/.next/server/chunks/[root-of-the-server]__afcb8f7d._.js +98 -0
  425. package/.next/standalone/.next/server/chunks/[root-of-the-server]__bc250d43._.js +98 -0
  426. package/.next/standalone/.next/server/chunks/[root-of-the-server]__bce2a6e7._.js +98 -0
  427. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c011bf91._.js +98 -0
  428. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c0ac2895._.js +3 -0
  429. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c130a00c._.js +1 -1
  430. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c37d6380._.js +3 -0
  431. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cae392eb._.js +98 -0
  432. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cc2616bb._.js +3 -3
  433. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d501fa9b._.js +98 -0
  434. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d59c6c15._.js +98 -0
  435. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d5c1db32._.js +98 -0
  436. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d5d92527._.js +1 -1
  437. package/.next/standalone/.next/server/chunks/[root-of-the-server]__dba60c86._.js +98 -0
  438. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2384f98e._.js → [root-of-the-server]__de14b9ae._.js} +3 -3
  439. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e10643d1._.js +98 -0
  440. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__00fdfbda._.js → [root-of-the-server]__e2a996e5._.js} +2 -2
  441. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__4d903941._.js → [root-of-the-server]__e3477417._.js} +3 -3
  442. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__32dc5513._.js → [root-of-the-server]__e4db362e._.js} +2 -2
  443. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__49e42a3a._.js → [root-of-the-server]__e4e70b86._.js} +3 -3
  444. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__ac39ecc7._.js → [root-of-the-server]__e54925af._.js} +3 -3
  445. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e8edc5b0._.js +98 -0
  446. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__eafd040b._.js → [root-of-the-server]__eab4d83b._.js} +2 -2
  447. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ead29015._.js +1 -1
  448. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__194955d4._.js → [root-of-the-server]__f056fd83._.js} +3 -3
  449. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f0e99572._.js +98 -0
  450. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fe1e16d0._.js +98 -0
  451. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ff9cd277._.js +98 -0
  452. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ffaea2ce._.js +98 -0
  453. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wizard_chart_route_actions_888e2ec1.js +3 -0
  454. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__2cffc362._.js +3 -0
  455. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__f1050870._.js → [root-of-the-server]__47c97637._.js} +2 -2
  456. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
  457. package/.next/standalone/.next/server/chunks/ssr/_17b946fd._.js +3 -0
  458. package/.next/standalone/.next/server/chunks/ssr/_2a1d79e7._.js +1 -1
  459. package/.next/standalone/.next/server/chunks/ssr/_5c3c4cfa._.js +7 -5
  460. package/.next/standalone/.next/server/chunks/ssr/_ba432382._.js +7 -5
  461. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_cortex_page_tsx_0f33d8b3._.js +1 -1
  462. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_terminal_page_tsx_de5e8d85._.js +4 -4
  463. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__90eeddae._.js +1 -1
  464. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  465. package/.next/standalone/.next/server/pages/404.html +1 -1
  466. package/.next/standalone/.next/server/pages/500.html +2 -2
  467. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  468. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  469. package/.next/standalone/.next/static/chunks/0852575eb90c1e8d.js +85 -0
  470. package/.next/standalone/.next/static/chunks/{74d0ac0b1d0a1b79.js → 10b00b4f66102dcf.js} +1 -1
  471. package/.next/standalone/.next/static/chunks/{16eb77953dee9ea3.js → 19c71a8376c23c58.js} +1 -1
  472. package/.next/standalone/.next/static/chunks/2b769d1597e4fc1c.css +3 -0
  473. package/.next/standalone/.next/static/chunks/{3e91fc608659c524.js → 350271fe79509caf.js} +1 -1
  474. package/.next/standalone/.next/static/chunks/{70423c7afd8abf5f.js → 597847c22200c212.js} +1 -1
  475. package/.next/standalone/.next/static/chunks/{fb0abd1933b2b2e1.js → 7f6a14f1849fa94d.js} +1 -1
  476. package/.next/standalone/.next/static/chunks/{7ecd9bbb0ce4d68a.js → b7c8fe9b7275a84f.js} +1 -1
  477. package/.next/standalone/.next/static/chunks/{6245135a7afb8c7b.js → c9b10fc55516d142.js} +8 -6
  478. package/.next/standalone/.next/static/chunks/d0065f48eab94944.js +1 -0
  479. package/.next/standalone/.next/static/chunks/{180c1b9ff31b979f.js → f7b34c807badf95d.js} +8 -6
  480. package/.next/standalone/.spaces/cortex-context.md +50 -144
  481. package/.next/standalone/LICENSE +661 -661
  482. package/.next/standalone/NOTICE +5 -5
  483. package/.next/standalone/README.md +131 -131
  484. package/.next/standalone/bin/cortex-hook.js +79 -79
  485. package/.next/standalone/bin/cortex-hook.sh +62 -62
  486. package/.next/standalone/bin/cortex-learn-hook.js +138 -138
  487. package/.next/standalone/bin/cortex-mcp.js +60 -60
  488. package/.next/standalone/bin/cortex-pi-extension.ts +170 -170
  489. package/.next/standalone/bin/fix-standalone-externals.js +79 -79
  490. package/.next/standalone/bin/lib/auto-setup.js +110 -110
  491. package/.next/standalone/bin/mdns-service.js +171 -171
  492. package/.next/standalone/bin/postinstall.js +35 -35
  493. package/.next/standalone/bin/setup-admin.js +195 -195
  494. package/.next/standalone/bin/spaces-dev.js +247 -247
  495. package/.next/standalone/bin/spaces-install.js +660 -660
  496. package/.next/standalone/bin/spaces-postinstall.js +50 -50
  497. package/.next/standalone/bin/spaces-reset-totp.js +50 -50
  498. package/.next/standalone/bin/spaces-service.js +1046 -1046
  499. package/.next/standalone/bin/spaces-setup.js +253 -253
  500. package/.next/standalone/bin/spaces.js +808 -805
  501. package/.next/standalone/bin/ssh-auth-keys.sh +68 -68
  502. package/.next/standalone/bin/terminal-server.js +2819 -2781
  503. package/.next/standalone/cortex-hook-debug.log +57 -23
  504. package/.next/standalone/docker-compose.yml +28 -28
  505. package/.next/standalone/docs/architecture.md +387 -387
  506. package/.next/standalone/docs/cortex-integration-reference.md +268 -268
  507. package/.next/standalone/docs/cortex.md +293 -293
  508. package/.next/standalone/docs/getting-started.md +96 -96
  509. package/.next/standalone/docs/plans/2026-02-24-multi-agent-sessions-design.md +133 -133
  510. package/.next/standalone/docs/plans/2026-02-24-multi-agent-sessions-plan.md +959 -959
  511. package/.next/standalone/docs/plans/2026-03-02-security-audit.md +229 -229
  512. package/.next/standalone/docs/plans/2026-03-07-service-command-design.md +146 -146
  513. package/.next/standalone/docs/plans/2026-03-07-service-command-plan.md +254 -254
  514. package/.next/standalone/docs/server-install.md +564 -564
  515. package/.next/standalone/docs/social-card.html +150 -150
  516. package/.next/standalone/docs/superpowers/plans/2026-03-12-spaces-cortex.md +5270 -5270
  517. package/.next/standalone/docs/superpowers/plans/2026-03-13-cortex-wiring.md +1387 -1387
  518. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-entity-graph.md +1923 -1923
  519. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-knowledge-evolution.md +1113 -1113
  520. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-boundary-engine.md +853 -853
  521. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-context-engine.md +1274 -1274
  522. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-signal-ingestion.md +933 -933
  523. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-lobes.md +1080 -1080
  524. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-gravity-system.md +768 -768
  525. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-ui.md +1108 -1108
  526. package/.next/standalone/docs/superpowers/plans/2026-03-18-cortex-ui-integration.md +1846 -1846
  527. package/.next/standalone/docs/superpowers/plans/2026-03-19-vr-phase1-shell.md +1639 -1639
  528. package/.next/standalone/docs/superpowers/plans/2026-03-27-dockview-pane-layout.md +98 -98
  529. package/.next/standalone/docs/superpowers/specs/2026-03-11-universe-view-design.md +320 -320
  530. package/.next/standalone/docs/superpowers/specs/2026-03-12-spaces-brain-design.md +720 -720
  531. package/.next/standalone/docs/superpowers/specs/2026-03-13-cortex-wiring-design.md +268 -268
  532. package/.next/standalone/docs/superpowers/specs/2026-03-14-cortex-v2-design.md +623 -623
  533. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-lobes-design.md +263 -263
  534. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md +240 -240
  535. package/.next/standalone/docs/superpowers/specs/2026-03-16-pane-ux-design.md +77 -77
  536. package/.next/standalone/docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md +341 -341
  537. package/.next/standalone/docs/superpowers/specs/2026-03-19-vr-phase1-shell-design.md +288 -288
  538. package/.next/standalone/docs/superpowers/specs/2026-03-27-pane-diff-review-and-project-wizard-design.md +322 -322
  539. package/.next/standalone/docs/tiers.md +104 -104
  540. package/.next/standalone/eslint.config.mjs +18 -18
  541. package/.next/standalone/next.config.ts +20 -20
  542. package/.next/standalone/nginx.conf +53 -53
  543. package/.next/standalone/node_modules/@img/sharp-win32-x64/lib/sharp-win32-x64.node +0 -0
  544. package/.next/standalone/node_modules/@img/{sharp-linux-x64 → sharp-win32-x64}/package.json +39 -46
  545. package/.next/standalone/package-lock.json +14985 -14986
  546. package/.next/standalone/package.json +111 -111
  547. package/.next/standalone/postcss.config.mjs +7 -7
  548. package/.next/standalone/scripts/rebuild.cmd +65 -65
  549. package/.next/standalone/scripts/rebuild.sh +59 -59
  550. package/.next/standalone/server.js +1 -1
  551. package/.next/standalone/src/app/(desktop)/admin/analytics/page.tsx +266 -266
  552. package/.next/standalone/src/app/(desktop)/admin/users/page.tsx +399 -399
  553. package/.next/standalone/src/app/(desktop)/analytics/page.tsx +166 -166
  554. package/.next/standalone/src/app/(desktop)/cortex/page.tsx +81 -81
  555. package/.next/standalone/src/app/(desktop)/dashboard-client.tsx +56 -56
  556. package/.next/standalone/src/app/(desktop)/layout.tsx +18 -18
  557. package/.next/standalone/src/app/(desktop)/network/page.tsx +137 -137
  558. package/.next/standalone/src/app/(desktop)/page.tsx +17 -17
  559. package/.next/standalone/src/app/(desktop)/projects/page.tsx +68 -68
  560. package/.next/standalone/src/app/(desktop)/sessions/[id]/page.tsx +519 -519
  561. package/.next/standalone/src/app/(desktop)/sessions/page.tsx +145 -145
  562. package/.next/standalone/src/app/(desktop)/settings/page.tsx +446 -446
  563. package/.next/standalone/src/app/(desktop)/terminal/layout.tsx +7 -7
  564. package/.next/standalone/src/app/(desktop)/terminal/page.tsx +1330 -1291
  565. package/.next/standalone/src/app/(desktop)/terminal/pane/[id]/page.tsx +211 -211
  566. package/.next/standalone/src/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.tsx +252 -252
  567. package/.next/standalone/src/app/(desktop)/workspaces/page.tsx +12 -12
  568. package/.next/standalone/src/app/api/admin/analytics/route.ts +10 -10
  569. package/.next/standalone/src/app/api/admin/users/[id]/route.ts +20 -20
  570. package/.next/standalone/src/app/api/admin/users/route.ts +15 -15
  571. package/.next/standalone/src/app/api/analytics/overview/route.ts +80 -80
  572. package/.next/standalone/src/app/api/auth/login/route.ts +10 -10
  573. package/.next/standalone/src/app/api/auth/logout/route.ts +9 -9
  574. package/.next/standalone/src/app/api/auth/me/route.ts +22 -22
  575. package/.next/standalone/src/app/api/auth/totp/setup/route.ts +10 -10
  576. package/.next/standalone/src/app/api/auth/totp/status/route.ts +10 -10
  577. package/.next/standalone/src/app/api/auth/totp/verify/route.ts +10 -10
  578. package/.next/standalone/src/app/api/benchmark/lobes/route.ts +16 -16
  579. package/.next/standalone/src/app/api/benchmark/run/route.ts +113 -92
  580. package/.next/standalone/src/app/api/benchmark/runs/[id]/route.ts +26 -26
  581. package/.next/standalone/src/app/api/benchmark/runs/route.ts +16 -16
  582. package/.next/standalone/src/app/api/benchmark/status/route.ts +35 -35
  583. package/.next/standalone/src/app/api/bulk/route.ts +34 -34
  584. package/.next/standalone/src/app/api/chat/route.ts +85 -85
  585. package/.next/standalone/src/app/api/config/route.ts +30 -30
  586. package/.next/standalone/src/app/api/cortex/context/route.ts +78 -78
  587. package/.next/standalone/src/app/api/cortex/curation/assess/route.ts +27 -27
  588. package/.next/standalone/src/app/api/cortex/curation/publish/route.ts +23 -23
  589. package/.next/standalone/src/app/api/cortex/curation/refine/route.ts +23 -23
  590. package/.next/standalone/src/app/api/cortex/curation/review/route.ts +29 -29
  591. package/.next/standalone/src/app/api/cortex/curation/seed/route.ts +23 -23
  592. package/.next/standalone/src/app/api/cortex/export/route.ts +40 -40
  593. package/.next/standalone/src/app/api/cortex/federation/pending/route.ts +20 -20
  594. package/.next/standalone/src/app/api/cortex/federation/resolve/route.ts +43 -43
  595. package/.next/standalone/src/app/api/cortex/federation/search/route.ts +35 -35
  596. package/.next/standalone/src/app/api/cortex/federation/teach/route.ts +76 -76
  597. package/.next/standalone/src/app/api/cortex/graph/edges/route.ts +112 -112
  598. package/.next/standalone/src/app/api/cortex/graph/entities/[id]/route.ts +73 -73
  599. package/.next/standalone/src/app/api/cortex/graph/entities/route.ts +75 -75
  600. package/.next/standalone/src/app/api/cortex/graph/populate/route.ts +203 -203
  601. package/.next/standalone/src/app/api/cortex/import/route.ts +75 -75
  602. package/.next/standalone/src/app/api/cortex/import/status/route.ts +15 -15
  603. package/.next/standalone/src/app/api/cortex/ingest/bootstrap/route.ts +39 -39
  604. package/.next/standalone/src/app/api/cortex/ingest/status/route.ts +15 -15
  605. package/.next/standalone/src/app/api/cortex/knowledge/[id]/route.ts +91 -91
  606. package/.next/standalone/src/app/api/cortex/knowledge/route.ts +97 -97
  607. package/.next/standalone/src/app/api/cortex/lobes/[id]/route.ts +67 -67
  608. package/.next/standalone/src/app/api/cortex/lobes/route.ts +22 -22
  609. package/.next/standalone/src/app/api/cortex/lobes/share/route.ts +80 -80
  610. package/.next/standalone/src/app/api/cortex/marketplace/browse/route.ts +43 -43
  611. package/.next/standalone/src/app/api/cortex/marketplace/preview/route.ts +46 -46
  612. package/.next/standalone/src/app/api/cortex/mcp/call/route.ts +11 -11
  613. package/.next/standalone/src/app/api/cortex/mcp/tools/route.ts +8 -8
  614. package/.next/standalone/src/app/api/cortex/search/route.ts +57 -45
  615. package/.next/standalone/src/app/api/cortex/settings/route.ts +35 -35
  616. package/.next/standalone/src/app/api/cortex/status/route.ts +169 -169
  617. package/.next/standalone/src/app/api/cortex/timeline/route.ts +42 -42
  618. package/.next/standalone/src/app/api/cortex/usage/route.ts +31 -31
  619. package/.next/standalone/src/app/api/cortex/workspace/[id]/context/route.ts +41 -41
  620. package/.next/standalone/src/app/api/events/route.ts +40 -40
  621. package/.next/standalone/src/app/api/files/route.ts +187 -187
  622. package/.next/standalone/src/app/api/folders/route.ts +107 -97
  623. package/.next/standalone/src/app/api/network/connect-callback/route.ts +11 -11
  624. package/.next/standalone/src/app/api/network/connect-request/[id]/route.ts +11 -11
  625. package/.next/standalone/src/app/api/network/connect-request/route.ts +17 -17
  626. package/.next/standalone/src/app/api/network/discovered/route.ts +9 -9
  627. package/.next/standalone/src/app/api/network/handshake/route.ts +25 -25
  628. package/.next/standalone/src/app/api/network/health/route.ts +10 -10
  629. package/.next/standalone/src/app/api/network/identity/route.ts +15 -15
  630. package/.next/standalone/src/app/api/network/keys/[id]/route.ts +10 -10
  631. package/.next/standalone/src/app/api/network/keys/route.ts +15 -15
  632. package/.next/standalone/src/app/api/network/nodes/[id]/route.ts +15 -15
  633. package/.next/standalone/src/app/api/network/nodes/check/route.ts +9 -9
  634. package/.next/standalone/src/app/api/network/nodes/route.ts +15 -15
  635. package/.next/standalone/src/app/api/network/panes/[id]/route.ts +78 -62
  636. package/.next/standalone/src/app/api/network/panes/route.ts +61 -50
  637. package/.next/standalone/src/app/api/network/projects/route.ts +32 -25
  638. package/.next/standalone/src/app/api/network/proxy/[nodeId]/[...path]/route.ts +25 -25
  639. package/.next/standalone/src/app/api/network/search/route.ts +45 -38
  640. package/.next/standalone/src/app/api/network/sessions/[id]/messages/route.ts +43 -36
  641. package/.next/standalone/src/app/api/network/sessions/[id]/route.ts +41 -34
  642. package/.next/standalone/src/app/api/network/sessions/route.ts +50 -43
  643. package/.next/standalone/src/app/api/network/terminal/token/route.ts +10 -10
  644. package/.next/standalone/src/app/api/network/workspaces/[id]/route.ts +80 -71
  645. package/.next/standalone/src/app/api/network/workspaces/route.ts +87 -85
  646. package/.next/standalone/src/app/api/panes/[id]/diff/route.ts +121 -121
  647. package/.next/standalone/src/app/api/panes/[id]/route.ts +60 -60
  648. package/.next/standalone/src/app/api/panes/route.ts +39 -39
  649. package/.next/standalone/src/app/api/projects/route.ts +13 -13
  650. package/.next/standalone/src/app/api/proxy/models/[modelId]/[...path]/route.ts +80 -80
  651. package/.next/standalone/src/app/api/proxy/models/[modelId]/status/route.ts +33 -33
  652. package/.next/standalone/src/app/api/search/route.ts +47 -47
  653. package/.next/standalone/src/app/api/sessions/[id]/chat/route.ts +120 -120
  654. package/.next/standalone/src/app/api/sessions/[id]/messages/route.ts +34 -34
  655. package/.next/standalone/src/app/api/sessions/[id]/route.ts +73 -73
  656. package/.next/standalone/src/app/api/sessions/route.ts +64 -64
  657. package/.next/standalone/src/app/api/sync/route.ts +24 -24
  658. package/.next/standalone/src/app/api/tags/route.ts +35 -35
  659. package/.next/standalone/src/app/api/tier/route.ts +16 -16
  660. package/.next/standalone/src/app/api/updates/route.ts +65 -65
  661. package/.next/standalone/src/app/api/whisper/config/route.ts +50 -42
  662. package/.next/standalone/src/app/api/whisper/route.ts +91 -91
  663. package/.next/standalone/src/app/api/wizard/chart/route.ts +129 -0
  664. package/.next/standalone/src/app/api/wizard/chat/route.ts +113 -113
  665. package/.next/standalone/src/app/api/workspaces/[id]/context/[key]/route.ts +39 -39
  666. package/.next/standalone/src/app/api/workspaces/[id]/context/route.ts +28 -28
  667. package/.next/standalone/src/app/api/workspaces/[id]/messages/[msgId]/route.ts +17 -17
  668. package/.next/standalone/src/app/api/workspaces/[id]/messages/route.ts +39 -39
  669. package/.next/standalone/src/app/api/workspaces/[id]/route.ts +47 -47
  670. package/.next/standalone/src/app/api/workspaces/[id]/sessions/route.ts +62 -62
  671. package/.next/standalone/src/app/api/workspaces/route.ts +79 -79
  672. package/.next/standalone/src/app/globals.css +88 -88
  673. package/.next/standalone/src/app/layout.tsx +33 -33
  674. package/.next/standalone/src/app/login/layout.tsx +7 -7
  675. package/.next/standalone/src/app/login/page.tsx +315 -315
  676. package/.next/standalone/src/app/m/layout.tsx +16 -16
  677. package/.next/standalone/src/app/m/page.tsx +118 -118
  678. package/.next/standalone/src/app/m/projects/page.tsx +64 -64
  679. package/.next/standalone/src/app/m/sessions/[id]/page.tsx +168 -168
  680. package/.next/standalone/src/app/m/sessions/page.tsx +177 -177
  681. package/.next/standalone/src/app/m/settings/page.tsx +230 -230
  682. package/.next/standalone/src/app/m/terminal/page.tsx +413 -413
  683. package/.next/standalone/src/app/vr/page.tsx +21 -21
  684. package/.next/standalone/src/app/vr/vr-app.tsx +163 -163
  685. package/.next/standalone/src/app/vr/vr-controls.tsx +139 -139
  686. package/.next/standalone/src/app/vr/vr-door.tsx +82 -82
  687. package/.next/standalone/src/app/vr/vr-environment.tsx +71 -71
  688. package/.next/standalone/src/app/vr/vr-gaze.tsx +89 -89
  689. package/.next/standalone/src/app/vr/vr-layout.ts +49 -49
  690. package/.next/standalone/src/app/vr/vr-lobby.tsx +97 -97
  691. package/.next/standalone/src/app/vr/vr-pane.tsx +195 -195
  692. package/.next/standalone/src/app/vr/vr-room.tsx +79 -79
  693. package/.next/standalone/src/app/vr/vr-terminal.tsx +303 -303
  694. package/.next/standalone/src/components/auth/totp-gate.tsx +183 -183
  695. package/.next/standalone/src/components/bus/activity-panel.tsx +261 -261
  696. package/.next/standalone/src/components/common/color-picker.tsx +35 -35
  697. package/.next/standalone/src/components/common/dev-directory-picker.tsx +339 -339
  698. package/.next/standalone/src/components/common/folder-picker.tsx +200 -200
  699. package/.next/standalone/src/components/common/tag-picker.tsx +190 -190
  700. package/.next/standalone/src/components/common/workspace-picker.tsx +113 -113
  701. package/.next/standalone/src/components/cortex/benchmark-tab.tsx +894 -880
  702. package/.next/standalone/src/components/cortex/constants.ts +29 -29
  703. package/.next/standalone/src/components/cortex/cortex-dashboard.tsx +304 -304
  704. package/.next/standalone/src/components/cortex/cortex-indicator.tsx +44 -44
  705. package/.next/standalone/src/components/cortex/cortex-panel.tsx +140 -140
  706. package/.next/standalone/src/components/cortex/cortex-settings.tsx +280 -280
  707. package/.next/standalone/src/components/cortex/curation-tab.tsx +810 -810
  708. package/.next/standalone/src/components/cortex/entity-detail.tsx +101 -101
  709. package/.next/standalone/src/components/cortex/entity-graph.tsx +382 -382
  710. package/.next/standalone/src/components/cortex/import-dialog.tsx +212 -212
  711. package/.next/standalone/src/components/cortex/injection-badge.tsx +72 -72
  712. package/.next/standalone/src/components/cortex/knowledge-card.tsx +109 -109
  713. package/.next/standalone/src/components/cortex/knowledge-tab.tsx +158 -158
  714. package/.next/standalone/src/components/cortex/lobe-settings.tsx +215 -215
  715. package/.next/standalone/src/components/cortex/marketplace-card.tsx +126 -126
  716. package/.next/standalone/src/components/cortex/marketplace-tab.tsx +113 -113
  717. package/.next/standalone/src/components/dashboard/activity-chart.tsx +41 -41
  718. package/.next/standalone/src/components/dashboard/model-usage-chart.tsx +61 -61
  719. package/.next/standalone/src/components/dashboard/recent-sessions.tsx +68 -68
  720. package/.next/standalone/src/components/dashboard/stats-cards.tsx +36 -36
  721. package/.next/standalone/src/components/files/file-explorer.tsx +703 -703
  722. package/.next/standalone/src/components/layout/providers.tsx +38 -38
  723. package/.next/standalone/src/components/layout/sidebar.tsx +170 -170
  724. package/.next/standalone/src/components/layout/tier-provider.tsx +53 -53
  725. package/.next/standalone/src/components/layout/update-banner.tsx +92 -92
  726. package/.next/standalone/src/components/mobile/bottom-nav.tsx +46 -46
  727. package/.next/standalone/src/components/mobile/immersive-voice-button.tsx +123 -123
  728. package/.next/standalone/src/components/mobile/mobile-chat-input.tsx +244 -244
  729. package/.next/standalone/src/components/mobile/mobile-header.tsx +44 -44
  730. package/.next/standalone/src/components/mobile/mobile-session-card.tsx +56 -56
  731. package/.next/standalone/src/components/mobile/mobile-terminal-input.tsx +74 -74
  732. package/.next/standalone/src/components/mobile/mobile-terminal-pane.tsx +302 -302
  733. package/.next/standalone/src/components/mobile/mobile-terminal-toolbar.tsx +76 -76
  734. package/.next/standalone/src/components/mobile/pull-to-refresh.tsx +82 -82
  735. package/.next/standalone/src/components/mobile/voice-input.tsx +53 -53
  736. package/.next/standalone/src/components/network/api-key-list.tsx +190 -190
  737. package/.next/standalone/src/components/network/connection-requests.tsx +94 -94
  738. package/.next/standalone/src/components/network/node-add-dialog.tsx +131 -131
  739. package/.next/standalone/src/components/network/node-badge.tsx +26 -26
  740. package/.next/standalone/src/components/network/node-list.tsx +207 -207
  741. package/.next/standalone/src/components/network/node-selector.tsx +49 -49
  742. package/.next/standalone/src/components/sessions/session-filters.tsx +116 -116
  743. package/.next/standalone/src/components/sessions/session-list.tsx +485 -485
  744. package/.next/standalone/src/components/terminal/pane-diff-panel.tsx +179 -179
  745. package/.next/standalone/src/components/terminal/terminal-pane.tsx +1530 -1464
  746. package/.next/standalone/src/components/viewer/chat-input.tsx +275 -275
  747. package/.next/standalone/src/components/viewer/message-renderer.tsx +551 -551
  748. package/.next/standalone/src/components/wizard/chart-wizard.tsx +405 -0
  749. package/.next/standalone/src/components/wizard/project-wizard.tsx +153 -153
  750. package/.next/standalone/src/components/wizard/wizard-chat.tsx +99 -99
  751. package/.next/standalone/src/components/wizard/wizard-plan-summary.tsx +103 -103
  752. package/.next/standalone/src/components/wizard/wizard-review.tsx +225 -225
  753. package/.next/standalone/src/components/workspace/universe-cluster.tsx +131 -131
  754. package/.next/standalone/src/components/workspace/universe-orb.tsx +128 -128
  755. package/.next/standalone/src/components/workspace/universe-types.ts +22 -22
  756. package/.next/standalone/src/components/workspace/universe-utils.ts +11 -11
  757. package/.next/standalone/src/components/workspace/universe-view.tsx +397 -397
  758. package/.next/standalone/src/components/workspace/workspace-chooser.tsx +634 -634
  759. package/.next/standalone/src/hooks/use-benchmark.ts +72 -71
  760. package/.next/standalone/src/hooks/use-bus.ts +147 -147
  761. package/.next/standalone/src/hooks/use-idle-detection.ts +79 -79
  762. package/.next/standalone/src/hooks/use-network.ts +229 -229
  763. package/.next/standalone/src/hooks/use-sessions.ts +437 -437
  764. package/.next/standalone/src/hooks/use-speech-recognition.ts +114 -113
  765. package/.next/standalone/src/hooks/use-sse.ts +35 -35
  766. package/.next/standalone/src/hooks/use-tier.ts +39 -39
  767. package/.next/standalone/src/lib/agents.ts +97 -97
  768. package/.next/standalone/src/lib/aider/parser.ts +111 -111
  769. package/.next/standalone/src/lib/api.ts +19 -19
  770. package/.next/standalone/src/lib/auth.ts +47 -47
  771. package/.next/standalone/src/lib/claude/parser.ts +212 -212
  772. package/.next/standalone/src/lib/claude/stats.ts +204 -204
  773. package/.next/standalone/src/lib/codex/parser.test.ts +111 -111
  774. package/.next/standalone/src/lib/codex/parser.ts +287 -287
  775. package/.next/standalone/src/lib/config.ts +132 -132
  776. package/.next/standalone/src/lib/cortex/benchmark.ts +83 -67
  777. package/.next/standalone/src/lib/cortex/config.ts +42 -42
  778. package/.next/standalone/src/lib/cortex/debug.ts +10 -10
  779. package/.next/standalone/src/lib/cortex/distillation/usage-store.ts +18 -18
  780. package/.next/standalone/src/lib/cortex/graph/resolver.ts +10 -10
  781. package/.next/standalone/src/lib/cortex/graph/types.ts +22 -22
  782. package/.next/standalone/src/lib/cortex/index.ts +109 -56
  783. package/.next/standalone/src/lib/cortex/ingestion/bootstrap.ts +14 -14
  784. package/.next/standalone/src/lib/cortex/knowledge/compat.ts +14 -14
  785. package/.next/standalone/src/lib/cortex/knowledge/contradiction.ts +10 -10
  786. package/.next/standalone/src/lib/cortex/knowledge/types.ts +67 -67
  787. package/.next/standalone/src/lib/cortex/lobes/config.ts +16 -16
  788. package/.next/standalone/src/lib/cortex/lobes/resolver.ts +8 -8
  789. package/.next/standalone/src/lib/cortex/lobes/shares.ts +14 -14
  790. package/.next/standalone/src/lib/cortex/mcp/server.ts +12 -12
  791. package/.next/standalone/src/lib/cortex/portability/exporter.ts +6 -6
  792. package/.next/standalone/src/lib/cortex/portability/importer.ts +10 -10
  793. package/.next/standalone/src/lib/cortex/retrieval/context-engine.ts +10 -10
  794. package/.next/standalone/src/lib/cortex/types.ts +39 -39
  795. package/.next/standalone/src/lib/cost-calculator.ts +48 -48
  796. package/.next/standalone/src/lib/db/init.ts +71 -71
  797. package/.next/standalone/src/lib/db/queries.ts +740 -827
  798. package/.next/standalone/src/lib/db/schema.ts +206 -206
  799. package/.next/standalone/src/lib/events/sse.ts +36 -36
  800. package/.next/standalone/src/lib/forge/parser.ts +52 -52
  801. package/.next/standalone/src/lib/gemini/parser.ts +258 -258
  802. package/.next/standalone/src/lib/license.ts +56 -56
  803. package/.next/standalone/src/lib/pro.ts +31 -31
  804. package/.next/standalone/src/lib/shell-user.ts +101 -0
  805. package/.next/standalone/src/lib/sync/indexer.ts +504 -504
  806. package/.next/standalone/src/lib/sync/watcher.ts +64 -64
  807. package/.next/standalone/src/lib/teams.ts +31 -31
  808. package/.next/standalone/src/lib/telemetry.ts +75 -75
  809. package/.next/standalone/src/lib/terminal/server.ts +188 -188
  810. package/.next/standalone/src/lib/tier.ts +38 -38
  811. package/.next/standalone/src/lib/utils.ts +72 -72
  812. package/.next/standalone/src/lib/vms/manager.ts +121 -121
  813. package/.next/standalone/src/middleware.ts +133 -133
  814. package/.next/standalone/src/types/claude.ts +208 -208
  815. package/.next/standalone/src/types/network.ts +61 -61
  816. package/.next/standalone/tests/setup.ts +8 -8
  817. package/.next/standalone/tsconfig.json +34 -34
  818. package/.next/standalone/vitest.config.ts +24 -24
  819. package/LICENSE +661 -661
  820. package/README.md +131 -131
  821. package/bin/cortex-hook.js +79 -79
  822. package/bin/cortex-hook.sh +62 -62
  823. package/bin/cortex-learn-hook.js +138 -138
  824. package/bin/cortex-mcp.js +60 -60
  825. package/bin/cortex-pi-extension.ts +170 -170
  826. package/bin/fix-standalone-externals.js +79 -79
  827. package/bin/lib/auto-setup.js +110 -110
  828. package/bin/mdns-service.js +171 -171
  829. package/bin/postinstall.js +35 -35
  830. package/bin/setup-admin.js +195 -195
  831. package/bin/spaces-dev.js +247 -247
  832. package/bin/spaces-install.js +660 -660
  833. package/bin/spaces-postinstall.js +50 -50
  834. package/bin/spaces-reset-totp.js +50 -50
  835. package/bin/spaces-service.js +1046 -1046
  836. package/bin/spaces-setup.js +253 -253
  837. package/bin/spaces.js +808 -805
  838. package/bin/ssh-auth-keys.sh +68 -68
  839. package/bin/terminal-server.js +2819 -2781
  840. package/package.json +111 -111
  841. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0903a426._.js +0 -98
  842. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09e8ccc9._.js +0 -98
  843. package/.next/standalone/.next/server/chunks/[root-of-the-server]__11c684b1._.js +0 -98
  844. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1572d4ef._.js +0 -98
  845. package/.next/standalone/.next/server/chunks/[root-of-the-server]__186cd0bb._.js +0 -3
  846. package/.next/standalone/.next/server/chunks/[root-of-the-server]__212760e6._.js +0 -98
  847. package/.next/standalone/.next/server/chunks/[root-of-the-server]__228595ec._.js +0 -98
  848. package/.next/standalone/.next/server/chunks/[root-of-the-server]__283c890f._.js +0 -3
  849. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2f300a68._.js +0 -98
  850. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2f452778._.js +0 -98
  851. package/.next/standalone/.next/server/chunks/[root-of-the-server]__35f8e77e._.js +0 -98
  852. package/.next/standalone/.next/server/chunks/[root-of-the-server]__379fc2e9._.js +0 -98
  853. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3b40d79f._.js +0 -98
  854. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3d3dca2b._.js +0 -98
  855. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4d5b78d2._.js +0 -98
  856. package/.next/standalone/.next/server/chunks/[root-of-the-server]__54163e52._.js +0 -98
  857. package/.next/standalone/.next/server/chunks/[root-of-the-server]__563c0817._.js +0 -3
  858. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5812f90a._.js +0 -98
  859. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c5e87f5._.js +0 -98
  860. package/.next/standalone/.next/server/chunks/[root-of-the-server]__60d15b16._.js +0 -98
  861. package/.next/standalone/.next/server/chunks/[root-of-the-server]__69d315e5._.js +0 -3
  862. package/.next/standalone/.next/server/chunks/[root-of-the-server]__71f29038._.js +0 -98
  863. package/.next/standalone/.next/server/chunks/[root-of-the-server]__74084e07._.js +0 -3
  864. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7921aa80._.js +0 -98
  865. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e077dd8._.js +0 -98
  866. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7ebc4280._.js +0 -131
  867. package/.next/standalone/.next/server/chunks/[root-of-the-server]__857c60bb._.js +0 -98
  868. package/.next/standalone/.next/server/chunks/[root-of-the-server]__874fe565._.js +0 -98
  869. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8e2171f7._.js +0 -98
  870. package/.next/standalone/.next/server/chunks/[root-of-the-server]__95659b2d._.js +0 -98
  871. package/.next/standalone/.next/server/chunks/[root-of-the-server]__9679b91e._.js +0 -98
  872. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a90729a1._.js +0 -98
  873. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ad4346fa._.js +0 -98
  874. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b0862d69._.js +0 -98
  875. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b43306ee._.js +0 -98
  876. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b689ff5e._.js +0 -106
  877. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ba87daaa._.js +0 -98
  878. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c0461005._.js +0 -98
  879. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c1deb5f3._.js +0 -98
  880. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c8a62f42._.js +0 -98
  881. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cabaac2b._.js +0 -98
  882. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cb027619._.js +0 -98
  883. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cf608218._.js +0 -98
  884. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cfc1290d._.js +0 -98
  885. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d0109b9b._.js +0 -98
  886. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d0125483._.js +0 -3
  887. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d048ee6b._.js +0 -98
  888. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d12644e7._.js +0 -98
  889. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e3cc946c._.js +0 -98
  890. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e6fd27f8._.js +0 -98
  891. package/.next/standalone/.next/server/chunks/[root-of-the-server]__efb8251e._.js +0 -98
  892. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f44c6882._.js +0 -98
  893. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f85283de._.js +0 -98
  894. package/.next/standalone/.next/server/chunks/[root-of-the-server]__feceb3e4._.js +0 -98
  895. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__843070a6._.js +0 -3
  896. package/.next/standalone/.next/server/chunks/ssr/_e84a0c06._.js +0 -3
  897. package/.next/standalone/.next/static/chunks/470cade58d4eceeb.css +0 -3
  898. package/.next/standalone/.next/static/chunks/9d4164833c2c1fd6.js +0 -85
  899. package/.next/standalone/.next/static/chunks/f091f4bf8d80fd07.js +0 -1
  900. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/README.md +0 -46
  901. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  902. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/index.js +0 -1
  903. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  904. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/package.json +0 -42
  905. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
  906. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  907. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
  908. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  909. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
  910. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
  911. package/.next/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  912. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  913. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
  914. /package/.next/standalone/.next/static/{5S4TviTCiNiTjf6KjXjBo → u1pHON3drz1mBi7owkbBP}/_buildManifest.js +0 -0
  915. /package/.next/standalone/.next/static/{5S4TviTCiNiTjf6KjXjBo → u1pHON3drz1mBi7owkbBP}/_clientMiddlewareManifest.json +0 -0
  916. /package/.next/standalone/.next/static/{5S4TviTCiNiTjf6KjXjBo → u1pHON3drz1mBi7owkbBP}/_ssgManifest.js +0 -0
  917. /package/.next/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-win32-x64}/versions.json +0 -0
@@ -1,1274 +1,1274 @@
1
- # Cortex v2 — Pillar 3: Context Assembly Engine
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:** Replace the flat layer-iteration search with a 6-stage context assembly pipeline that detects intent, resolves entities, computes graph-aware weights, searches multiple scopes in parallel, fuses results with evidence scoring, and surfaces conflicts — all within 150ms.
6
-
7
- **Architecture:** A new `ContextEngine` class wraps the existing `CortexStore` (for low-level vector search) and `EntityGraph` (for graph distance/proximity). It does NOT replace `CortexSearch` — instead it provides the higher-level retrieval interface that the RAG hook calls. The existing `CortexSearch` remains for backward-compatible simple searches. The RAG hook (`cortex-hook.js`) switches from calling the search API to calling a new context-assembly API endpoint.
8
-
9
- **Tech Stack:** TypeScript, vitest, LanceDB, SQLite (entity graph)
10
-
11
- **Spec:** `docs/superpowers/specs/2026-03-14-cortex-v2-design.md` — Pillar 3
12
-
13
- **Depends on:** Pillar 1 (Entity Graph) + Pillar 2 (Knowledge Unit Evolution) — both completed
14
-
15
- ---
16
-
17
- ## File Structure
18
-
19
- ```
20
- New files:
21
- ├── src/lib/cortex/retrieval/intent.ts — Intent detection (regex + keyword)
22
- ├── src/lib/cortex/retrieval/weight.ts — Weight computation (graph × intent × freshness × authority)
23
- ├── src/lib/cortex/retrieval/conflict.ts — Conflict detection in results
24
- ├── src/lib/cortex/retrieval/formatter.ts — Context formatting for RAG injection
25
- ├── src/lib/cortex/retrieval/context-engine.ts — Main 6-stage ContextEngine class
26
- ├── src/app/api/cortex/context/route.ts — API endpoint for context assembly
27
-
28
- Modified files:
29
- ├── bin/cortex-hook.js — Switch to context-assembly endpoint
30
-
31
- Test files:
32
- ├── tests/lib/cortex/retrieval/intent.test.ts
33
- ├── tests/lib/cortex/retrieval/weight.test.ts
34
- ├── tests/lib/cortex/retrieval/conflict.test.ts
35
- ├── tests/lib/cortex/retrieval/formatter.test.ts
36
- ├── tests/lib/cortex/retrieval/context-engine.test.ts
37
- ```
38
-
39
- ---
40
-
41
- ## Chunk 1: Intent Detection and Weight Computation
42
-
43
- ### Task 1: Intent detection
44
-
45
- **Files:**
46
- - Create: `src/lib/cortex/retrieval/intent.ts`
47
- - Create: `tests/lib/cortex/retrieval/intent.test.ts`
48
-
49
- - [ ] **Step 1: Write failing tests**
50
-
51
- ```typescript
52
- // tests/lib/cortex/retrieval/intent.test.ts
53
- import { describe, it, expect } from 'vitest';
54
- import { detectIntent, INTENTS } from '@/lib/cortex/retrieval/intent';
55
- import type { IntentResult } from '@/lib/cortex/retrieval/intent';
56
-
57
- describe('detectIntent', () => {
58
- it('detects debugging intent', () => {
59
- const result = detectIntent('why does the auth service throw a timeout error?');
60
- expect(result.intent).toBe('debugging');
61
- expect(result.confidence).toBeGreaterThan(0.5);
62
- });
63
-
64
- it('detects architecture intent', () => {
65
- const result = detectIntent('what architecture pattern should we use for the new service?');
66
- expect(result.intent).toBe('architecture');
67
- });
68
-
69
- it('detects how-to intent', () => {
70
- const result = detectIntent('how do I deploy this service to production?');
71
- expect(result.intent).toBe('how-to');
72
- });
73
-
74
- it('detects security intent', () => {
75
- const result = detectIntent('is there a vulnerability in our authentication flow?');
76
- expect(result.intent).toBe('security');
77
- });
78
-
79
- it('defaults to general for ambiguous queries', () => {
80
- const result = detectIntent('tell me about the project');
81
- expect(result.intent).toBe('general');
82
- });
83
-
84
- it('returns bias config for the detected intent', () => {
85
- const result = detectIntent('fix this bug in the login page');
86
- expect(result.biases).toBeDefined();
87
- expect(result.biases.scope_boost).toBeDefined();
88
- expect(result.biases.type_boost).toBeDefined();
89
- });
90
-
91
- it('exports all intent definitions', () => {
92
- expect(Object.keys(INTENTS)).toContain('debugging');
93
- expect(Object.keys(INTENTS)).toContain('architecture');
94
- expect(Object.keys(INTENTS)).toContain('general');
95
- expect(Object.keys(INTENTS).length).toBe(8);
96
- });
97
- });
98
- ```
99
-
100
- - [ ] **Step 2: Run tests to verify they fail**
101
-
102
- Run: `npx vitest run tests/lib/cortex/retrieval/intent.test.ts`
103
-
104
- - [ ] **Step 3: Implement intent detection**
105
-
106
- ```typescript
107
- // src/lib/cortex/retrieval/intent.ts
108
-
109
- export interface IntentBiases {
110
- scope_boost: Record<string, number>; // scope level → multiplier
111
- type_boost: Record<string, number>; // knowledge type → multiplier
112
- recency_boost: number; // extra recency multiplier
113
- }
114
-
115
- export interface IntentResult {
116
- intent: string;
117
- confidence: number;
118
- biases: IntentBiases;
119
- }
120
-
121
- interface IntentDef {
122
- patterns: RegExp[];
123
- keywords: string[];
124
- biases: IntentBiases;
125
- }
126
-
127
- export const INTENTS: Record<string, IntentDef> = {
128
- debugging: {
129
- patterns: [
130
- /\b(error|bug|fix|crash|fail|broken|throw|exception|timeout|issue)\b/i,
131
- /\bwhy\s+(does|is|did|do)\b/i,
132
- /\bnot\s+work/i,
133
- ],
134
- keywords: ['error', 'bug', 'fix', 'debug', 'crash', 'fail', 'broken', 'throw', 'exception', 'timeout', 'issue', 'stack trace'],
135
- biases: {
136
- scope_boost: { personal: 1.2, team: 1.0, department: 0.9, organization: 0.8 },
137
- type_boost: { error_fix: 1.3, pattern: 1.0, decision: 0.8, conversation: 0.7 },
138
- recency_boost: 1.1,
139
- },
140
- },
141
- architecture: {
142
- patterns: [
143
- /\b(architect|design|pattern|structure|approach)\b/i,
144
- /\bshould\s+we\s+(use|adopt|switch|migrate)\b/i,
145
- ],
146
- keywords: ['architecture', 'design', 'pattern', 'structure', 'approach', 'decision', 'migration', 'refactor'],
147
- biases: {
148
- scope_boost: { personal: 0.9, team: 1.1, department: 1.2, organization: 1.0 },
149
- type_boost: { decision: 1.5, pattern: 1.2, error_fix: 0.7, conversation: 0.5 },
150
- recency_boost: 1.0,
151
- },
152
- },
153
- onboarding: {
154
- patterns: [
155
- /\b(how\s+does|explain|what\s+is|overview|getting\s+started)\b/i,
156
- /\bnew\s+to\b/i,
157
- ],
158
- keywords: ['explain', 'overview', 'introduction', 'getting started', 'onboarding', 'how does'],
159
- biases: {
160
- scope_boost: { personal: 0.7, team: 1.0, department: 1.1, organization: 1.2 },
161
- type_boost: { pattern: 1.3, decision: 1.2, summary: 1.2, conversation: 0.5 },
162
- recency_boost: 0.9,
163
- },
164
- },
165
- policy: {
166
- patterns: [
167
- /\b(policy|compliance|regulation|standard|rule|requirement)\b/i,
168
- /\ballowed\s+to\b/i,
169
- ],
170
- keywords: ['policy', 'compliance', 'standard', 'regulation', 'rule', 'requirement', 'allowed'],
171
- biases: {
172
- scope_boost: { personal: 0.6, team: 0.8, department: 1.0, organization: 1.3 },
173
- type_boost: { decision: 1.5, preference: 1.2, pattern: 0.8, conversation: 0.3 },
174
- recency_boost: 1.0,
175
- },
176
- },
177
- 'how-to': {
178
- patterns: [
179
- /\bhow\s+(do|can|to|should)\s+I?\b/i,
180
- /\bsteps?\s+(to|for)\b/i,
181
- /\bwhat('s| is)\s+the\s+(command|way|process)\b/i,
182
- ],
183
- keywords: ['how to', 'steps', 'command', 'run', 'deploy', 'install', 'configure', 'setup'],
184
- biases: {
185
- scope_boost: { personal: 1.2, team: 1.0, department: 0.8, organization: 0.7 },
186
- type_boost: { command: 1.3, pattern: 1.2, error_fix: 1.0, conversation: 0.6 },
187
- recency_boost: 1.05,
188
- },
189
- },
190
- review: {
191
- patterns: [
192
- /\b(review|feedback|improve|quality|best\s+practice)\b/i,
193
- /\bis\s+this\s+(good|correct|right)\b/i,
194
- ],
195
- keywords: ['review', 'feedback', 'quality', 'improve', 'best practice', 'convention'],
196
- biases: {
197
- scope_boost: { personal: 0.9, team: 1.2, department: 1.0, organization: 0.8 },
198
- type_boost: { preference: 1.3, pattern: 1.2, code_pattern: 1.2, decision: 1.0 },
199
- recency_boost: 1.0,
200
- },
201
- },
202
- security: {
203
- patterns: [
204
- /\b(security|vulnerab|exploit|attack|auth|cve|injection|xss)\b/i,
205
- /\bsecure\b/i,
206
- ],
207
- keywords: ['security', 'vulnerability', 'exploit', 'attack', 'authentication', 'authorization', 'cve', 'injection', 'xss', 'csrf'],
208
- biases: {
209
- scope_boost: { personal: 0.8, team: 1.0, department: 1.2, organization: 1.0 },
210
- type_boost: { error_fix: 1.3, decision: 1.2, pattern: 1.0, conversation: 0.5 },
211
- recency_boost: 1.1,
212
- },
213
- },
214
- general: {
215
- patterns: [],
216
- keywords: [],
217
- biases: {
218
- scope_boost: { personal: 1.0, team: 1.0, department: 1.0, organization: 1.0 },
219
- type_boost: {},
220
- recency_boost: 1.0,
221
- },
222
- },
223
- };
224
-
225
- /**
226
- * Detect the intent of a query using regex patterns and keyword scoring.
227
- * No LLM call — fast and deterministic.
228
- */
229
- export function detectIntent(query: string): IntentResult {
230
- const lower = query.toLowerCase();
231
- let bestIntent = 'general';
232
- let bestScore = 0;
233
-
234
- for (const [name, def] of Object.entries(INTENTS)) {
235
- if (name === 'general') continue;
236
-
237
- let score = 0;
238
-
239
- // Regex pattern matches (high weight)
240
- for (const pattern of def.patterns) {
241
- if (pattern.test(query)) score += 2;
242
- }
243
-
244
- // Keyword matches (lower weight)
245
- for (const keyword of def.keywords) {
246
- if (lower.includes(keyword)) score += 1;
247
- }
248
-
249
- if (score > bestScore) {
250
- bestScore = score;
251
- bestIntent = name;
252
- }
253
- }
254
-
255
- return {
256
- intent: bestIntent,
257
- confidence: bestScore > 0 ? Math.min(1.0, bestScore / 6) : 0.5,
258
- biases: INTENTS[bestIntent].biases,
259
- };
260
- }
261
- ```
262
-
263
- - [ ] **Step 4: Run tests to verify they pass**
264
-
265
- Run: `npx vitest run tests/lib/cortex/retrieval/intent.test.ts`
266
- Expected: PASS (7 tests)
267
-
268
- - [ ] **Step 5: Commit**
269
-
270
- ```bash
271
- git add src/lib/cortex/retrieval/intent.ts tests/lib/cortex/retrieval/intent.test.ts
272
- git commit -m "feat(cortex): add intent detection for context assembly"
273
- ```
274
-
275
- ---
276
-
277
- ### Task 2: Weight computation
278
-
279
- **Files:**
280
- - Create: `src/lib/cortex/retrieval/weight.ts`
281
- - Create: `tests/lib/cortex/retrieval/weight.test.ts`
282
-
283
- - [ ] **Step 1: Write failing tests**
284
-
285
- ```typescript
286
- // tests/lib/cortex/retrieval/weight.test.ts
287
- import { describe, it, expect } from 'vitest';
288
- import { computeScopeWeight } from '@/lib/cortex/retrieval/weight';
289
- import type { IntentBiases } from '@/lib/cortex/retrieval/intent';
290
-
291
- describe('computeScopeWeight', () => {
292
- const neutralBiases: IntentBiases = {
293
- scope_boost: { personal: 1.0, team: 1.0, department: 1.0, organization: 1.0 },
294
- type_boost: {},
295
- recency_boost: 1.0,
296
- };
297
-
298
- it('returns 1.0 for self (distance 0)', () => {
299
- const weight = computeScopeWeight({
300
- graphProximity: 1.0, // 1/(1+0)
301
- scopeLevel: 'personal',
302
- intentBiases: neutralBiases,
303
- authorityFactor: 1.0,
304
- });
305
- expect(weight).toBeCloseTo(1.0);
306
- });
307
-
308
- it('decreases with graph distance', () => {
309
- const close = computeScopeWeight({
310
- graphProximity: 0.5, // distance 1
311
- scopeLevel: 'team',
312
- intentBiases: neutralBiases,
313
- authorityFactor: 1.0,
314
- });
315
- const far = computeScopeWeight({
316
- graphProximity: 0.25, // distance 3
317
- scopeLevel: 'organization',
318
- intentBiases: neutralBiases,
319
- authorityFactor: 1.0,
320
- });
321
- expect(close).toBeGreaterThan(far);
322
- });
323
-
324
- it('is boosted by intent biases', () => {
325
- const debugBiases: IntentBiases = {
326
- scope_boost: { personal: 1.2, team: 0.8 },
327
- type_boost: {},
328
- recency_boost: 1.0,
329
- };
330
- const personal = computeScopeWeight({
331
- graphProximity: 0.5,
332
- scopeLevel: 'personal',
333
- intentBiases: debugBiases,
334
- authorityFactor: 1.0,
335
- });
336
- const team = computeScopeWeight({
337
- graphProximity: 0.5,
338
- scopeLevel: 'team',
339
- intentBiases: debugBiases,
340
- authorityFactor: 1.0,
341
- });
342
- expect(personal).toBeGreaterThan(team);
343
- });
344
-
345
- it('is boosted by authority factor', () => {
346
- const low = computeScopeWeight({
347
- graphProximity: 0.5,
348
- scopeLevel: 'team',
349
- intentBiases: neutralBiases,
350
- authorityFactor: 1.0,
351
- });
352
- const high = computeScopeWeight({
353
- graphProximity: 0.5,
354
- scopeLevel: 'team',
355
- intentBiases: neutralBiases,
356
- authorityFactor: 1.2,
357
- });
358
- expect(high).toBeGreaterThan(low);
359
- });
360
-
361
- it('never returns negative', () => {
362
- const weight = computeScopeWeight({
363
- graphProximity: 0,
364
- scopeLevel: 'organization',
365
- intentBiases: neutralBiases,
366
- authorityFactor: 1.0,
367
- });
368
- expect(weight).toBeGreaterThanOrEqual(0);
369
- });
370
- });
371
- ```
372
-
373
- - [ ] **Step 2: Run tests to verify they fail**
374
-
375
- Run: `npx vitest run tests/lib/cortex/retrieval/weight.test.ts`
376
-
377
- - [ ] **Step 3: Implement weight computation**
378
-
379
- ```typescript
380
- // src/lib/cortex/retrieval/weight.ts
381
- import type { IntentBiases } from './intent';
382
- import type { ScopeLevel } from '../knowledge/types';
383
-
384
- export interface ScopeWeightInput {
385
- graphProximity: number; // 0-1, from EntityGraph.proximity()
386
- scopeLevel: ScopeLevel | string;
387
- intentBiases: IntentBiases;
388
- authorityFactor: number; // 1.0 default, higher for experts/docs
389
- }
390
-
391
- /**
392
- * Compute the retrieval weight for a knowledge scope.
393
- *
394
- * weight = graphProximity × intentBias × authorityFactor
395
- *
396
- * Per spec: weight(scope) = graph_proximity × intent_bias × freshness_bonus × authority
397
- * Freshness is applied per-result in the fusion stage, not per-scope.
398
- */
399
- export function computeScopeWeight(input: ScopeWeightInput): number {
400
- const { graphProximity, scopeLevel, intentBiases, authorityFactor } = input;
401
-
402
- const intentBias = intentBiases.scope_boost[scopeLevel] ?? 1.0;
403
-
404
- return Math.max(0, graphProximity * intentBias * authorityFactor);
405
- }
406
-
407
- /**
408
- * Compute per-result type boost from intent biases.
409
- */
410
- export function computeTypeBoost(knowledgeType: string, intentBiases: IntentBiases): number {
411
- return intentBiases.type_boost[knowledgeType] ?? 1.0;
412
- }
413
-
414
- /**
415
- * Authority factor for a source based on role and expertise.
416
- *
417
- * role_boost: 0.0 member, 0.1 lead, 0.15 senior/principal, 0.2 director+
418
- * expertise_weight: EXPERT_IN edge weight (0-1)
419
- * Documents get 1.2 base authority.
420
- */
421
- export function computeAuthority(params: {
422
- role?: string;
423
- expertiseWeight?: number;
424
- isDocument?: boolean;
425
- }): number {
426
- const { role, expertiseWeight = 0, isDocument = false } = params;
427
-
428
- if (isDocument) return 1.2;
429
-
430
- const roleBoosts: Record<string, number> = {
431
- member: 0.0,
432
- lead: 0.1,
433
- senior: 0.15,
434
- principal: 0.15,
435
- director: 0.2,
436
- vp: 0.2,
437
- cto: 0.2,
438
- };
439
-
440
- const roleBoost = roleBoosts[role?.toLowerCase() ?? 'member'] ?? 0.0;
441
- return Math.max(1.0, roleBoost + expertiseWeight);
442
- }
443
- ```
444
-
445
- - [ ] **Step 4: Run tests to verify they pass**
446
-
447
- Run: `npx vitest run tests/lib/cortex/retrieval/weight.test.ts`
448
- Expected: PASS (5 tests)
449
-
450
- - [ ] **Step 5: Commit**
451
-
452
- ```bash
453
- git add src/lib/cortex/retrieval/weight.ts tests/lib/cortex/retrieval/weight.test.ts
454
- git commit -m "feat(cortex): add scope weight computation for context assembly"
455
- ```
456
-
457
- ---
458
-
459
- ## Chunk 2: Conflict Detection and Context Formatting
460
-
461
- ### Task 3: Conflict detection
462
-
463
- **Files:**
464
- - Create: `src/lib/cortex/retrieval/conflict.ts`
465
- - Create: `tests/lib/cortex/retrieval/conflict.test.ts`
466
-
467
- - [ ] **Step 1: Write failing tests**
468
-
469
- ```typescript
470
- // tests/lib/cortex/retrieval/conflict.test.ts
471
- import { describe, it, expect } from 'vitest';
472
- import { detectConflicts } from '@/lib/cortex/retrieval/conflict';
473
- import type { ScoredKnowledge } from '@/lib/cortex/knowledge/types';
474
-
475
- function makeResult(overrides: Partial<ScoredKnowledge> = {}): ScoredKnowledge {
476
- return {
477
- id: 'r1', vector: [], text: 'test', type: 'decision', layer: 'personal',
478
- workspace_id: null, session_id: null, agent_type: 'claude',
479
- project_path: null, file_refs: [], confidence: 0.8,
480
- created: new Date().toISOString(), source_timestamp: new Date().toISOString(),
481
- stale_score: 0, access_count: 0, last_accessed: null, metadata: {},
482
- relevance_score: 0.9, similarity: 0.9,
483
- contradiction_refs: [], ...overrides,
484
- };
485
- }
486
-
487
- describe('detectConflicts', () => {
488
- it('returns no conflicts when no contradiction_refs', () => {
489
- const results = [makeResult({ id: 'a' }), makeResult({ id: 'b' })];
490
- const conflicts = detectConflicts(results);
491
- expect(conflicts).toHaveLength(0);
492
- });
493
-
494
- it('detects conflict between two results', () => {
495
- const results = [
496
- makeResult({ id: 'a', text: 'use pool size 50', contradiction_refs: ['b'] }),
497
- makeResult({ id: 'b', text: 'scale horizontally', contradiction_refs: ['a'] }),
498
- ];
499
- const conflicts = detectConflicts(results);
500
- expect(conflicts).toHaveLength(1);
501
- expect(conflicts[0].unitA.id).toBe('a');
502
- expect(conflicts[0].unitB.id).toBe('b');
503
- });
504
-
505
- it('ignores contradiction_refs pointing to results not in the set', () => {
506
- const results = [
507
- makeResult({ id: 'a', contradiction_refs: ['z'] }), // z is not in results
508
- ];
509
- const conflicts = detectConflicts(results);
510
- expect(conflicts).toHaveLength(0);
511
- });
512
-
513
- it('deduplicates symmetric conflicts', () => {
514
- // A contradicts B and B contradicts A should produce one conflict, not two
515
- const results = [
516
- makeResult({ id: 'a', contradiction_refs: ['b'] }),
517
- makeResult({ id: 'b', contradiction_refs: ['a'] }),
518
- ];
519
- const conflicts = detectConflicts(results);
520
- expect(conflicts).toHaveLength(1);
521
- });
522
- });
523
- ```
524
-
525
- - [ ] **Step 2: Implement conflict detection**
526
-
527
- ```typescript
528
- // src/lib/cortex/retrieval/conflict.ts
529
- import type { ScoredKnowledge } from '../knowledge/types';
530
-
531
- export interface ConflictPair {
532
- unitA: ScoredKnowledge;
533
- unitB: ScoredKnowledge;
534
- }
535
-
536
- /**
537
- * Detect conflicts among search results by checking contradiction_refs.
538
- * Returns deduplicated conflict pairs (A↔B counted once, not twice).
539
- */
540
- export function detectConflicts(results: ScoredKnowledge[]): ConflictPair[] {
541
- const resultMap = new Map(results.map(r => [r.id, r]));
542
- const seen = new Set<string>();
543
- const conflicts: ConflictPair[] = [];
544
-
545
- for (const result of results) {
546
- const refs = result.contradiction_refs ?? [];
547
- for (const refId of refs) {
548
- const other = resultMap.get(refId);
549
- if (!other) continue;
550
-
551
- const key = [result.id, refId].sort().join('|');
552
- if (seen.has(key)) continue;
553
- seen.add(key);
554
-
555
- conflicts.push({ unitA: result, unitB: other });
556
- }
557
- }
558
-
559
- return conflicts;
560
- }
561
- ```
562
-
563
- - [ ] **Step 3: Run tests, commit**
564
-
565
- Run: `npx vitest run tests/lib/cortex/retrieval/conflict.test.ts`
566
-
567
- ```bash
568
- git add src/lib/cortex/retrieval/conflict.ts tests/lib/cortex/retrieval/conflict.test.ts
569
- git commit -m "feat(cortex): add conflict detection for search results"
570
- ```
571
-
572
- ---
573
-
574
- ### Task 4: Context formatter
575
-
576
- **Files:**
577
- - Create: `src/lib/cortex/retrieval/formatter.ts`
578
- - Create: `tests/lib/cortex/retrieval/formatter.test.ts`
579
-
580
- - [ ] **Step 1: Write failing tests**
581
-
582
- ```typescript
583
- // tests/lib/cortex/retrieval/formatter.test.ts
584
- import { describe, it, expect } from 'vitest';
585
- import { formatContext } from '@/lib/cortex/retrieval/formatter';
586
- import type { ScoredKnowledge } from '@/lib/cortex/knowledge/types';
587
- import type { ConflictPair } from '@/lib/cortex/retrieval/conflict';
588
-
589
- function makeResult(overrides: Partial<ScoredKnowledge> = {}): ScoredKnowledge {
590
- return {
591
- id: 'r1', vector: [], text: 'test knowledge', type: 'decision', layer: 'personal',
592
- workspace_id: null, session_id: null, agent_type: 'claude',
593
- project_path: null, file_refs: [], confidence: 0.8,
594
- created: '2026-03-15T00:00:00.000Z', source_timestamp: '2026-03-15T00:00:00.000Z',
595
- stale_score: 0, access_count: 5, last_accessed: null, metadata: {},
596
- relevance_score: 0.9, similarity: 0.9,
597
- ...overrides,
598
- };
599
- }
600
-
601
- describe('formatContext', () => {
602
- it('wraps results in cortex-context tags', () => {
603
- const output = formatContext([makeResult()], []);
604
- expect(output).toContain('<cortex-context>');
605
- expect(output).toContain('</cortex-context>');
606
- });
607
-
608
- it('includes type labels and dates', () => {
609
- const output = formatContext([makeResult({ type: 'error_fix', source_timestamp: '2026-03-10T00:00:00.000Z' })], []);
610
- expect(output).toContain('[Error Fix]');
611
- expect(output).toContain('2026-03-10');
612
- });
613
-
614
- it('includes source attribution when origin is present', () => {
615
- const output = formatContext([makeResult({
616
- origin: { source_type: 'conversation', source_ref: 'sess-1', creator_entity_id: 'person-alice' },
617
- })], []);
618
- expect(output).toContain('person-alice');
619
- });
620
-
621
- it('includes conflict callout when conflicts exist', () => {
622
- const a = makeResult({ id: 'a', text: 'use pool size 50' });
623
- const b = makeResult({ id: 'b', text: 'scale horizontally' });
624
- const conflicts: ConflictPair[] = [{ unitA: a, unitB: b }];
625
- const output = formatContext([a, b], conflicts);
626
- expect(output).toContain('Conflicting');
627
- });
628
-
629
- it('respects max token budget', () => {
630
- const bigResults = Array.from({ length: 20 }, (_, i) =>
631
- makeResult({ id: `r${i}`, text: 'x'.repeat(500) })
632
- );
633
- const output = formatContext(bigResults, [], { maxTokens: 500 });
634
- // Should not include all 20 results (would be ~2500 tokens)
635
- expect(output.length).toBeLessThan(3000);
636
- });
637
-
638
- it('returns empty string when no results', () => {
639
- expect(formatContext([], [])).toBe('');
640
- });
641
- });
642
- ```
643
-
644
- - [ ] **Step 2: Implement context formatter**
645
-
646
- ```typescript
647
- // src/lib/cortex/retrieval/formatter.ts
648
- import type { ScoredKnowledge } from '../knowledge/types';
649
- import type { ConflictPair } from './conflict';
650
-
651
- const TYPE_LABELS: Record<string, string> = {
652
- decision: 'Decision', pattern: 'Pattern', preference: 'Preference',
653
- error_fix: 'Error Fix', context: 'Context', code_pattern: 'Code',
654
- command: 'Command', conversation: 'Conversation', summary: 'Summary',
655
- };
656
-
657
- export interface FormatOptions {
658
- maxTokens?: number;
659
- }
660
-
661
- /**
662
- * Format search results + conflicts as annotated <cortex-context> for RAG injection.
663
- */
664
- export function formatContext(
665
- results: ScoredKnowledge[],
666
- conflicts: ConflictPair[],
667
- options: FormatOptions = {},
668
- ): string {
669
- if (results.length === 0) return '';
670
-
671
- const maxTokens = options.maxTokens ?? 1500;
672
- const entries: string[] = [];
673
- let tokens = 20; // overhead for tags
674
-
675
- // Format each result with attribution
676
- for (const unit of results) {
677
- const label = TYPE_LABELS[unit.type] || unit.type;
678
- const date = (unit.source_timestamp || '').slice(0, 10);
679
- const creator = unit.origin?.creator_entity_id ?? '';
680
- const sourceInfo = creator ? ` (${creator})` : '';
681
-
682
- let entry = `[${label}] ${date}${sourceInfo}:\n ${unit.text}`;
683
-
684
- const entryTokens = Math.ceil(entry.length / 4);
685
- if (tokens + entryTokens > maxTokens) break;
686
-
687
- entries.push(entry);
688
- tokens += entryTokens;
689
- }
690
-
691
- if (entries.length === 0) return '';
692
-
693
- // Build conflict section
694
- let conflictSection = '';
695
- if (conflicts.length > 0) {
696
- const conflictLines = conflicts.map(c =>
697
- ` - "${c.unitA.text.slice(0, 80)}..." vs "${c.unitB.text.slice(0, 80)}..."`
698
- );
699
- conflictSection = `\nConflicting perspectives (${conflicts.length}):\n${conflictLines.join('\n')}\n`;
700
- }
701
-
702
- const sourceCount = entries.length;
703
- const header = `Relevant knowledge (${sourceCount} source${sourceCount > 1 ? 's' : ''}${conflicts.length > 0 ? `, ${conflicts.length} conflict${conflicts.length > 1 ? 's' : ''}` : ''}):`;
704
-
705
- return [
706
- '<cortex-context>',
707
- header,
708
- '',
709
- ...entries,
710
- conflictSection,
711
- '</cortex-context>',
712
- ].join('\n');
713
- }
714
- ```
715
-
716
- - [ ] **Step 3: Run tests, commit**
717
-
718
- Run: `npx vitest run tests/lib/cortex/retrieval/formatter.test.ts`
719
-
720
- ```bash
721
- git add src/lib/cortex/retrieval/formatter.ts tests/lib/cortex/retrieval/formatter.test.ts
722
- git commit -m "feat(cortex): add context formatter for RAG injection"
723
- ```
724
-
725
- ---
726
-
727
- ## Chunk 3: Context Assembly Engine
728
-
729
- ### Task 5: ContextEngine — the 6-stage pipeline
730
-
731
- **Files:**
732
- - Create: `src/lib/cortex/retrieval/context-engine.ts`
733
- - Create: `tests/lib/cortex/retrieval/context-engine.test.ts`
734
-
735
- - [ ] **Step 1: Write failing tests**
736
-
737
- ```typescript
738
- // tests/lib/cortex/retrieval/context-engine.test.ts
739
- import { describe, it, expect, vi, beforeEach } from 'vitest';
740
- import { ContextEngine } from '@/lib/cortex/retrieval/context-engine';
741
-
742
- // Create mocks for dependencies
743
- const mockStore = {
744
- search: vi.fn().mockResolvedValue([]),
745
- };
746
-
747
- const mockGraph = {
748
- proximity: vi.fn().mockReturnValue(0.5),
749
- neighborhood: vi.fn().mockReturnValue([]),
750
- getEntity: vi.fn().mockReturnValue(null),
751
- };
752
-
753
- const mockResolver = {
754
- extractEntities: vi.fn().mockReturnValue([]),
755
- };
756
-
757
- const mockEmbedding = {
758
- embed: vi.fn().mockResolvedValue([[0.1, 0.2, 0.3]]),
759
- dimensions: 3,
760
- name: 'mock',
761
- init: vi.fn(),
762
- };
763
-
764
- describe('ContextEngine', () => {
765
- let engine: ContextEngine;
766
-
767
- beforeEach(() => {
768
- vi.clearAllMocks();
769
- engine = new ContextEngine({
770
- store: mockStore as any,
771
- graph: mockGraph as any,
772
- resolver: mockResolver as any,
773
- embedding: mockEmbedding as any,
774
- requesterId: 'person-alice',
775
- });
776
- });
777
-
778
- it('returns empty context for empty results', async () => {
779
- const result = await engine.assemble('some query');
780
- expect(result.results).toHaveLength(0);
781
- expect(result.context).toBe('');
782
- });
783
-
784
- it('calls embedding.embed with the query', async () => {
785
- await engine.assemble('test query');
786
- expect(mockEmbedding.embed).toHaveBeenCalledWith(['test query']);
787
- });
788
-
789
- it('detects intent from the query', async () => {
790
- const result = await engine.assemble('why does auth throw an error?');
791
- expect(result.intent.intent).toBe('debugging');
792
- });
793
-
794
- it('extracts entities from the query', async () => {
795
- mockResolver.extractEntities.mockReturnValue([
796
- { entity: { id: 'system-auth', type: 'system', name: 'Auth' }, confidence: 0.9, method: 'alias' },
797
- ]);
798
- const result = await engine.assemble('fix the auth service');
799
- expect(mockResolver.extractEntities).toHaveBeenCalledWith('fix the auth service');
800
- expect(result.entities).toHaveLength(1);
801
- });
802
-
803
- it('searches store with embedded query vector', async () => {
804
- mockStore.search.mockResolvedValue([{
805
- id: 'k1', text: 'test knowledge', type: 'decision', layer: 'personal',
806
- confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
807
- source_timestamp: new Date().toISOString(), evidence_score: 0.7,
808
- contradiction_refs: [], _distance: 0.2,
809
- workspace_id: null, session_id: null, agent_type: 'claude',
810
- project_path: null, file_refs: [], access_count: 0, last_accessed: null,
811
- metadata: {},
812
- }]);
813
-
814
- const result = await engine.assemble('test query');
815
- expect(result.results.length).toBeGreaterThanOrEqual(1);
816
- expect(result.context).toContain('<cortex-context>');
817
- });
818
-
819
- it('completes within performance budget', async () => {
820
- const start = Date.now();
821
- await engine.assemble('test query');
822
- const elapsed = Date.now() - start;
823
- expect(elapsed).toBeLessThan(500); // generous for CI, target is 150ms
824
- });
825
- });
826
- ```
827
-
828
- - [ ] **Step 2: Implement ContextEngine**
829
-
830
- ```typescript
831
- // src/lib/cortex/retrieval/context-engine.ts
832
- import type { CortexStore } from '../store';
833
- import type { EntityGraph } from '../graph/entity-graph';
834
- import type { EntityResolver, ResolvedEntity } from '../graph/resolver';
835
- import type { EmbeddingProvider } from '../embeddings';
836
- import type { ScoredKnowledge } from '../knowledge/types';
837
- import { detectIntent } from './intent';
838
- import type { IntentResult } from './intent';
839
- import { computeScopeWeight, computeTypeBoost } from './weight';
840
- import { detectConflicts } from './conflict';
841
- import type { ConflictPair } from './conflict';
842
- import { formatContext } from './formatter';
843
- import { computeRelevanceScore } from './scoring';
844
-
845
- export interface ContextEngineDeps {
846
- store: CortexStore;
847
- graph: EntityGraph;
848
- resolver: EntityResolver;
849
- embedding: EmbeddingProvider;
850
- requesterId: string; // entity ID of the person making the query
851
- }
852
-
853
- export interface AssemblyResult {
854
- results: ScoredKnowledge[];
855
- conflicts: ConflictPair[];
856
- context: string; // formatted <cortex-context> string
857
- intent: IntentResult;
858
- entities: ResolvedEntity[];
859
- timing: {
860
- intentMs: number;
861
- entityMs: number;
862
- searchMs: number;
863
- totalMs: number;
864
- };
865
- }
866
-
867
- interface SearchSource {
868
- layerKey: string;
869
- weight: number;
870
- limit: number;
871
- }
872
-
873
- const DEFAULT_LAYERS = ['personal', 'workspace', 'team'] as const;
874
- const SEARCH_TIMEOUT_MS = 100;
875
-
876
- export class ContextEngine {
877
- constructor(private deps: ContextEngineDeps) {}
878
-
879
- async assemble(query: string, options: { limit?: number; workspaceId?: number | null; maxTokens?: number } = {}): Promise<AssemblyResult> {
880
- const totalStart = Date.now();
881
- const { limit = 5, workspaceId = null, maxTokens = 1500 } = options;
882
-
883
- // Stage 1: Intent Detection
884
- const intentStart = Date.now();
885
- const intent = detectIntent(query);
886
- const intentMs = Date.now() - intentStart;
887
-
888
- // Stage 2: Entity Resolution
889
- const entityStart = Date.now();
890
- const entities = this.deps.resolver.extractEntities(query);
891
- const entityMs = Date.now() - entityStart;
892
-
893
- // Embed the query
894
- const [queryVector] = await this.deps.embedding.embed([query]);
895
-
896
- // Stage 3: Weight Computation
897
- const sources = this.computeSourceWeights(intent, workspaceId);
898
-
899
- // Stage 4: Parallel Multi-Source Search
900
- const searchStart = Date.now();
901
- const allResults = await this.parallelSearch(queryVector, sources, limit);
902
- const searchMs = Date.now() - searchStart;
903
-
904
- // Stage 5: Fusion + Re-Ranking
905
- const fused = this.fuseAndRank(allResults, intent, limit);
906
-
907
- // Stage 6: Conflict Detection + Formatting
908
- const conflicts = detectConflicts(fused);
909
- const context = formatContext(fused, conflicts, { maxTokens });
910
-
911
- return {
912
- results: fused,
913
- conflicts,
914
- context,
915
- intent,
916
- entities,
917
- timing: {
918
- intentMs,
919
- entityMs,
920
- searchMs,
921
- totalMs: Date.now() - totalStart,
922
- },
923
- };
924
- }
925
-
926
- private computeSourceWeights(intent: IntentResult, workspaceId: number | null): SearchSource[] {
927
- const sources: SearchSource[] = [];
928
-
929
- for (const layer of DEFAULT_LAYERS) {
930
- const layerKey = layer === 'workspace' && workspaceId
931
- ? `workspace/${workspaceId}` : layer;
932
-
933
- // Map v1 layer to scope level for intent bias lookup
934
- const scopeLevel = layer === 'personal' ? 'personal'
935
- : layer === 'workspace' ? 'team' : 'organization';
936
-
937
- // Use graph proximity if available, else fall back to fixed weights
938
- let graphProximity: number;
939
- try {
940
- // For personal, distance is 0; for workspace, 1; for team, 2
941
- const layerEntity = layer === 'personal' ? this.deps.requesterId
942
- : layer === 'workspace' ? 'team-default' : 'organization-default';
943
- graphProximity = this.deps.graph.proximity(this.deps.requesterId, layerEntity);
944
- } catch {
945
- // Graph not populated, use fallback
946
- graphProximity = layer === 'personal' ? 1.0 : layer === 'workspace' ? 0.5 : 0.33;
947
- }
948
-
949
- // If graph returns 0 (unreachable/not found), use fallback
950
- if (graphProximity === 0) {
951
- graphProximity = layer === 'personal' ? 1.0 : layer === 'workspace' ? 0.5 : 0.33;
952
- }
953
-
954
- const weight = computeScopeWeight({
955
- graphProximity,
956
- scopeLevel,
957
- intentBiases: intent.biases,
958
- authorityFactor: 1.0,
959
- });
960
-
961
- sources.push({
962
- layerKey,
963
- weight,
964
- limit: Math.max(3, Math.round(weight * 10)), // proportional slots
965
- });
966
- }
967
-
968
- return sources.sort((a, b) => b.weight - a.weight);
969
- }
970
-
971
- private async parallelSearch(
972
- queryVector: number[],
973
- sources: SearchSource[],
974
- limit: number,
975
- ): Promise<Array<ScoredKnowledge & { sourceWeight: number }>> {
976
- const searchPromises = sources.map(async (source) => {
977
- try {
978
- const results = await Promise.race([
979
- this.deps.store.search(source.layerKey, queryVector, source.limit),
980
- new Promise<never>((_, reject) =>
981
- setTimeout(() => reject(new Error('timeout')), SEARCH_TIMEOUT_MS)
982
- ),
983
- ]);
984
-
985
- return results.map(unit => {
986
- const similarity = 1 - ((unit as any)._distance ?? 0);
987
- return {
988
- ...unit,
989
- similarity,
990
- relevance_score: 0, // computed in fusion
991
- sourceWeight: source.weight,
992
- } as ScoredKnowledge & { sourceWeight: number };
993
- });
994
- } catch {
995
- return []; // source failed or timed out
996
- }
997
- });
998
-
999
- const settled = await Promise.allSettled(searchPromises);
1000
- const allResults: Array<ScoredKnowledge & { sourceWeight: number }> = [];
1001
-
1002
- for (const result of settled) {
1003
- if (result.status === 'fulfilled') {
1004
- allResults.push(...result.value);
1005
- }
1006
- }
1007
-
1008
- return allResults;
1009
- }
1010
-
1011
- private fuseAndRank(
1012
- results: Array<ScoredKnowledge & { sourceWeight: number }>,
1013
- intent: IntentResult,
1014
- limit: number,
1015
- ): ScoredKnowledge[] {
1016
- // Score each result
1017
- for (const result of results) {
1018
- const typeBoost = computeTypeBoost(result.type, intent.biases);
1019
- const recencyBoost = intent.biases.recency_boost;
1020
-
1021
- result.relevance_score = computeRelevanceScore({
1022
- similarity: result.similarity,
1023
- confidence: result.confidence,
1024
- stale_score: result.stale_score,
1025
- created: result.created,
1026
- evidence_score: result.evidence_score,
1027
- }) * result.sourceWeight * typeBoost * recencyBoost;
1028
- }
1029
-
1030
- // Deduplicate: cosine > 0.9 between results (approximate via text similarity)
1031
- const deduped = this.deduplicateResults(results);
1032
-
1033
- // Sort and take top K
1034
- deduped.sort((a, b) => b.relevance_score - a.relevance_score);
1035
- return deduped.slice(0, limit);
1036
- }
1037
-
1038
- private deduplicateResults(results: ScoredKnowledge[]): ScoredKnowledge[] {
1039
- const kept: ScoredKnowledge[] = [];
1040
- const seenTexts = new Set<string>();
1041
-
1042
- // Sort by score first so we keep the better-scored version
1043
- results.sort((a, b) => b.relevance_score - a.relevance_score);
1044
-
1045
- for (const result of results) {
1046
- // Simple text-based dedup: normalize and check prefix overlap
1047
- const normalized = result.text.slice(0, 200).toLowerCase().trim();
1048
- if (seenTexts.has(normalized)) continue;
1049
-
1050
- // Check against existing kept items for high text overlap
1051
- let isDupe = false;
1052
- for (const existing of kept) {
1053
- if (result.id === existing.id) { isDupe = true; break; }
1054
- // If texts share >80% of content, consider duplicate
1055
- const existNorm = existing.text.slice(0, 200).toLowerCase().trim();
1056
- if (normalized === existNorm) { isDupe = true; break; }
1057
- }
1058
-
1059
- if (!isDupe) {
1060
- seenTexts.add(normalized);
1061
- kept.push(result);
1062
- }
1063
- }
1064
-
1065
- return kept;
1066
- }
1067
- }
1068
- ```
1069
-
1070
- - [ ] **Step 3: Run tests to verify they pass**
1071
-
1072
- Run: `npx vitest run tests/lib/cortex/retrieval/context-engine.test.ts`
1073
- Expected: PASS (6 tests)
1074
-
1075
- - [ ] **Step 4: Commit**
1076
-
1077
- ```bash
1078
- git add src/lib/cortex/retrieval/context-engine.ts tests/lib/cortex/retrieval/context-engine.test.ts
1079
- git commit -m "feat(cortex): add ContextEngine with 6-stage retrieval pipeline"
1080
- ```
1081
-
1082
- ---
1083
-
1084
- ## Chunk 4: API Endpoint and Hook Integration
1085
-
1086
- ### Task 6: Context assembly API endpoint
1087
-
1088
- **Files:**
1089
- - Create: `src/app/api/cortex/context/route.ts`
1090
-
1091
- - [ ] **Step 1: Create the endpoint**
1092
-
1093
- ```typescript
1094
- // src/app/api/cortex/context/route.ts
1095
- import { NextResponse } from 'next/server';
1096
- import type { NextRequest } from 'next/server';
1097
- import { getAuthUser, withUser } from '@/lib/auth';
1098
- import { getCortex, isCortexAvailable } from '@/lib/cortex';
1099
- import { ContextEngine } from '@/lib/cortex/retrieval/context-engine';
1100
- import { EntityResolver } from '@/lib/cortex/graph/resolver';
1101
- import { slugify } from '@/lib/cortex/graph/types';
1102
-
1103
- export async function GET(request: NextRequest) {
1104
- const user = getAuthUser(request);
1105
- return withUser(user, async () => {
1106
- if (!isCortexAvailable()) {
1107
- return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
1108
- }
1109
- const cortex = await getCortex();
1110
- if (!cortex) return NextResponse.json({ results: [], context: '' });
1111
-
1112
- const url = new URL(request.url);
1113
- const query = url.searchParams.get('q') || '';
1114
- const limit = parseInt(url.searchParams.get('limit') || '5', 10);
1115
- const workspaceId = url.searchParams.get('workspace_id');
1116
- const maxTokens = parseInt(url.searchParams.get('max_tokens') || '1500', 10);
1117
-
1118
- if (!query || query.length < 3) {
1119
- return NextResponse.json({ results: [], context: '' });
1120
- }
1121
-
1122
- const resolver = new EntityResolver(cortex.graph);
1123
- const requesterId = `person-${slugify(user)}`;
1124
-
1125
- const engine = new ContextEngine({
1126
- store: cortex.store,
1127
- graph: cortex.graph,
1128
- resolver,
1129
- embedding: cortex.embedding,
1130
- requesterId,
1131
- });
1132
-
1133
- const result = await engine.assemble(query, {
1134
- limit,
1135
- workspaceId: workspaceId ? parseInt(workspaceId, 10) : null,
1136
- maxTokens,
1137
- });
1138
-
1139
- return NextResponse.json({
1140
- results: result.results.map(r => ({ ...r, vector: undefined })), // strip vectors
1141
- context: result.context,
1142
- intent: result.intent,
1143
- conflicts: result.conflicts.length,
1144
- timing: result.timing,
1145
- });
1146
- });
1147
- }
1148
- ```
1149
-
1150
- - [ ] **Step 2: Commit**
1151
-
1152
- ```bash
1153
- git add src/app/api/cortex/context/route.ts
1154
- git commit -m "feat(cortex): add context assembly API endpoint"
1155
- ```
1156
-
1157
- ---
1158
-
1159
- ### Task 7: Update RAG hook to use context assembly endpoint
1160
-
1161
- **Files:**
1162
- - Modify: `bin/cortex-hook.js`
1163
-
1164
- - [ ] **Step 1: Read current cortex-hook.js**
1165
-
1166
- Read the file to understand the current flow: query → /api/cortex/search → format results → output.
1167
-
1168
- - [ ] **Step 2: Update to call context assembly endpoint**
1169
-
1170
- Change the URL from `/api/cortex/search/?q=...` to `/api/cortex/context/?q=...`. The new endpoint returns `{ context, results, intent, conflicts, timing }` — the `context` field is already pre-formatted as `<cortex-context>`, so the hook can output it directly instead of doing its own formatting.
1171
-
1172
- Key changes:
1173
- 1. URL: `/api/cortex/search/` → `/api/cortex/context/`
1174
- 2. Response handling: use `parsed.context` directly instead of formatting results manually
1175
- 3. Keep the fallback: if the new endpoint returns empty or fails, fall back to old behavior
1176
-
1177
- ```javascript
1178
- // Replace the response handling section:
1179
- const parsed = JSON.parse(body);
1180
-
1181
- // New: context is pre-formatted by the Context Assembly Engine
1182
- if (parsed.context) {
1183
- const output = JSON.stringify({
1184
- hookSpecificOutput: {
1185
- hookEventName: 'UserPromptSubmit',
1186
- additionalContext: parsed.context,
1187
- },
1188
- });
1189
- process.stdout.write(output);
1190
- process.exit(0);
1191
- }
1192
-
1193
- // Fallback: old-style results formatting (if context endpoint not available)
1194
- const results = parsed.results;
1195
- if (!results || results.length === 0) process.exit(0);
1196
- // ... existing formatting code stays as fallback ...
1197
- ```
1198
-
1199
- - [ ] **Step 3: Commit**
1200
-
1201
- ```bash
1202
- git add bin/cortex-hook.js
1203
- git commit -m "feat(cortex): switch RAG hook to context assembly endpoint"
1204
- ```
1205
-
1206
- ---
1207
-
1208
- ### Task 8: Integrate ContextEngine into CortexInstance
1209
-
1210
- **Files:**
1211
- - Modify: `src/lib/cortex/index.ts`
1212
-
1213
- - [ ] **Step 1: Read current index.ts**
1214
-
1215
- - [ ] **Step 2: Add ContextEngine to CortexInstance**
1216
-
1217
- 1. Import: `import { ContextEngine } from './retrieval/context-engine';` and `import { EntityResolver } from './graph/resolver';`
1218
- 2. Add `contextEngine?: ContextEngine` to `CortexInstance` interface (optional since it depends on graph)
1219
- 3. In `getCortex()`, after graph initialization, create the ContextEngine:
1220
-
1221
- ```typescript
1222
- const resolver = new EntityResolver(graph);
1223
- const contextEngine = new ContextEngine({
1224
- store,
1225
- graph,
1226
- resolver,
1227
- embedding,
1228
- requesterId: 'person-default-user', // default; overridden per-request in API
1229
- });
1230
- ```
1231
-
1232
- 4. Add to instance object: `contextEngine,`
1233
-
1234
- - [ ] **Step 3: Run full cortex test suite**
1235
-
1236
- Run: `npx vitest run tests/lib/cortex/`
1237
-
1238
- - [ ] **Step 4: Commit**
1239
-
1240
- ```bash
1241
- git add src/lib/cortex/index.ts
1242
- git commit -m "feat(cortex): add ContextEngine to CortexInstance"
1243
- ```
1244
-
1245
- ---
1246
-
1247
- ## Summary
1248
-
1249
- | Task | Component | Tests | Status |
1250
- |------|-----------|-------|--------|
1251
- | 1 | Intent detection | 7 | |
1252
- | 2 | Weight computation | 5 | |
1253
- | 3 | Conflict detection | 4 | |
1254
- | 4 | Context formatter | 6 | |
1255
- | 5 | ContextEngine (6-stage pipeline) | 6 | |
1256
- | 6 | Context assembly API endpoint | — | |
1257
- | 7 | RAG hook integration | — | |
1258
- | 8 | CortexInstance integration | regression | |
1259
-
1260
- **Total: 8 tasks, ~28 new tests, 4 chunks**
1261
-
1262
- **Performance budget:** The ContextEngine targets <150ms total latency:
1263
- - Intent detection: <5ms (regex, no LLM)
1264
- - Entity resolution: <5ms (alias lookup)
1265
- - Weight computation: <10ms (graph proximity, cached)
1266
- - Parallel search: <100ms (concurrent vector search with 100ms timeout)
1267
- - Fusion + formatting: <10ms
1268
-
1269
- **Key design decisions:**
1270
- - ContextEngine sits ABOVE CortexSearch — doesn't replace it, wraps it
1271
- - Graph proximity drives weights — but gracefully degrades to fixed weights when graph is empty
1272
- - Deduplication uses text prefix comparison (not cosine between result vectors — that would require N² vector ops)
1273
- - RAG hook uses pre-formatted `context` from the engine — no more client-side formatting
1274
- - Old `/api/cortex/search` endpoint still works — new `/api/cortex/context` endpoint adds the intelligence layer
1
+ # Cortex v2 — Pillar 3: Context Assembly Engine
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:** Replace the flat layer-iteration search with a 6-stage context assembly pipeline that detects intent, resolves entities, computes graph-aware weights, searches multiple scopes in parallel, fuses results with evidence scoring, and surfaces conflicts — all within 150ms.
6
+
7
+ **Architecture:** A new `ContextEngine` class wraps the existing `CortexStore` (for low-level vector search) and `EntityGraph` (for graph distance/proximity). It does NOT replace `CortexSearch` — instead it provides the higher-level retrieval interface that the RAG hook calls. The existing `CortexSearch` remains for backward-compatible simple searches. The RAG hook (`cortex-hook.js`) switches from calling the search API to calling a new context-assembly API endpoint.
8
+
9
+ **Tech Stack:** TypeScript, vitest, LanceDB, SQLite (entity graph)
10
+
11
+ **Spec:** `docs/superpowers/specs/2026-03-14-cortex-v2-design.md` — Pillar 3
12
+
13
+ **Depends on:** Pillar 1 (Entity Graph) + Pillar 2 (Knowledge Unit Evolution) — both completed
14
+
15
+ ---
16
+
17
+ ## File Structure
18
+
19
+ ```
20
+ New files:
21
+ ├── src/lib/cortex/retrieval/intent.ts — Intent detection (regex + keyword)
22
+ ├── src/lib/cortex/retrieval/weight.ts — Weight computation (graph × intent × freshness × authority)
23
+ ├── src/lib/cortex/retrieval/conflict.ts — Conflict detection in results
24
+ ├── src/lib/cortex/retrieval/formatter.ts — Context formatting for RAG injection
25
+ ├── src/lib/cortex/retrieval/context-engine.ts — Main 6-stage ContextEngine class
26
+ ├── src/app/api/cortex/context/route.ts — API endpoint for context assembly
27
+
28
+ Modified files:
29
+ ├── bin/cortex-hook.js — Switch to context-assembly endpoint
30
+
31
+ Test files:
32
+ ├── tests/lib/cortex/retrieval/intent.test.ts
33
+ ├── tests/lib/cortex/retrieval/weight.test.ts
34
+ ├── tests/lib/cortex/retrieval/conflict.test.ts
35
+ ├── tests/lib/cortex/retrieval/formatter.test.ts
36
+ ├── tests/lib/cortex/retrieval/context-engine.test.ts
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Chunk 1: Intent Detection and Weight Computation
42
+
43
+ ### Task 1: Intent detection
44
+
45
+ **Files:**
46
+ - Create: `src/lib/cortex/retrieval/intent.ts`
47
+ - Create: `tests/lib/cortex/retrieval/intent.test.ts`
48
+
49
+ - [ ] **Step 1: Write failing tests**
50
+
51
+ ```typescript
52
+ // tests/lib/cortex/retrieval/intent.test.ts
53
+ import { describe, it, expect } from 'vitest';
54
+ import { detectIntent, INTENTS } from '@/lib/cortex/retrieval/intent';
55
+ import type { IntentResult } from '@/lib/cortex/retrieval/intent';
56
+
57
+ describe('detectIntent', () => {
58
+ it('detects debugging intent', () => {
59
+ const result = detectIntent('why does the auth service throw a timeout error?');
60
+ expect(result.intent).toBe('debugging');
61
+ expect(result.confidence).toBeGreaterThan(0.5);
62
+ });
63
+
64
+ it('detects architecture intent', () => {
65
+ const result = detectIntent('what architecture pattern should we use for the new service?');
66
+ expect(result.intent).toBe('architecture');
67
+ });
68
+
69
+ it('detects how-to intent', () => {
70
+ const result = detectIntent('how do I deploy this service to production?');
71
+ expect(result.intent).toBe('how-to');
72
+ });
73
+
74
+ it('detects security intent', () => {
75
+ const result = detectIntent('is there a vulnerability in our authentication flow?');
76
+ expect(result.intent).toBe('security');
77
+ });
78
+
79
+ it('defaults to general for ambiguous queries', () => {
80
+ const result = detectIntent('tell me about the project');
81
+ expect(result.intent).toBe('general');
82
+ });
83
+
84
+ it('returns bias config for the detected intent', () => {
85
+ const result = detectIntent('fix this bug in the login page');
86
+ expect(result.biases).toBeDefined();
87
+ expect(result.biases.scope_boost).toBeDefined();
88
+ expect(result.biases.type_boost).toBeDefined();
89
+ });
90
+
91
+ it('exports all intent definitions', () => {
92
+ expect(Object.keys(INTENTS)).toContain('debugging');
93
+ expect(Object.keys(INTENTS)).toContain('architecture');
94
+ expect(Object.keys(INTENTS)).toContain('general');
95
+ expect(Object.keys(INTENTS).length).toBe(8);
96
+ });
97
+ });
98
+ ```
99
+
100
+ - [ ] **Step 2: Run tests to verify they fail**
101
+
102
+ Run: `npx vitest run tests/lib/cortex/retrieval/intent.test.ts`
103
+
104
+ - [ ] **Step 3: Implement intent detection**
105
+
106
+ ```typescript
107
+ // src/lib/cortex/retrieval/intent.ts
108
+
109
+ export interface IntentBiases {
110
+ scope_boost: Record<string, number>; // scope level → multiplier
111
+ type_boost: Record<string, number>; // knowledge type → multiplier
112
+ recency_boost: number; // extra recency multiplier
113
+ }
114
+
115
+ export interface IntentResult {
116
+ intent: string;
117
+ confidence: number;
118
+ biases: IntentBiases;
119
+ }
120
+
121
+ interface IntentDef {
122
+ patterns: RegExp[];
123
+ keywords: string[];
124
+ biases: IntentBiases;
125
+ }
126
+
127
+ export const INTENTS: Record<string, IntentDef> = {
128
+ debugging: {
129
+ patterns: [
130
+ /\b(error|bug|fix|crash|fail|broken|throw|exception|timeout|issue)\b/i,
131
+ /\bwhy\s+(does|is|did|do)\b/i,
132
+ /\bnot\s+work/i,
133
+ ],
134
+ keywords: ['error', 'bug', 'fix', 'debug', 'crash', 'fail', 'broken', 'throw', 'exception', 'timeout', 'issue', 'stack trace'],
135
+ biases: {
136
+ scope_boost: { personal: 1.2, team: 1.0, department: 0.9, organization: 0.8 },
137
+ type_boost: { error_fix: 1.3, pattern: 1.0, decision: 0.8, conversation: 0.7 },
138
+ recency_boost: 1.1,
139
+ },
140
+ },
141
+ architecture: {
142
+ patterns: [
143
+ /\b(architect|design|pattern|structure|approach)\b/i,
144
+ /\bshould\s+we\s+(use|adopt|switch|migrate)\b/i,
145
+ ],
146
+ keywords: ['architecture', 'design', 'pattern', 'structure', 'approach', 'decision', 'migration', 'refactor'],
147
+ biases: {
148
+ scope_boost: { personal: 0.9, team: 1.1, department: 1.2, organization: 1.0 },
149
+ type_boost: { decision: 1.5, pattern: 1.2, error_fix: 0.7, conversation: 0.5 },
150
+ recency_boost: 1.0,
151
+ },
152
+ },
153
+ onboarding: {
154
+ patterns: [
155
+ /\b(how\s+does|explain|what\s+is|overview|getting\s+started)\b/i,
156
+ /\bnew\s+to\b/i,
157
+ ],
158
+ keywords: ['explain', 'overview', 'introduction', 'getting started', 'onboarding', 'how does'],
159
+ biases: {
160
+ scope_boost: { personal: 0.7, team: 1.0, department: 1.1, organization: 1.2 },
161
+ type_boost: { pattern: 1.3, decision: 1.2, summary: 1.2, conversation: 0.5 },
162
+ recency_boost: 0.9,
163
+ },
164
+ },
165
+ policy: {
166
+ patterns: [
167
+ /\b(policy|compliance|regulation|standard|rule|requirement)\b/i,
168
+ /\ballowed\s+to\b/i,
169
+ ],
170
+ keywords: ['policy', 'compliance', 'standard', 'regulation', 'rule', 'requirement', 'allowed'],
171
+ biases: {
172
+ scope_boost: { personal: 0.6, team: 0.8, department: 1.0, organization: 1.3 },
173
+ type_boost: { decision: 1.5, preference: 1.2, pattern: 0.8, conversation: 0.3 },
174
+ recency_boost: 1.0,
175
+ },
176
+ },
177
+ 'how-to': {
178
+ patterns: [
179
+ /\bhow\s+(do|can|to|should)\s+I?\b/i,
180
+ /\bsteps?\s+(to|for)\b/i,
181
+ /\bwhat('s| is)\s+the\s+(command|way|process)\b/i,
182
+ ],
183
+ keywords: ['how to', 'steps', 'command', 'run', 'deploy', 'install', 'configure', 'setup'],
184
+ biases: {
185
+ scope_boost: { personal: 1.2, team: 1.0, department: 0.8, organization: 0.7 },
186
+ type_boost: { command: 1.3, pattern: 1.2, error_fix: 1.0, conversation: 0.6 },
187
+ recency_boost: 1.05,
188
+ },
189
+ },
190
+ review: {
191
+ patterns: [
192
+ /\b(review|feedback|improve|quality|best\s+practice)\b/i,
193
+ /\bis\s+this\s+(good|correct|right)\b/i,
194
+ ],
195
+ keywords: ['review', 'feedback', 'quality', 'improve', 'best practice', 'convention'],
196
+ biases: {
197
+ scope_boost: { personal: 0.9, team: 1.2, department: 1.0, organization: 0.8 },
198
+ type_boost: { preference: 1.3, pattern: 1.2, code_pattern: 1.2, decision: 1.0 },
199
+ recency_boost: 1.0,
200
+ },
201
+ },
202
+ security: {
203
+ patterns: [
204
+ /\b(security|vulnerab|exploit|attack|auth|cve|injection|xss)\b/i,
205
+ /\bsecure\b/i,
206
+ ],
207
+ keywords: ['security', 'vulnerability', 'exploit', 'attack', 'authentication', 'authorization', 'cve', 'injection', 'xss', 'csrf'],
208
+ biases: {
209
+ scope_boost: { personal: 0.8, team: 1.0, department: 1.2, organization: 1.0 },
210
+ type_boost: { error_fix: 1.3, decision: 1.2, pattern: 1.0, conversation: 0.5 },
211
+ recency_boost: 1.1,
212
+ },
213
+ },
214
+ general: {
215
+ patterns: [],
216
+ keywords: [],
217
+ biases: {
218
+ scope_boost: { personal: 1.0, team: 1.0, department: 1.0, organization: 1.0 },
219
+ type_boost: {},
220
+ recency_boost: 1.0,
221
+ },
222
+ },
223
+ };
224
+
225
+ /**
226
+ * Detect the intent of a query using regex patterns and keyword scoring.
227
+ * No LLM call — fast and deterministic.
228
+ */
229
+ export function detectIntent(query: string): IntentResult {
230
+ const lower = query.toLowerCase();
231
+ let bestIntent = 'general';
232
+ let bestScore = 0;
233
+
234
+ for (const [name, def] of Object.entries(INTENTS)) {
235
+ if (name === 'general') continue;
236
+
237
+ let score = 0;
238
+
239
+ // Regex pattern matches (high weight)
240
+ for (const pattern of def.patterns) {
241
+ if (pattern.test(query)) score += 2;
242
+ }
243
+
244
+ // Keyword matches (lower weight)
245
+ for (const keyword of def.keywords) {
246
+ if (lower.includes(keyword)) score += 1;
247
+ }
248
+
249
+ if (score > bestScore) {
250
+ bestScore = score;
251
+ bestIntent = name;
252
+ }
253
+ }
254
+
255
+ return {
256
+ intent: bestIntent,
257
+ confidence: bestScore > 0 ? Math.min(1.0, bestScore / 6) : 0.5,
258
+ biases: INTENTS[bestIntent].biases,
259
+ };
260
+ }
261
+ ```
262
+
263
+ - [ ] **Step 4: Run tests to verify they pass**
264
+
265
+ Run: `npx vitest run tests/lib/cortex/retrieval/intent.test.ts`
266
+ Expected: PASS (7 tests)
267
+
268
+ - [ ] **Step 5: Commit**
269
+
270
+ ```bash
271
+ git add src/lib/cortex/retrieval/intent.ts tests/lib/cortex/retrieval/intent.test.ts
272
+ git commit -m "feat(cortex): add intent detection for context assembly"
273
+ ```
274
+
275
+ ---
276
+
277
+ ### Task 2: Weight computation
278
+
279
+ **Files:**
280
+ - Create: `src/lib/cortex/retrieval/weight.ts`
281
+ - Create: `tests/lib/cortex/retrieval/weight.test.ts`
282
+
283
+ - [ ] **Step 1: Write failing tests**
284
+
285
+ ```typescript
286
+ // tests/lib/cortex/retrieval/weight.test.ts
287
+ import { describe, it, expect } from 'vitest';
288
+ import { computeScopeWeight } from '@/lib/cortex/retrieval/weight';
289
+ import type { IntentBiases } from '@/lib/cortex/retrieval/intent';
290
+
291
+ describe('computeScopeWeight', () => {
292
+ const neutralBiases: IntentBiases = {
293
+ scope_boost: { personal: 1.0, team: 1.0, department: 1.0, organization: 1.0 },
294
+ type_boost: {},
295
+ recency_boost: 1.0,
296
+ };
297
+
298
+ it('returns 1.0 for self (distance 0)', () => {
299
+ const weight = computeScopeWeight({
300
+ graphProximity: 1.0, // 1/(1+0)
301
+ scopeLevel: 'personal',
302
+ intentBiases: neutralBiases,
303
+ authorityFactor: 1.0,
304
+ });
305
+ expect(weight).toBeCloseTo(1.0);
306
+ });
307
+
308
+ it('decreases with graph distance', () => {
309
+ const close = computeScopeWeight({
310
+ graphProximity: 0.5, // distance 1
311
+ scopeLevel: 'team',
312
+ intentBiases: neutralBiases,
313
+ authorityFactor: 1.0,
314
+ });
315
+ const far = computeScopeWeight({
316
+ graphProximity: 0.25, // distance 3
317
+ scopeLevel: 'organization',
318
+ intentBiases: neutralBiases,
319
+ authorityFactor: 1.0,
320
+ });
321
+ expect(close).toBeGreaterThan(far);
322
+ });
323
+
324
+ it('is boosted by intent biases', () => {
325
+ const debugBiases: IntentBiases = {
326
+ scope_boost: { personal: 1.2, team: 0.8 },
327
+ type_boost: {},
328
+ recency_boost: 1.0,
329
+ };
330
+ const personal = computeScopeWeight({
331
+ graphProximity: 0.5,
332
+ scopeLevel: 'personal',
333
+ intentBiases: debugBiases,
334
+ authorityFactor: 1.0,
335
+ });
336
+ const team = computeScopeWeight({
337
+ graphProximity: 0.5,
338
+ scopeLevel: 'team',
339
+ intentBiases: debugBiases,
340
+ authorityFactor: 1.0,
341
+ });
342
+ expect(personal).toBeGreaterThan(team);
343
+ });
344
+
345
+ it('is boosted by authority factor', () => {
346
+ const low = computeScopeWeight({
347
+ graphProximity: 0.5,
348
+ scopeLevel: 'team',
349
+ intentBiases: neutralBiases,
350
+ authorityFactor: 1.0,
351
+ });
352
+ const high = computeScopeWeight({
353
+ graphProximity: 0.5,
354
+ scopeLevel: 'team',
355
+ intentBiases: neutralBiases,
356
+ authorityFactor: 1.2,
357
+ });
358
+ expect(high).toBeGreaterThan(low);
359
+ });
360
+
361
+ it('never returns negative', () => {
362
+ const weight = computeScopeWeight({
363
+ graphProximity: 0,
364
+ scopeLevel: 'organization',
365
+ intentBiases: neutralBiases,
366
+ authorityFactor: 1.0,
367
+ });
368
+ expect(weight).toBeGreaterThanOrEqual(0);
369
+ });
370
+ });
371
+ ```
372
+
373
+ - [ ] **Step 2: Run tests to verify they fail**
374
+
375
+ Run: `npx vitest run tests/lib/cortex/retrieval/weight.test.ts`
376
+
377
+ - [ ] **Step 3: Implement weight computation**
378
+
379
+ ```typescript
380
+ // src/lib/cortex/retrieval/weight.ts
381
+ import type { IntentBiases } from './intent';
382
+ import type { ScopeLevel } from '../knowledge/types';
383
+
384
+ export interface ScopeWeightInput {
385
+ graphProximity: number; // 0-1, from EntityGraph.proximity()
386
+ scopeLevel: ScopeLevel | string;
387
+ intentBiases: IntentBiases;
388
+ authorityFactor: number; // 1.0 default, higher for experts/docs
389
+ }
390
+
391
+ /**
392
+ * Compute the retrieval weight for a knowledge scope.
393
+ *
394
+ * weight = graphProximity × intentBias × authorityFactor
395
+ *
396
+ * Per spec: weight(scope) = graph_proximity × intent_bias × freshness_bonus × authority
397
+ * Freshness is applied per-result in the fusion stage, not per-scope.
398
+ */
399
+ export function computeScopeWeight(input: ScopeWeightInput): number {
400
+ const { graphProximity, scopeLevel, intentBiases, authorityFactor } = input;
401
+
402
+ const intentBias = intentBiases.scope_boost[scopeLevel] ?? 1.0;
403
+
404
+ return Math.max(0, graphProximity * intentBias * authorityFactor);
405
+ }
406
+
407
+ /**
408
+ * Compute per-result type boost from intent biases.
409
+ */
410
+ export function computeTypeBoost(knowledgeType: string, intentBiases: IntentBiases): number {
411
+ return intentBiases.type_boost[knowledgeType] ?? 1.0;
412
+ }
413
+
414
+ /**
415
+ * Authority factor for a source based on role and expertise.
416
+ *
417
+ * role_boost: 0.0 member, 0.1 lead, 0.15 senior/principal, 0.2 director+
418
+ * expertise_weight: EXPERT_IN edge weight (0-1)
419
+ * Documents get 1.2 base authority.
420
+ */
421
+ export function computeAuthority(params: {
422
+ role?: string;
423
+ expertiseWeight?: number;
424
+ isDocument?: boolean;
425
+ }): number {
426
+ const { role, expertiseWeight = 0, isDocument = false } = params;
427
+
428
+ if (isDocument) return 1.2;
429
+
430
+ const roleBoosts: Record<string, number> = {
431
+ member: 0.0,
432
+ lead: 0.1,
433
+ senior: 0.15,
434
+ principal: 0.15,
435
+ director: 0.2,
436
+ vp: 0.2,
437
+ cto: 0.2,
438
+ };
439
+
440
+ const roleBoost = roleBoosts[role?.toLowerCase() ?? 'member'] ?? 0.0;
441
+ return Math.max(1.0, roleBoost + expertiseWeight);
442
+ }
443
+ ```
444
+
445
+ - [ ] **Step 4: Run tests to verify they pass**
446
+
447
+ Run: `npx vitest run tests/lib/cortex/retrieval/weight.test.ts`
448
+ Expected: PASS (5 tests)
449
+
450
+ - [ ] **Step 5: Commit**
451
+
452
+ ```bash
453
+ git add src/lib/cortex/retrieval/weight.ts tests/lib/cortex/retrieval/weight.test.ts
454
+ git commit -m "feat(cortex): add scope weight computation for context assembly"
455
+ ```
456
+
457
+ ---
458
+
459
+ ## Chunk 2: Conflict Detection and Context Formatting
460
+
461
+ ### Task 3: Conflict detection
462
+
463
+ **Files:**
464
+ - Create: `src/lib/cortex/retrieval/conflict.ts`
465
+ - Create: `tests/lib/cortex/retrieval/conflict.test.ts`
466
+
467
+ - [ ] **Step 1: Write failing tests**
468
+
469
+ ```typescript
470
+ // tests/lib/cortex/retrieval/conflict.test.ts
471
+ import { describe, it, expect } from 'vitest';
472
+ import { detectConflicts } from '@/lib/cortex/retrieval/conflict';
473
+ import type { ScoredKnowledge } from '@/lib/cortex/knowledge/types';
474
+
475
+ function makeResult(overrides: Partial<ScoredKnowledge> = {}): ScoredKnowledge {
476
+ return {
477
+ id: 'r1', vector: [], text: 'test', type: 'decision', layer: 'personal',
478
+ workspace_id: null, session_id: null, agent_type: 'claude',
479
+ project_path: null, file_refs: [], confidence: 0.8,
480
+ created: new Date().toISOString(), source_timestamp: new Date().toISOString(),
481
+ stale_score: 0, access_count: 0, last_accessed: null, metadata: {},
482
+ relevance_score: 0.9, similarity: 0.9,
483
+ contradiction_refs: [], ...overrides,
484
+ };
485
+ }
486
+
487
+ describe('detectConflicts', () => {
488
+ it('returns no conflicts when no contradiction_refs', () => {
489
+ const results = [makeResult({ id: 'a' }), makeResult({ id: 'b' })];
490
+ const conflicts = detectConflicts(results);
491
+ expect(conflicts).toHaveLength(0);
492
+ });
493
+
494
+ it('detects conflict between two results', () => {
495
+ const results = [
496
+ makeResult({ id: 'a', text: 'use pool size 50', contradiction_refs: ['b'] }),
497
+ makeResult({ id: 'b', text: 'scale horizontally', contradiction_refs: ['a'] }),
498
+ ];
499
+ const conflicts = detectConflicts(results);
500
+ expect(conflicts).toHaveLength(1);
501
+ expect(conflicts[0].unitA.id).toBe('a');
502
+ expect(conflicts[0].unitB.id).toBe('b');
503
+ });
504
+
505
+ it('ignores contradiction_refs pointing to results not in the set', () => {
506
+ const results = [
507
+ makeResult({ id: 'a', contradiction_refs: ['z'] }), // z is not in results
508
+ ];
509
+ const conflicts = detectConflicts(results);
510
+ expect(conflicts).toHaveLength(0);
511
+ });
512
+
513
+ it('deduplicates symmetric conflicts', () => {
514
+ // A contradicts B and B contradicts A should produce one conflict, not two
515
+ const results = [
516
+ makeResult({ id: 'a', contradiction_refs: ['b'] }),
517
+ makeResult({ id: 'b', contradiction_refs: ['a'] }),
518
+ ];
519
+ const conflicts = detectConflicts(results);
520
+ expect(conflicts).toHaveLength(1);
521
+ });
522
+ });
523
+ ```
524
+
525
+ - [ ] **Step 2: Implement conflict detection**
526
+
527
+ ```typescript
528
+ // src/lib/cortex/retrieval/conflict.ts
529
+ import type { ScoredKnowledge } from '../knowledge/types';
530
+
531
+ export interface ConflictPair {
532
+ unitA: ScoredKnowledge;
533
+ unitB: ScoredKnowledge;
534
+ }
535
+
536
+ /**
537
+ * Detect conflicts among search results by checking contradiction_refs.
538
+ * Returns deduplicated conflict pairs (A↔B counted once, not twice).
539
+ */
540
+ export function detectConflicts(results: ScoredKnowledge[]): ConflictPair[] {
541
+ const resultMap = new Map(results.map(r => [r.id, r]));
542
+ const seen = new Set<string>();
543
+ const conflicts: ConflictPair[] = [];
544
+
545
+ for (const result of results) {
546
+ const refs = result.contradiction_refs ?? [];
547
+ for (const refId of refs) {
548
+ const other = resultMap.get(refId);
549
+ if (!other) continue;
550
+
551
+ const key = [result.id, refId].sort().join('|');
552
+ if (seen.has(key)) continue;
553
+ seen.add(key);
554
+
555
+ conflicts.push({ unitA: result, unitB: other });
556
+ }
557
+ }
558
+
559
+ return conflicts;
560
+ }
561
+ ```
562
+
563
+ - [ ] **Step 3: Run tests, commit**
564
+
565
+ Run: `npx vitest run tests/lib/cortex/retrieval/conflict.test.ts`
566
+
567
+ ```bash
568
+ git add src/lib/cortex/retrieval/conflict.ts tests/lib/cortex/retrieval/conflict.test.ts
569
+ git commit -m "feat(cortex): add conflict detection for search results"
570
+ ```
571
+
572
+ ---
573
+
574
+ ### Task 4: Context formatter
575
+
576
+ **Files:**
577
+ - Create: `src/lib/cortex/retrieval/formatter.ts`
578
+ - Create: `tests/lib/cortex/retrieval/formatter.test.ts`
579
+
580
+ - [ ] **Step 1: Write failing tests**
581
+
582
+ ```typescript
583
+ // tests/lib/cortex/retrieval/formatter.test.ts
584
+ import { describe, it, expect } from 'vitest';
585
+ import { formatContext } from '@/lib/cortex/retrieval/formatter';
586
+ import type { ScoredKnowledge } from '@/lib/cortex/knowledge/types';
587
+ import type { ConflictPair } from '@/lib/cortex/retrieval/conflict';
588
+
589
+ function makeResult(overrides: Partial<ScoredKnowledge> = {}): ScoredKnowledge {
590
+ return {
591
+ id: 'r1', vector: [], text: 'test knowledge', type: 'decision', layer: 'personal',
592
+ workspace_id: null, session_id: null, agent_type: 'claude',
593
+ project_path: null, file_refs: [], confidence: 0.8,
594
+ created: '2026-03-15T00:00:00.000Z', source_timestamp: '2026-03-15T00:00:00.000Z',
595
+ stale_score: 0, access_count: 5, last_accessed: null, metadata: {},
596
+ relevance_score: 0.9, similarity: 0.9,
597
+ ...overrides,
598
+ };
599
+ }
600
+
601
+ describe('formatContext', () => {
602
+ it('wraps results in cortex-context tags', () => {
603
+ const output = formatContext([makeResult()], []);
604
+ expect(output).toContain('<cortex-context>');
605
+ expect(output).toContain('</cortex-context>');
606
+ });
607
+
608
+ it('includes type labels and dates', () => {
609
+ const output = formatContext([makeResult({ type: 'error_fix', source_timestamp: '2026-03-10T00:00:00.000Z' })], []);
610
+ expect(output).toContain('[Error Fix]');
611
+ expect(output).toContain('2026-03-10');
612
+ });
613
+
614
+ it('includes source attribution when origin is present', () => {
615
+ const output = formatContext([makeResult({
616
+ origin: { source_type: 'conversation', source_ref: 'sess-1', creator_entity_id: 'person-alice' },
617
+ })], []);
618
+ expect(output).toContain('person-alice');
619
+ });
620
+
621
+ it('includes conflict callout when conflicts exist', () => {
622
+ const a = makeResult({ id: 'a', text: 'use pool size 50' });
623
+ const b = makeResult({ id: 'b', text: 'scale horizontally' });
624
+ const conflicts: ConflictPair[] = [{ unitA: a, unitB: b }];
625
+ const output = formatContext([a, b], conflicts);
626
+ expect(output).toContain('Conflicting');
627
+ });
628
+
629
+ it('respects max token budget', () => {
630
+ const bigResults = Array.from({ length: 20 }, (_, i) =>
631
+ makeResult({ id: `r${i}`, text: 'x'.repeat(500) })
632
+ );
633
+ const output = formatContext(bigResults, [], { maxTokens: 500 });
634
+ // Should not include all 20 results (would be ~2500 tokens)
635
+ expect(output.length).toBeLessThan(3000);
636
+ });
637
+
638
+ it('returns empty string when no results', () => {
639
+ expect(formatContext([], [])).toBe('');
640
+ });
641
+ });
642
+ ```
643
+
644
+ - [ ] **Step 2: Implement context formatter**
645
+
646
+ ```typescript
647
+ // src/lib/cortex/retrieval/formatter.ts
648
+ import type { ScoredKnowledge } from '../knowledge/types';
649
+ import type { ConflictPair } from './conflict';
650
+
651
+ const TYPE_LABELS: Record<string, string> = {
652
+ decision: 'Decision', pattern: 'Pattern', preference: 'Preference',
653
+ error_fix: 'Error Fix', context: 'Context', code_pattern: 'Code',
654
+ command: 'Command', conversation: 'Conversation', summary: 'Summary',
655
+ };
656
+
657
+ export interface FormatOptions {
658
+ maxTokens?: number;
659
+ }
660
+
661
+ /**
662
+ * Format search results + conflicts as annotated <cortex-context> for RAG injection.
663
+ */
664
+ export function formatContext(
665
+ results: ScoredKnowledge[],
666
+ conflicts: ConflictPair[],
667
+ options: FormatOptions = {},
668
+ ): string {
669
+ if (results.length === 0) return '';
670
+
671
+ const maxTokens = options.maxTokens ?? 1500;
672
+ const entries: string[] = [];
673
+ let tokens = 20; // overhead for tags
674
+
675
+ // Format each result with attribution
676
+ for (const unit of results) {
677
+ const label = TYPE_LABELS[unit.type] || unit.type;
678
+ const date = (unit.source_timestamp || '').slice(0, 10);
679
+ const creator = unit.origin?.creator_entity_id ?? '';
680
+ const sourceInfo = creator ? ` (${creator})` : '';
681
+
682
+ let entry = `[${label}] ${date}${sourceInfo}:\n ${unit.text}`;
683
+
684
+ const entryTokens = Math.ceil(entry.length / 4);
685
+ if (tokens + entryTokens > maxTokens) break;
686
+
687
+ entries.push(entry);
688
+ tokens += entryTokens;
689
+ }
690
+
691
+ if (entries.length === 0) return '';
692
+
693
+ // Build conflict section
694
+ let conflictSection = '';
695
+ if (conflicts.length > 0) {
696
+ const conflictLines = conflicts.map(c =>
697
+ ` - "${c.unitA.text.slice(0, 80)}..." vs "${c.unitB.text.slice(0, 80)}..."`
698
+ );
699
+ conflictSection = `\nConflicting perspectives (${conflicts.length}):\n${conflictLines.join('\n')}\n`;
700
+ }
701
+
702
+ const sourceCount = entries.length;
703
+ const header = `Relevant knowledge (${sourceCount} source${sourceCount > 1 ? 's' : ''}${conflicts.length > 0 ? `, ${conflicts.length} conflict${conflicts.length > 1 ? 's' : ''}` : ''}):`;
704
+
705
+ return [
706
+ '<cortex-context>',
707
+ header,
708
+ '',
709
+ ...entries,
710
+ conflictSection,
711
+ '</cortex-context>',
712
+ ].join('\n');
713
+ }
714
+ ```
715
+
716
+ - [ ] **Step 3: Run tests, commit**
717
+
718
+ Run: `npx vitest run tests/lib/cortex/retrieval/formatter.test.ts`
719
+
720
+ ```bash
721
+ git add src/lib/cortex/retrieval/formatter.ts tests/lib/cortex/retrieval/formatter.test.ts
722
+ git commit -m "feat(cortex): add context formatter for RAG injection"
723
+ ```
724
+
725
+ ---
726
+
727
+ ## Chunk 3: Context Assembly Engine
728
+
729
+ ### Task 5: ContextEngine — the 6-stage pipeline
730
+
731
+ **Files:**
732
+ - Create: `src/lib/cortex/retrieval/context-engine.ts`
733
+ - Create: `tests/lib/cortex/retrieval/context-engine.test.ts`
734
+
735
+ - [ ] **Step 1: Write failing tests**
736
+
737
+ ```typescript
738
+ // tests/lib/cortex/retrieval/context-engine.test.ts
739
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
740
+ import { ContextEngine } from '@/lib/cortex/retrieval/context-engine';
741
+
742
+ // Create mocks for dependencies
743
+ const mockStore = {
744
+ search: vi.fn().mockResolvedValue([]),
745
+ };
746
+
747
+ const mockGraph = {
748
+ proximity: vi.fn().mockReturnValue(0.5),
749
+ neighborhood: vi.fn().mockReturnValue([]),
750
+ getEntity: vi.fn().mockReturnValue(null),
751
+ };
752
+
753
+ const mockResolver = {
754
+ extractEntities: vi.fn().mockReturnValue([]),
755
+ };
756
+
757
+ const mockEmbedding = {
758
+ embed: vi.fn().mockResolvedValue([[0.1, 0.2, 0.3]]),
759
+ dimensions: 3,
760
+ name: 'mock',
761
+ init: vi.fn(),
762
+ };
763
+
764
+ describe('ContextEngine', () => {
765
+ let engine: ContextEngine;
766
+
767
+ beforeEach(() => {
768
+ vi.clearAllMocks();
769
+ engine = new ContextEngine({
770
+ store: mockStore as any,
771
+ graph: mockGraph as any,
772
+ resolver: mockResolver as any,
773
+ embedding: mockEmbedding as any,
774
+ requesterId: 'person-alice',
775
+ });
776
+ });
777
+
778
+ it('returns empty context for empty results', async () => {
779
+ const result = await engine.assemble('some query');
780
+ expect(result.results).toHaveLength(0);
781
+ expect(result.context).toBe('');
782
+ });
783
+
784
+ it('calls embedding.embed with the query', async () => {
785
+ await engine.assemble('test query');
786
+ expect(mockEmbedding.embed).toHaveBeenCalledWith(['test query']);
787
+ });
788
+
789
+ it('detects intent from the query', async () => {
790
+ const result = await engine.assemble('why does auth throw an error?');
791
+ expect(result.intent.intent).toBe('debugging');
792
+ });
793
+
794
+ it('extracts entities from the query', async () => {
795
+ mockResolver.extractEntities.mockReturnValue([
796
+ { entity: { id: 'system-auth', type: 'system', name: 'Auth' }, confidence: 0.9, method: 'alias' },
797
+ ]);
798
+ const result = await engine.assemble('fix the auth service');
799
+ expect(mockResolver.extractEntities).toHaveBeenCalledWith('fix the auth service');
800
+ expect(result.entities).toHaveLength(1);
801
+ });
802
+
803
+ it('searches store with embedded query vector', async () => {
804
+ mockStore.search.mockResolvedValue([{
805
+ id: 'k1', text: 'test knowledge', type: 'decision', layer: 'personal',
806
+ confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
807
+ source_timestamp: new Date().toISOString(), evidence_score: 0.7,
808
+ contradiction_refs: [], _distance: 0.2,
809
+ workspace_id: null, session_id: null, agent_type: 'claude',
810
+ project_path: null, file_refs: [], access_count: 0, last_accessed: null,
811
+ metadata: {},
812
+ }]);
813
+
814
+ const result = await engine.assemble('test query');
815
+ expect(result.results.length).toBeGreaterThanOrEqual(1);
816
+ expect(result.context).toContain('<cortex-context>');
817
+ });
818
+
819
+ it('completes within performance budget', async () => {
820
+ const start = Date.now();
821
+ await engine.assemble('test query');
822
+ const elapsed = Date.now() - start;
823
+ expect(elapsed).toBeLessThan(500); // generous for CI, target is 150ms
824
+ });
825
+ });
826
+ ```
827
+
828
+ - [ ] **Step 2: Implement ContextEngine**
829
+
830
+ ```typescript
831
+ // src/lib/cortex/retrieval/context-engine.ts
832
+ import type { CortexStore } from '../store';
833
+ import type { EntityGraph } from '../graph/entity-graph';
834
+ import type { EntityResolver, ResolvedEntity } from '../graph/resolver';
835
+ import type { EmbeddingProvider } from '../embeddings';
836
+ import type { ScoredKnowledge } from '../knowledge/types';
837
+ import { detectIntent } from './intent';
838
+ import type { IntentResult } from './intent';
839
+ import { computeScopeWeight, computeTypeBoost } from './weight';
840
+ import { detectConflicts } from './conflict';
841
+ import type { ConflictPair } from './conflict';
842
+ import { formatContext } from './formatter';
843
+ import { computeRelevanceScore } from './scoring';
844
+
845
+ export interface ContextEngineDeps {
846
+ store: CortexStore;
847
+ graph: EntityGraph;
848
+ resolver: EntityResolver;
849
+ embedding: EmbeddingProvider;
850
+ requesterId: string; // entity ID of the person making the query
851
+ }
852
+
853
+ export interface AssemblyResult {
854
+ results: ScoredKnowledge[];
855
+ conflicts: ConflictPair[];
856
+ context: string; // formatted <cortex-context> string
857
+ intent: IntentResult;
858
+ entities: ResolvedEntity[];
859
+ timing: {
860
+ intentMs: number;
861
+ entityMs: number;
862
+ searchMs: number;
863
+ totalMs: number;
864
+ };
865
+ }
866
+
867
+ interface SearchSource {
868
+ layerKey: string;
869
+ weight: number;
870
+ limit: number;
871
+ }
872
+
873
+ const DEFAULT_LAYERS = ['personal', 'workspace', 'team'] as const;
874
+ const SEARCH_TIMEOUT_MS = 100;
875
+
876
+ export class ContextEngine {
877
+ constructor(private deps: ContextEngineDeps) {}
878
+
879
+ async assemble(query: string, options: { limit?: number; workspaceId?: number | null; maxTokens?: number } = {}): Promise<AssemblyResult> {
880
+ const totalStart = Date.now();
881
+ const { limit = 5, workspaceId = null, maxTokens = 1500 } = options;
882
+
883
+ // Stage 1: Intent Detection
884
+ const intentStart = Date.now();
885
+ const intent = detectIntent(query);
886
+ const intentMs = Date.now() - intentStart;
887
+
888
+ // Stage 2: Entity Resolution
889
+ const entityStart = Date.now();
890
+ const entities = this.deps.resolver.extractEntities(query);
891
+ const entityMs = Date.now() - entityStart;
892
+
893
+ // Embed the query
894
+ const [queryVector] = await this.deps.embedding.embed([query]);
895
+
896
+ // Stage 3: Weight Computation
897
+ const sources = this.computeSourceWeights(intent, workspaceId);
898
+
899
+ // Stage 4: Parallel Multi-Source Search
900
+ const searchStart = Date.now();
901
+ const allResults = await this.parallelSearch(queryVector, sources, limit);
902
+ const searchMs = Date.now() - searchStart;
903
+
904
+ // Stage 5: Fusion + Re-Ranking
905
+ const fused = this.fuseAndRank(allResults, intent, limit);
906
+
907
+ // Stage 6: Conflict Detection + Formatting
908
+ const conflicts = detectConflicts(fused);
909
+ const context = formatContext(fused, conflicts, { maxTokens });
910
+
911
+ return {
912
+ results: fused,
913
+ conflicts,
914
+ context,
915
+ intent,
916
+ entities,
917
+ timing: {
918
+ intentMs,
919
+ entityMs,
920
+ searchMs,
921
+ totalMs: Date.now() - totalStart,
922
+ },
923
+ };
924
+ }
925
+
926
+ private computeSourceWeights(intent: IntentResult, workspaceId: number | null): SearchSource[] {
927
+ const sources: SearchSource[] = [];
928
+
929
+ for (const layer of DEFAULT_LAYERS) {
930
+ const layerKey = layer === 'workspace' && workspaceId
931
+ ? `workspace/${workspaceId}` : layer;
932
+
933
+ // Map v1 layer to scope level for intent bias lookup
934
+ const scopeLevel = layer === 'personal' ? 'personal'
935
+ : layer === 'workspace' ? 'team' : 'organization';
936
+
937
+ // Use graph proximity if available, else fall back to fixed weights
938
+ let graphProximity: number;
939
+ try {
940
+ // For personal, distance is 0; for workspace, 1; for team, 2
941
+ const layerEntity = layer === 'personal' ? this.deps.requesterId
942
+ : layer === 'workspace' ? 'team-default' : 'organization-default';
943
+ graphProximity = this.deps.graph.proximity(this.deps.requesterId, layerEntity);
944
+ } catch {
945
+ // Graph not populated, use fallback
946
+ graphProximity = layer === 'personal' ? 1.0 : layer === 'workspace' ? 0.5 : 0.33;
947
+ }
948
+
949
+ // If graph returns 0 (unreachable/not found), use fallback
950
+ if (graphProximity === 0) {
951
+ graphProximity = layer === 'personal' ? 1.0 : layer === 'workspace' ? 0.5 : 0.33;
952
+ }
953
+
954
+ const weight = computeScopeWeight({
955
+ graphProximity,
956
+ scopeLevel,
957
+ intentBiases: intent.biases,
958
+ authorityFactor: 1.0,
959
+ });
960
+
961
+ sources.push({
962
+ layerKey,
963
+ weight,
964
+ limit: Math.max(3, Math.round(weight * 10)), // proportional slots
965
+ });
966
+ }
967
+
968
+ return sources.sort((a, b) => b.weight - a.weight);
969
+ }
970
+
971
+ private async parallelSearch(
972
+ queryVector: number[],
973
+ sources: SearchSource[],
974
+ limit: number,
975
+ ): Promise<Array<ScoredKnowledge & { sourceWeight: number }>> {
976
+ const searchPromises = sources.map(async (source) => {
977
+ try {
978
+ const results = await Promise.race([
979
+ this.deps.store.search(source.layerKey, queryVector, source.limit),
980
+ new Promise<never>((_, reject) =>
981
+ setTimeout(() => reject(new Error('timeout')), SEARCH_TIMEOUT_MS)
982
+ ),
983
+ ]);
984
+
985
+ return results.map(unit => {
986
+ const similarity = 1 - ((unit as any)._distance ?? 0);
987
+ return {
988
+ ...unit,
989
+ similarity,
990
+ relevance_score: 0, // computed in fusion
991
+ sourceWeight: source.weight,
992
+ } as ScoredKnowledge & { sourceWeight: number };
993
+ });
994
+ } catch {
995
+ return []; // source failed or timed out
996
+ }
997
+ });
998
+
999
+ const settled = await Promise.allSettled(searchPromises);
1000
+ const allResults: Array<ScoredKnowledge & { sourceWeight: number }> = [];
1001
+
1002
+ for (const result of settled) {
1003
+ if (result.status === 'fulfilled') {
1004
+ allResults.push(...result.value);
1005
+ }
1006
+ }
1007
+
1008
+ return allResults;
1009
+ }
1010
+
1011
+ private fuseAndRank(
1012
+ results: Array<ScoredKnowledge & { sourceWeight: number }>,
1013
+ intent: IntentResult,
1014
+ limit: number,
1015
+ ): ScoredKnowledge[] {
1016
+ // Score each result
1017
+ for (const result of results) {
1018
+ const typeBoost = computeTypeBoost(result.type, intent.biases);
1019
+ const recencyBoost = intent.biases.recency_boost;
1020
+
1021
+ result.relevance_score = computeRelevanceScore({
1022
+ similarity: result.similarity,
1023
+ confidence: result.confidence,
1024
+ stale_score: result.stale_score,
1025
+ created: result.created,
1026
+ evidence_score: result.evidence_score,
1027
+ }) * result.sourceWeight * typeBoost * recencyBoost;
1028
+ }
1029
+
1030
+ // Deduplicate: cosine > 0.9 between results (approximate via text similarity)
1031
+ const deduped = this.deduplicateResults(results);
1032
+
1033
+ // Sort and take top K
1034
+ deduped.sort((a, b) => b.relevance_score - a.relevance_score);
1035
+ return deduped.slice(0, limit);
1036
+ }
1037
+
1038
+ private deduplicateResults(results: ScoredKnowledge[]): ScoredKnowledge[] {
1039
+ const kept: ScoredKnowledge[] = [];
1040
+ const seenTexts = new Set<string>();
1041
+
1042
+ // Sort by score first so we keep the better-scored version
1043
+ results.sort((a, b) => b.relevance_score - a.relevance_score);
1044
+
1045
+ for (const result of results) {
1046
+ // Simple text-based dedup: normalize and check prefix overlap
1047
+ const normalized = result.text.slice(0, 200).toLowerCase().trim();
1048
+ if (seenTexts.has(normalized)) continue;
1049
+
1050
+ // Check against existing kept items for high text overlap
1051
+ let isDupe = false;
1052
+ for (const existing of kept) {
1053
+ if (result.id === existing.id) { isDupe = true; break; }
1054
+ // If texts share >80% of content, consider duplicate
1055
+ const existNorm = existing.text.slice(0, 200).toLowerCase().trim();
1056
+ if (normalized === existNorm) { isDupe = true; break; }
1057
+ }
1058
+
1059
+ if (!isDupe) {
1060
+ seenTexts.add(normalized);
1061
+ kept.push(result);
1062
+ }
1063
+ }
1064
+
1065
+ return kept;
1066
+ }
1067
+ }
1068
+ ```
1069
+
1070
+ - [ ] **Step 3: Run tests to verify they pass**
1071
+
1072
+ Run: `npx vitest run tests/lib/cortex/retrieval/context-engine.test.ts`
1073
+ Expected: PASS (6 tests)
1074
+
1075
+ - [ ] **Step 4: Commit**
1076
+
1077
+ ```bash
1078
+ git add src/lib/cortex/retrieval/context-engine.ts tests/lib/cortex/retrieval/context-engine.test.ts
1079
+ git commit -m "feat(cortex): add ContextEngine with 6-stage retrieval pipeline"
1080
+ ```
1081
+
1082
+ ---
1083
+
1084
+ ## Chunk 4: API Endpoint and Hook Integration
1085
+
1086
+ ### Task 6: Context assembly API endpoint
1087
+
1088
+ **Files:**
1089
+ - Create: `src/app/api/cortex/context/route.ts`
1090
+
1091
+ - [ ] **Step 1: Create the endpoint**
1092
+
1093
+ ```typescript
1094
+ // src/app/api/cortex/context/route.ts
1095
+ import { NextResponse } from 'next/server';
1096
+ import type { NextRequest } from 'next/server';
1097
+ import { getAuthUser, withUser } from '@/lib/auth';
1098
+ import { getCortex, isCortexAvailable } from '@/lib/cortex';
1099
+ import { ContextEngine } from '@/lib/cortex/retrieval/context-engine';
1100
+ import { EntityResolver } from '@/lib/cortex/graph/resolver';
1101
+ import { slugify } from '@/lib/cortex/graph/types';
1102
+
1103
+ export async function GET(request: NextRequest) {
1104
+ const user = getAuthUser(request);
1105
+ return withUser(user, async () => {
1106
+ if (!isCortexAvailable()) {
1107
+ return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
1108
+ }
1109
+ const cortex = await getCortex();
1110
+ if (!cortex) return NextResponse.json({ results: [], context: '' });
1111
+
1112
+ const url = new URL(request.url);
1113
+ const query = url.searchParams.get('q') || '';
1114
+ const limit = parseInt(url.searchParams.get('limit') || '5', 10);
1115
+ const workspaceId = url.searchParams.get('workspace_id');
1116
+ const maxTokens = parseInt(url.searchParams.get('max_tokens') || '1500', 10);
1117
+
1118
+ if (!query || query.length < 3) {
1119
+ return NextResponse.json({ results: [], context: '' });
1120
+ }
1121
+
1122
+ const resolver = new EntityResolver(cortex.graph);
1123
+ const requesterId = `person-${slugify(user)}`;
1124
+
1125
+ const engine = new ContextEngine({
1126
+ store: cortex.store,
1127
+ graph: cortex.graph,
1128
+ resolver,
1129
+ embedding: cortex.embedding,
1130
+ requesterId,
1131
+ });
1132
+
1133
+ const result = await engine.assemble(query, {
1134
+ limit,
1135
+ workspaceId: workspaceId ? parseInt(workspaceId, 10) : null,
1136
+ maxTokens,
1137
+ });
1138
+
1139
+ return NextResponse.json({
1140
+ results: result.results.map(r => ({ ...r, vector: undefined })), // strip vectors
1141
+ context: result.context,
1142
+ intent: result.intent,
1143
+ conflicts: result.conflicts.length,
1144
+ timing: result.timing,
1145
+ });
1146
+ });
1147
+ }
1148
+ ```
1149
+
1150
+ - [ ] **Step 2: Commit**
1151
+
1152
+ ```bash
1153
+ git add src/app/api/cortex/context/route.ts
1154
+ git commit -m "feat(cortex): add context assembly API endpoint"
1155
+ ```
1156
+
1157
+ ---
1158
+
1159
+ ### Task 7: Update RAG hook to use context assembly endpoint
1160
+
1161
+ **Files:**
1162
+ - Modify: `bin/cortex-hook.js`
1163
+
1164
+ - [ ] **Step 1: Read current cortex-hook.js**
1165
+
1166
+ Read the file to understand the current flow: query → /api/cortex/search → format results → output.
1167
+
1168
+ - [ ] **Step 2: Update to call context assembly endpoint**
1169
+
1170
+ Change the URL from `/api/cortex/search/?q=...` to `/api/cortex/context/?q=...`. The new endpoint returns `{ context, results, intent, conflicts, timing }` — the `context` field is already pre-formatted as `<cortex-context>`, so the hook can output it directly instead of doing its own formatting.
1171
+
1172
+ Key changes:
1173
+ 1. URL: `/api/cortex/search/` → `/api/cortex/context/`
1174
+ 2. Response handling: use `parsed.context` directly instead of formatting results manually
1175
+ 3. Keep the fallback: if the new endpoint returns empty or fails, fall back to old behavior
1176
+
1177
+ ```javascript
1178
+ // Replace the response handling section:
1179
+ const parsed = JSON.parse(body);
1180
+
1181
+ // New: context is pre-formatted by the Context Assembly Engine
1182
+ if (parsed.context) {
1183
+ const output = JSON.stringify({
1184
+ hookSpecificOutput: {
1185
+ hookEventName: 'UserPromptSubmit',
1186
+ additionalContext: parsed.context,
1187
+ },
1188
+ });
1189
+ process.stdout.write(output);
1190
+ process.exit(0);
1191
+ }
1192
+
1193
+ // Fallback: old-style results formatting (if context endpoint not available)
1194
+ const results = parsed.results;
1195
+ if (!results || results.length === 0) process.exit(0);
1196
+ // ... existing formatting code stays as fallback ...
1197
+ ```
1198
+
1199
+ - [ ] **Step 3: Commit**
1200
+
1201
+ ```bash
1202
+ git add bin/cortex-hook.js
1203
+ git commit -m "feat(cortex): switch RAG hook to context assembly endpoint"
1204
+ ```
1205
+
1206
+ ---
1207
+
1208
+ ### Task 8: Integrate ContextEngine into CortexInstance
1209
+
1210
+ **Files:**
1211
+ - Modify: `src/lib/cortex/index.ts`
1212
+
1213
+ - [ ] **Step 1: Read current index.ts**
1214
+
1215
+ - [ ] **Step 2: Add ContextEngine to CortexInstance**
1216
+
1217
+ 1. Import: `import { ContextEngine } from './retrieval/context-engine';` and `import { EntityResolver } from './graph/resolver';`
1218
+ 2. Add `contextEngine?: ContextEngine` to `CortexInstance` interface (optional since it depends on graph)
1219
+ 3. In `getCortex()`, after graph initialization, create the ContextEngine:
1220
+
1221
+ ```typescript
1222
+ const resolver = new EntityResolver(graph);
1223
+ const contextEngine = new ContextEngine({
1224
+ store,
1225
+ graph,
1226
+ resolver,
1227
+ embedding,
1228
+ requesterId: 'person-default-user', // default; overridden per-request in API
1229
+ });
1230
+ ```
1231
+
1232
+ 4. Add to instance object: `contextEngine,`
1233
+
1234
+ - [ ] **Step 3: Run full cortex test suite**
1235
+
1236
+ Run: `npx vitest run tests/lib/cortex/`
1237
+
1238
+ - [ ] **Step 4: Commit**
1239
+
1240
+ ```bash
1241
+ git add src/lib/cortex/index.ts
1242
+ git commit -m "feat(cortex): add ContextEngine to CortexInstance"
1243
+ ```
1244
+
1245
+ ---
1246
+
1247
+ ## Summary
1248
+
1249
+ | Task | Component | Tests | Status |
1250
+ |------|-----------|-------|--------|
1251
+ | 1 | Intent detection | 7 | |
1252
+ | 2 | Weight computation | 5 | |
1253
+ | 3 | Conflict detection | 4 | |
1254
+ | 4 | Context formatter | 6 | |
1255
+ | 5 | ContextEngine (6-stage pipeline) | 6 | |
1256
+ | 6 | Context assembly API endpoint | — | |
1257
+ | 7 | RAG hook integration | — | |
1258
+ | 8 | CortexInstance integration | regression | |
1259
+
1260
+ **Total: 8 tasks, ~28 new tests, 4 chunks**
1261
+
1262
+ **Performance budget:** The ContextEngine targets <150ms total latency:
1263
+ - Intent detection: <5ms (regex, no LLM)
1264
+ - Entity resolution: <5ms (alias lookup)
1265
+ - Weight computation: <10ms (graph proximity, cached)
1266
+ - Parallel search: <100ms (concurrent vector search with 100ms timeout)
1267
+ - Fusion + formatting: <10ms
1268
+
1269
+ **Key design decisions:**
1270
+ - ContextEngine sits ABOVE CortexSearch — doesn't replace it, wraps it
1271
+ - Graph proximity drives weights — but gracefully degrades to fixed weights when graph is empty
1272
+ - Deduplication uses text prefix comparison (not cosine between result vectors — that would require N² vector ops)
1273
+ - RAG hook uses pre-formatted `context` from the engine — no more client-side formatting
1274
+ - Old `/api/cortex/search` endpoint still works — new `/api/cortex/context` endpoint adds the intelligence layer