@jlongo78/agent-spaces 0.7.5 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/.next/standalone/.claude/settings.local.json +55 -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 +2 -1
  5. package/.next/standalone/.next/build-manifest.json +5 -5
  6. package/.next/standalone/.next/prerender-manifest.json +27 -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/build-manifest.json +3 -3
  10. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/(desktop)/admin/users/page/build-manifest.json +3 -3
  12. package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/(desktop)/analytics/page/build-manifest.json +3 -3
  14. package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/(desktop)/cortex/page/build-manifest.json +3 -3
  16. package/.next/standalone/.next/server/app/(desktop)/cortex/page/react-loadable-manifest.json +3 -3
  17. package/.next/standalone/.next/server/app/(desktop)/cortex/page.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/(desktop)/cortex/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/(desktop)/network/page/build-manifest.json +3 -3
  20. package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
  21. package/.next/standalone/.next/server/app/(desktop)/page/build-manifest.json +3 -3
  22. package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/(desktop)/projects/page/build-manifest.json +3 -3
  24. package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page/build-manifest.json +3 -3
  26. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
  27. package/.next/standalone/.next/server/app/(desktop)/sessions/page/build-manifest.json +3 -3
  28. package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
  29. package/.next/standalone/.next/server/app/(desktop)/settings/page/build-manifest.json +3 -3
  30. package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
  31. package/.next/standalone/.next/server/app/(desktop)/terminal/page/build-manifest.json +3 -3
  32. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
  34. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page/build-manifest.json +3 -3
  35. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
  37. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page/build-manifest.json +3 -3
  38. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/(desktop)/workspaces/page/build-manifest.json +3 -3
  41. package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
  42. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
  43. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  44. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  45. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  46. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  47. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  48. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  49. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  50. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
  51. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  53. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  54. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  55. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  56. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  57. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  58. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  59. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  60. package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
  61. package/.next/standalone/.next/server/app/admin/analytics.rsc +7 -6
  62. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +2 -2
  63. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
  64. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  65. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  66. package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +7 -6
  67. package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
  68. package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +2 -2
  69. package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
  70. package/.next/standalone/.next/server/app/admin/users.html +1 -1
  71. package/.next/standalone/.next/server/app/admin/users.rsc +2 -2
  72. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +1 -1
  73. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
  74. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  75. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  76. package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +2 -2
  77. package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
  78. package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +2 -2
  79. package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
  80. package/.next/standalone/.next/server/app/analytics.html +1 -1
  81. package/.next/standalone/.next/server/app/analytics.rsc +3 -3
  82. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +2 -2
  83. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
  84. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  85. package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +3 -3
  86. package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
  87. package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +2 -2
  88. package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  89. package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
  91. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/api/cortex/context/route.js.nft.json +1 -1
  93. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.nft.json +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.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js.nft.json +1 -1
  100. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js.nft.json +1 -1
  101. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js.nft.json +1 -1
  102. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js.nft.json +1 -1
  105. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js.nft.json +1 -1
  107. package/.next/standalone/.next/server/app/api/cortex/import/route.js.nft.json +1 -1
  108. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js.nft.json +1 -1
  109. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js.nft.json +1 -1
  110. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js.nft.json +1 -1
  111. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js.nft.json +1 -1
  113. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js.nft.json +1 -1
  115. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js.nft.json +1 -1
  116. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.nft.json +1 -1
  117. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.nft.json +1 -1
  118. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js.nft.json +1 -1
  119. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/api/cortex/search/route.js.nft.json +1 -1
  121. package/.next/standalone/.next/server/app/api/cortex/settings/route.js.nft.json +1 -1
  122. package/.next/standalone/.next/server/app/api/cortex/status/route.js.nft.json +1 -1
  123. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/app/api/cortex/usage/route.js.nft.json +1 -1
  125. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js.nft.json +1 -1
  126. package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
  127. package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
  128. package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
  129. package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
  130. package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
  131. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
  132. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
  133. package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
  134. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
  135. package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
  136. package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
  137. package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
  138. package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  139. package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  140. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
  141. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
  142. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  143. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
  145. package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
  147. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
  149. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
  151. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
  152. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
  153. package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  154. package/.next/standalone/.next/server/app/cortex.html +1 -1
  155. package/.next/standalone/.next/server/app/cortex.rsc +3 -3
  156. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex/__PAGE__.segment.rsc +2 -2
  157. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex.segment.rsc +1 -1
  158. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  159. package/.next/standalone/.next/server/app/cortex.segments/_full.segment.rsc +3 -3
  160. package/.next/standalone/.next/server/app/cortex.segments/_head.segment.rsc +1 -1
  161. package/.next/standalone/.next/server/app/cortex.segments/_index.segment.rsc +2 -2
  162. package/.next/standalone/.next/server/app/cortex.segments/_tree.segment.rsc +2 -2
  163. package/.next/standalone/.next/server/app/login/page/build-manifest.json +3 -3
  164. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  165. package/.next/standalone/.next/server/app/login.html +1 -1
  166. package/.next/standalone/.next/server/app/login.rsc +2 -2
  167. package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
  168. package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
  169. package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +2 -2
  170. package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  171. package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  172. package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
  173. package/.next/standalone/.next/server/app/m/page/build-manifest.json +3 -3
  174. package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
  175. package/.next/standalone/.next/server/app/m/projects/page/build-manifest.json +3 -3
  176. package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
  177. package/.next/standalone/.next/server/app/m/projects.html +1 -1
  178. package/.next/standalone/.next/server/app/m/projects.rsc +2 -2
  179. package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +2 -2
  180. package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
  181. package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +2 -2
  182. package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
  183. package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +1 -1
  184. package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
  185. package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +1 -1
  186. package/.next/standalone/.next/server/app/m/sessions/[id]/page/build-manifest.json +3 -3
  187. package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
  188. package/.next/standalone/.next/server/app/m/sessions/page/build-manifest.json +3 -3
  189. package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
  190. package/.next/standalone/.next/server/app/m/sessions.html +1 -1
  191. package/.next/standalone/.next/server/app/m/sessions.rsc +2 -2
  192. package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +2 -2
  193. package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
  194. package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +2 -2
  195. package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
  196. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +1 -1
  197. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
  198. package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +1 -1
  199. package/.next/standalone/.next/server/app/m/settings/page/build-manifest.json +3 -3
  200. package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
  201. package/.next/standalone/.next/server/app/m/settings.html +1 -1
  202. package/.next/standalone/.next/server/app/m/settings.rsc +2 -2
  203. package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +2 -2
  204. package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
  205. package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +2 -2
  206. package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
  207. package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +1 -1
  208. package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
  209. package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +1 -1
  210. package/.next/standalone/.next/server/app/m/terminal/page/build-manifest.json +3 -3
  211. package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
  212. package/.next/standalone/.next/server/app/m/terminal.html +1 -1
  213. package/.next/standalone/.next/server/app/m/terminal.rsc +2 -2
  214. package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +2 -2
  215. package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
  216. package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +2 -2
  217. package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
  218. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +1 -1
  219. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
  220. package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +1 -1
  221. package/.next/standalone/.next/server/app/m.html +1 -1
  222. package/.next/standalone/.next/server/app/m.rsc +2 -2
  223. package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +2 -2
  224. package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
  225. package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +2 -2
  226. package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
  227. package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +1 -1
  228. package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +1 -1
  229. package/.next/standalone/.next/server/app/network.html +1 -1
  230. package/.next/standalone/.next/server/app/network.rsc +2 -2
  231. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +1 -1
  232. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
  233. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  234. package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +2 -2
  235. package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
  236. package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +2 -2
  237. package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
  238. package/.next/standalone/.next/server/app/projects.html +1 -1
  239. package/.next/standalone/.next/server/app/projects.rsc +2 -2
  240. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +1 -1
  241. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
  242. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  243. package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +2 -2
  244. package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  245. package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +2 -2
  246. package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  247. package/.next/standalone/.next/server/app/sessions.html +1 -1
  248. package/.next/standalone/.next/server/app/sessions.rsc +2 -2
  249. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +1 -1
  250. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
  251. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  252. package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +2 -2
  253. package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
  254. package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +2 -2
  255. package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
  256. package/.next/standalone/.next/server/app/settings.html +1 -1
  257. package/.next/standalone/.next/server/app/settings.rsc +2 -2
  258. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +1 -1
  259. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
  260. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  261. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +2 -2
  262. package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  263. package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  264. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  265. package/.next/standalone/.next/server/app/terminal.html +1 -1
  266. package/.next/standalone/.next/server/app/terminal.rsc +3 -3
  267. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
  268. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
  269. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  270. package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +3 -3
  271. package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
  272. package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +2 -2
  273. package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
  274. package/.next/standalone/.next/server/app/vr/page/app-paths-manifest.json +3 -0
  275. package/.next/standalone/.next/server/app/vr/page/build-manifest.json +18 -0
  276. package/.next/standalone/.next/server/app/vr/page/next-font-manifest.json +11 -0
  277. package/.next/standalone/.next/server/app/vr/page/react-loadable-manifest.json +11 -0
  278. package/.next/standalone/.next/server/app/vr/page/server-reference-manifest.json +4 -0
  279. package/.next/standalone/.next/server/app/vr/page.js +17 -0
  280. package/.next/standalone/.next/server/app/vr/page.js.map +5 -0
  281. package/.next/standalone/.next/server/app/vr/page.js.nft.json +1 -0
  282. package/.next/standalone/.next/server/app/vr/page_client-reference-manifest.js +2 -0
  283. package/.next/standalone/.next/server/app/vr.html +1 -0
  284. package/.next/standalone/.next/server/app/vr.meta +15 -0
  285. package/.next/standalone/.next/server/app/vr.rsc +21 -0
  286. package/.next/standalone/.next/server/app/vr.segments/_full.segment.rsc +21 -0
  287. package/.next/standalone/.next/server/app/vr.segments/_head.segment.rsc +6 -0
  288. package/.next/standalone/.next/server/app/vr.segments/_index.segment.rsc +6 -0
  289. package/.next/standalone/.next/server/app/vr.segments/_tree.segment.rsc +4 -0
  290. package/.next/standalone/.next/server/app/vr.segments/vr/__PAGE__.segment.rsc +9 -0
  291. package/.next/standalone/.next/server/app/vr.segments/vr.segment.rsc +4 -0
  292. package/.next/standalone/.next/server/app/workspaces.html +1 -1
  293. package/.next/standalone/.next/server/app/workspaces.rsc +2 -2
  294. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +1 -1
  295. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
  296. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  297. package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +2 -2
  298. package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
  299. package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +2 -2
  300. package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
  301. package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
  302. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0041efe4._.js +2 -2
  303. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00bf0ace._.js +2 -2
  304. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08a68343._.js +1 -1
  305. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0add852f._.js +1 -1
  306. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0c113ed0._.js +1 -1
  307. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e1a27e0._.js +1 -1
  308. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e71d908._.js +3 -3
  309. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e9142f3._.js +2 -2
  310. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10e47926._.js +2 -2
  311. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1194f2c1._.js +1 -1
  312. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1665dc78._.js +2 -2
  313. package/.next/standalone/.next/server/chunks/[root-of-the-server]__175cbabf._.js +2 -2
  314. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19c2d094._.js +1 -1
  315. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adae357._.js +2 -2
  316. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d359752._.js +2 -2
  317. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1e8fabeb._.js +3 -3
  318. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1f8deca0._.js +8 -8
  319. package/.next/standalone/.next/server/chunks/[root-of-the-server]__253fdda1._.js +2 -2
  320. package/.next/standalone/.next/server/chunks/[root-of-the-server]__28e6434f._.js +2 -2
  321. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2a386564._.js +3 -3
  322. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2acbd703._.js +1 -1
  323. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2acefabb._.js +1 -1
  324. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2c20fb38._.js +2 -2
  325. package/.next/standalone/.next/server/chunks/[root-of-the-server]__309132cd._.js +1 -1
  326. package/.next/standalone/.next/server/chunks/[root-of-the-server]__33fec964._.js +3 -3
  327. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3786d8ae._.js +2 -2
  328. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3ae92407._.js +2 -2
  329. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3beda9fe._.js +2 -2
  330. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3e3f25a1._.js +1 -1
  331. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4619e9bd._.js +1 -1
  332. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4a051043._.js +2 -2
  333. package/.next/standalone/.next/server/chunks/[root-of-the-server]__50208a5f._.js +1 -1
  334. package/.next/standalone/.next/server/chunks/[root-of-the-server]__508002e4._.js +2 -2
  335. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5086c373._.js +2 -2
  336. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5913e097._.js +2 -2
  337. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5b5f68d2._.js +2 -2
  338. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c1f2459._.js +2 -2
  339. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5ec8c977._.js +2 -2
  340. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5f8c694a._.js +1 -1
  341. package/.next/standalone/.next/server/chunks/[root-of-the-server]__63cebc6c._.js +2 -2
  342. package/.next/standalone/.next/server/chunks/[root-of-the-server]__64d30d4d._.js +2 -2
  343. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c54fc2e._.js +2 -2
  344. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6dc1fb7e._.js +2 -2
  345. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6e568102._.js +2 -2
  346. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6faa04c0._.js +2 -2
  347. package/.next/standalone/.next/server/chunks/[root-of-the-server]__727d05f1._.js +1 -1
  348. package/.next/standalone/.next/server/chunks/[root-of-the-server]__74a34dc3._.js +2 -2
  349. package/.next/standalone/.next/server/chunks/[root-of-the-server]__75d12b32._.js +1 -1
  350. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e7250a4._.js +2 -2
  351. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8309e0a4._.js +2 -2
  352. package/.next/standalone/.next/server/chunks/[root-of-the-server]__86cc0e2b._.js +6 -6
  353. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8915603e._.js +1 -1
  354. package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c2565a._.js +2 -2
  355. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8d178ad9._.js +2 -2
  356. package/.next/standalone/.next/server/chunks/[root-of-the-server]__93ee06f3._.js +3 -3
  357. package/.next/standalone/.next/server/chunks/[root-of-the-server]__9e4c154a._.js +2 -2
  358. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a1fbc199._.js +1 -1
  359. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9d2e1d3._.js +2 -2
  360. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ae53d343._.js +2 -2
  361. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b3a04cef._.js +2 -2
  362. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b4270b77._.js +1 -1
  363. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b6b6ce60._.js +1 -1
  364. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b9545dd9._.js +1 -1
  365. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c200e21a._.js +1 -1
  366. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c3c74ca4._.js +1 -1
  367. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c88b63f7._.js +2 -2
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cba5f007._.js +1 -1
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cbf4ceb0._.js +2 -2
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cefdba2f._.js +2 -2
  371. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cf9e82bb._.js +2 -2
  372. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d15515e3._.js +1 -1
  373. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d2897392._.js +2 -2
  374. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d3b2d856._.js +2 -2
  375. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d73273ca._.js +2 -2
  376. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8417eb6._.js +2 -2
  377. package/.next/standalone/.next/server/chunks/[root-of-the-server]__db4726bc._.js +1 -1
  378. package/.next/standalone/.next/server/chunks/[root-of-the-server]__dc2a55de._.js +2 -2
  379. package/.next/standalone/.next/server/chunks/[root-of-the-server]__dc6e2e5f._.js +1 -1
  380. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e0d4690b._.js +3 -3
  381. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e3ecfd17._.js +3 -3
  382. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e678dd53._.js +1 -1
  383. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e9223f55._.js +2 -2
  384. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ea630076._.js +3 -3
  385. package/.next/standalone/.next/server/chunks/[root-of-the-server]__eb8acb65._.js +1 -1
  386. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f26ca49d._.js +1 -1
  387. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f33e1101._.js +2 -2
  388. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f3a4c668._.js +1 -1
  389. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f515f865._.js +2 -2
  390. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fceb5d60._.js +2 -2
  391. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fed41403._.js +2 -2
  392. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ff2e98c2._.js +2 -2
  393. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_339169c8.js +1 -1
  394. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_97dac613.js +1 -1
  395. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0d8d81ca._.js +1 -1
  396. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1425c64f._.js +1 -1
  397. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1d2ce8f1._.js +1 -1
  398. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__31137509._.js +1 -1
  399. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__3633a587._.js +1 -1
  400. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__3c79441b._.js +1 -1
  401. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__4ca0f26b._.js +1 -1
  402. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__5b90d3ad._.js +3 -0
  403. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__62a0b363._.js +1 -1
  404. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
  405. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__68205a46._.js +1 -1
  406. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__69fd2efa._.js +1 -1
  407. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__85dcf0f7._.js +1 -1
  408. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__8c53a5da._.js +1 -1
  409. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__aecb1873._.js +1 -1
  410. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__b02cd143._.js +1 -1
  411. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__b9bcde11._.js +3 -0
  412. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__cac90169._.js +1 -1
  413. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__d25de2f0._.js +1 -1
  414. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__e2f86be8._.js +1 -1
  415. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__ee626b5b._.js +1 -1
  416. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__f39a9e98._.js +1 -1
  417. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__f3c566cd._.js +1 -1
  418. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__f76aa221._.js +1 -1
  419. package/.next/standalone/.next/server/chunks/ssr/_149d7fd4._.js +1 -1
  420. package/.next/standalone/.next/server/chunks/ssr/_2e0dd6a7._.js +1 -1
  421. package/.next/standalone/.next/server/chunks/ssr/_3cd2355c._.js +1 -1
  422. package/.next/standalone/.next/server/chunks/ssr/_3d206597._.js +4 -0
  423. package/.next/standalone/.next/server/chunks/ssr/_47cc9af0._.js +1 -1
  424. package/.next/standalone/.next/server/chunks/ssr/_5cf334fd._.js +3 -0
  425. package/.next/standalone/.next/server/chunks/ssr/_7082788b._.js +1 -1
  426. package/.next/standalone/.next/server/chunks/ssr/_7154d8ae._.js +1 -1
  427. package/.next/standalone/.next/server/chunks/ssr/_75bb1b9a._.js +1 -1
  428. package/.next/standalone/.next/server/chunks/ssr/{_aeeff784._.js → _81abf587._.js} +2 -2
  429. package/.next/standalone/.next/server/chunks/ssr/_8acf81e2._.js +1 -1
  430. package/.next/standalone/.next/server/chunks/ssr/_8c36feb8._.js +1 -1
  431. package/.next/standalone/.next/server/chunks/ssr/_91e9bb86._.js +1 -1
  432. package/.next/standalone/.next/server/chunks/ssr/_ac4c1838._.js +1 -1
  433. package/.next/standalone/.next/server/chunks/ssr/_ad8515fc._.js +1 -1
  434. package/.next/standalone/.next/server/chunks/ssr/_b1f49e81._.js +1 -1
  435. package/.next/standalone/.next/server/chunks/ssr/_c0fe7614._.js +1 -1
  436. package/.next/standalone/.next/server/chunks/ssr/_d4825f5a._.js +1 -1
  437. package/.next/standalone/.next/server/chunks/ssr/_da10a9f4._.js +1 -1
  438. package/.next/standalone/.next/server/chunks/ssr/_db0abd0a._.js +3 -0
  439. package/.next/standalone/.next/server/chunks/ssr/_dee5d4a1._.js +1 -1
  440. package/.next/standalone/.next/server/chunks/ssr/_ef482c0c._.js +1 -1
  441. package/.next/standalone/.next/server/chunks/ssr/_efe43d2f._.js +1 -1
  442. package/.next/standalone/.next/server/chunks/ssr/_f4a4e116._.js +1 -1
  443. package/.next/standalone/.next/server/chunks/ssr/_f4d525d2._.js +1 -1
  444. package/.next/standalone/.next/server/chunks/ssr/_f4e57187._.js +3 -0
  445. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_vr_page_actions_3fb70d92.js +3 -0
  446. package/.next/standalone/.next/server/chunks/ssr/node_modules_32f9d62f._.js +1 -1
  447. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_02f39477.js +1 -1
  448. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_eedfc1fd._.js +1 -1
  449. package/.next/standalone/.next/server/chunks/ssr/src_40fa36ce._.js +7 -0
  450. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_cortex_page_tsx_0f33d8b3._.js +3 -0
  451. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__32a0045c._.js +1 -1
  452. package/.next/standalone/.next/server/edge/chunks/_d73df637._.js +1 -1
  453. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  454. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  455. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  456. package/.next/standalone/.next/server/next-font-manifest.json +4 -0
  457. package/.next/standalone/.next/server/pages/404.html +1 -1
  458. package/.next/standalone/.next/server/pages/500.html +2 -2
  459. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  460. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  461. package/.next/standalone/.next/static/chunks/045c83caa4d15373.js +1 -0
  462. package/.next/standalone/.next/static/chunks/07ea09e6024a523b.js +1 -0
  463. package/.next/standalone/.next/static/chunks/232d8aae4fefab70.js +1 -0
  464. package/.next/standalone/.next/static/chunks/2ad22562bb37ecad.js +1011 -0
  465. package/.next/standalone/.next/static/chunks/396eac60f496f178.js +1 -0
  466. package/.next/standalone/.next/static/chunks/{a4e5c700421eaa46.js → 412140a02893327a.js} +1 -1
  467. package/.next/standalone/.next/static/chunks/481cc11ae80b08b1.js +1 -0
  468. package/.next/standalone/.next/static/chunks/5325351ef49cb65f.js +1 -0
  469. package/.next/standalone/.next/static/chunks/559735e598ca3cbb.js +1 -0
  470. package/.next/standalone/.next/static/chunks/59c63d5af5cf3daf.js +1 -0
  471. package/.next/standalone/.next/static/chunks/5d5d7b0095dd52ae.js +1 -0
  472. package/.next/standalone/.next/static/chunks/6ae575967d091df4.js +1 -0
  473. package/.next/standalone/.next/static/chunks/7a7c0d9d875332a3.js +1 -0
  474. package/.next/standalone/.next/static/chunks/7f8455bb855a6c84.js +1 -0
  475. package/.next/standalone/.next/static/chunks/898f380eba90427a.js +1 -0
  476. package/.next/standalone/.next/static/chunks/95339e55722bb4ca.js +5 -0
  477. package/.next/standalone/.next/static/chunks/9cd594813c539df9.js +1 -0
  478. package/.next/standalone/.next/static/chunks/ad1423eed05d129b.js +1 -0
  479. package/.next/standalone/.next/static/chunks/ae7b146884c67d2a.js +1 -0
  480. package/.next/standalone/.next/static/chunks/b84072d72aa86417.js +1 -0
  481. package/.next/standalone/.next/static/chunks/c1a95aebf6725f64.css +3 -0
  482. package/.next/standalone/.next/static/chunks/c515eb77d9410aa0.js +5 -0
  483. package/.next/standalone/.next/static/chunks/{9899cf4c2bdbe61d.js → d9ae203a7f123546.js} +2 -2
  484. package/.next/standalone/.next/static/chunks/e23f20b51a75a5bb.js +757 -0
  485. package/.next/standalone/.next/static/chunks/fdc09bd135846960.js +1 -0
  486. package/.next/standalone/.next/static/chunks/ff0196911449e745.js +1 -0
  487. package/.next/standalone/.next/static/chunks/{turbopack-4c21186b79fb4c10.js → turbopack-e1a0994ed4af988c.js} +1 -1
  488. package/.next/standalone/.spaces/cortex-context.md +70 -0
  489. package/.next/standalone/bin/cortex-hook.sh +62 -62
  490. package/.next/standalone/bin/cortex-mcp.js +60 -60
  491. package/.next/standalone/docs/superpowers/plans/2026-03-13-cortex-wiring.md +1387 -1387
  492. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-entity-graph.md +1923 -1923
  493. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-knowledge-evolution.md +1113 -1113
  494. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-boundary-engine.md +853 -853
  495. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-context-engine.md +1274 -1274
  496. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-signal-ingestion.md +933 -933
  497. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-lobes.md +1080 -1080
  498. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-gravity-system.md +768 -768
  499. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-ui.md +1108 -1108
  500. package/.next/standalone/docs/superpowers/plans/2026-03-18-cortex-ui-integration.md +1846 -1846
  501. package/.next/standalone/docs/superpowers/specs/2026-03-13-cortex-wiring-design.md +268 -268
  502. package/.next/standalone/docs/superpowers/specs/2026-03-14-cortex-v2-design.md +623 -623
  503. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-lobes-design.md +263 -263
  504. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md +240 -240
  505. package/.next/standalone/docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md +341 -341
  506. package/.next/standalone/node_modules/@img/sharp-win32-x64/lib/sharp-win32-x64.node +0 -0
  507. package/.next/standalone/node_modules/@img/{sharp-linux-x64 → sharp-win32-x64}/package.json +39 -46
  508. package/.next/standalone/package.json +103 -102
  509. package/.next/standalone/server.js +1 -1
  510. package/.next/standalone/src/app/(desktop)/cortex/page.tsx +78 -78
  511. package/.next/standalone/src/app/api/cortex/context/route.ts +78 -78
  512. package/.next/standalone/src/app/api/cortex/curation/assess/route.ts +27 -27
  513. package/.next/standalone/src/app/api/cortex/curation/publish/route.ts +23 -23
  514. package/.next/standalone/src/app/api/cortex/curation/refine/route.ts +23 -23
  515. package/.next/standalone/src/app/api/cortex/curation/review/route.ts +29 -29
  516. package/.next/standalone/src/app/api/cortex/curation/seed/route.ts +23 -23
  517. package/.next/standalone/src/app/api/cortex/export/route.ts +40 -40
  518. package/.next/standalone/src/app/api/cortex/federation/pending/route.ts +20 -20
  519. package/.next/standalone/src/app/api/cortex/federation/resolve/route.ts +43 -43
  520. package/.next/standalone/src/app/api/cortex/federation/search/route.ts +35 -35
  521. package/.next/standalone/src/app/api/cortex/federation/teach/route.ts +76 -76
  522. package/.next/standalone/src/app/api/cortex/graph/edges/route.ts +112 -112
  523. package/.next/standalone/src/app/api/cortex/graph/entities/[id]/route.ts +73 -73
  524. package/.next/standalone/src/app/api/cortex/graph/entities/route.ts +75 -75
  525. package/.next/standalone/src/app/api/cortex/graph/populate/route.ts +203 -203
  526. package/.next/standalone/src/app/api/cortex/import/route.ts +75 -75
  527. package/.next/standalone/src/app/api/cortex/import/status/route.ts +15 -15
  528. package/.next/standalone/src/app/api/cortex/ingest/bootstrap/route.ts +29 -29
  529. package/.next/standalone/src/app/api/cortex/ingest/status/route.ts +15 -15
  530. package/.next/standalone/src/app/api/cortex/knowledge/[id]/route.ts +91 -91
  531. package/.next/standalone/src/app/api/cortex/knowledge/route.ts +93 -93
  532. package/.next/standalone/src/app/api/cortex/lobes/[id]/route.ts +67 -67
  533. package/.next/standalone/src/app/api/cortex/lobes/route.ts +22 -22
  534. package/.next/standalone/src/app/api/cortex/lobes/share/route.ts +80 -80
  535. package/.next/standalone/src/app/api/cortex/marketplace/browse/route.ts +43 -43
  536. package/.next/standalone/src/app/api/cortex/marketplace/preview/route.ts +46 -46
  537. package/.next/standalone/src/app/api/cortex/mcp/call/route.ts +11 -11
  538. package/.next/standalone/src/app/api/cortex/mcp/tools/route.ts +6 -6
  539. package/.next/standalone/src/app/api/cortex/search/route.ts +43 -43
  540. package/.next/standalone/src/app/api/cortex/settings/route.ts +33 -33
  541. package/.next/standalone/src/app/api/cortex/status/route.ts +169 -169
  542. package/.next/standalone/src/app/api/cortex/timeline/route.ts +42 -42
  543. package/.next/standalone/src/app/api/cortex/usage/route.ts +31 -31
  544. package/.next/standalone/src/app/api/cortex/workspace/[id]/context/route.ts +41 -41
  545. package/.next/standalone/src/components/cortex/constants.ts +29 -29
  546. package/.next/standalone/src/components/cortex/cortex-dashboard.tsx +304 -304
  547. package/.next/standalone/src/components/cortex/cortex-indicator.tsx +44 -44
  548. package/.next/standalone/src/components/cortex/cortex-panel.tsx +140 -140
  549. package/.next/standalone/src/components/cortex/cortex-settings.tsx +221 -221
  550. package/.next/standalone/src/components/cortex/curation-tab.tsx +810 -810
  551. package/.next/standalone/src/components/cortex/entity-detail.tsx +101 -101
  552. package/.next/standalone/src/components/cortex/entity-graph.tsx +382 -382
  553. package/.next/standalone/src/components/cortex/import-dialog.tsx +212 -212
  554. package/.next/standalone/src/components/cortex/injection-badge.tsx +72 -72
  555. package/.next/standalone/src/components/cortex/knowledge-card.tsx +109 -109
  556. package/.next/standalone/src/components/cortex/knowledge-tab.tsx +158 -158
  557. package/.next/standalone/src/components/cortex/lobe-settings.tsx +215 -215
  558. package/.next/standalone/src/components/cortex/marketplace-card.tsx +126 -126
  559. package/.next/standalone/src/components/cortex/marketplace-tab.tsx +113 -113
  560. package/.next/standalone/src/lib/cortex/config.ts +40 -40
  561. package/.next/standalone/src/lib/cortex/debug.ts +10 -10
  562. package/.next/standalone/src/lib/cortex/distillation/usage-store.ts +18 -18
  563. package/.next/standalone/src/lib/cortex/graph/resolver.ts +10 -10
  564. package/.next/standalone/src/lib/cortex/graph/types.ts +22 -22
  565. package/.next/standalone/src/lib/cortex/index.ts +56 -56
  566. package/.next/standalone/src/lib/cortex/ingestion/bootstrap.ts +14 -14
  567. package/.next/standalone/src/lib/cortex/knowledge/compat.ts +14 -14
  568. package/.next/standalone/src/lib/cortex/knowledge/contradiction.ts +10 -10
  569. package/.next/standalone/src/lib/cortex/knowledge/types.ts +67 -67
  570. package/.next/standalone/src/lib/cortex/lobes/config.ts +16 -16
  571. package/.next/standalone/src/lib/cortex/lobes/resolver.ts +8 -8
  572. package/.next/standalone/src/lib/cortex/lobes/shares.ts +14 -14
  573. package/.next/standalone/src/lib/cortex/mcp/server.ts +8 -8
  574. package/.next/standalone/src/lib/cortex/portability/exporter.ts +6 -6
  575. package/.next/standalone/src/lib/cortex/portability/importer.ts +10 -10
  576. package/.next/standalone/src/lib/cortex/retrieval/context-engine.ts +10 -10
  577. package/.next/standalone/src/lib/cortex/types.ts +39 -39
  578. package/.next/standalone/tsconfig.json +34 -34
  579. package/LICENSE +661 -661
  580. package/README.md +131 -131
  581. package/bin/cortex-hook.sh +62 -62
  582. package/bin/cortex-mcp.js +60 -60
  583. package/bin/fix-standalone-externals.js +79 -79
  584. package/bin/lib/auto-setup.js +110 -110
  585. package/bin/mdns-service.js +171 -171
  586. package/bin/postinstall.js +35 -35
  587. package/bin/setup-admin.js +195 -195
  588. package/bin/spaces-dev.js +208 -208
  589. package/bin/spaces-install.js +599 -599
  590. package/bin/spaces-reset-totp.js +50 -50
  591. package/bin/spaces-service.js +1020 -1020
  592. package/bin/spaces-setup.js +253 -253
  593. package/bin/spaces.js +776 -776
  594. package/bin/ssh-auth-keys.sh +68 -68
  595. package/bin/terminal-server.js +1683 -1649
  596. package/package.json +103 -102
  597. package/.next/standalone/.next/server/chunks/ssr/_078dd64d._.js +0 -3
  598. package/.next/standalone/.next/server/chunks/ssr/_701606d5._.js +0 -3
  599. package/.next/standalone/.next/server/chunks/ssr/_72b1de37._.js +0 -3
  600. package/.next/standalone/.next/server/chunks/ssr/_950142a4._.js +0 -3
  601. package/.next/standalone/.next/server/chunks/ssr/src_components_terminal_terminal-pane_tsx_803c5e2c._.js +0 -7
  602. package/.next/standalone/.next/static/chunks/18f168665aef1aab.js +0 -1
  603. package/.next/standalone/.next/static/chunks/25b7a243a404a1a7.js +0 -1
  604. package/.next/standalone/.next/static/chunks/4a50d2a3e9bc9b41.js +0 -1
  605. package/.next/standalone/.next/static/chunks/6c78a1dfa7ec2959.css +0 -3
  606. package/.next/standalone/.next/static/chunks/7e0091ab6c5ee8bd.js +0 -1
  607. package/.next/standalone/.next/static/chunks/869f562dc32e55f4.js +0 -1
  608. package/.next/standalone/.next/static/chunks/8b3f4572fec83caa.js +0 -5
  609. package/.next/standalone/.next/static/chunks/8d5419afc4b9116b.js +0 -1
  610. package/.next/standalone/.next/static/chunks/9b2c5451f0b67975.js +0 -1
  611. package/.next/standalone/.next/static/chunks/ac339e970df82fa5.js +0 -5
  612. package/.next/standalone/.next/static/chunks/e7772d64463868eb.js +0 -1
  613. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/README.md +0 -46
  614. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  615. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/index.js +0 -1
  616. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  617. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/package.json +0 -42
  618. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
  619. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  620. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
  621. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  622. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
  623. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
  624. package/.next/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  625. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  626. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
  627. /package/.next/standalone/.next/static/{77VYbwIoyxFNr5xevTrCu → ncDe4k4gvD0788HAnq_3G}/_buildManifest.js +0 -0
  628. /package/.next/standalone/.next/static/{77VYbwIoyxFNr5xevTrCu → ncDe4k4gvD0788HAnq_3G}/_clientMiddlewareManifest.json +0 -0
  629. /package/.next/standalone/.next/static/{77VYbwIoyxFNr5xevTrCu → ncDe4k4gvD0788HAnq_3G}/_ssgManifest.js +0 -0
  630. /package/.next/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-win32-x64}/versions.json +0 -0
@@ -1,933 +1,933 @@
1
- # Cortex v2 — Pillar 5: Observable Signal Ingestion
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:** Build the adapter-based signal ingestion framework and implement the 3 core adapters (Conversations, Git History, Documents). The remaining 4 adapters (PR Reviews, Test Signals, Deployment, Behavioral) are deferred — they require external webhooks/APIs and can be added incrementally since the adapter interface is extensible.
6
-
7
- **Architecture:** A new `src/lib/cortex/signals/` module with a `SignalPipeline` class that consumes `SignalEnvelope` objects from any adapter. Each adapter implements a `SignalAdapter` interface with `extract()` (AsyncIterable) and `healthCheck()`. The existing `IngestionPipeline` is wrapped as the Conversation adapter for backward compat. The Git adapter parses `git log` output. The Document adapter watches `docs/**` for ADRs/READMEs.
8
-
9
- **Tech Stack:** TypeScript, vitest, child_process (for git), fs (for docs)
10
-
11
- **Spec:** `docs/superpowers/specs/2026-03-14-cortex-v2-design.md` — Pillar 5
12
-
13
- **Depends on:** Pillars 1-4 (all completed)
14
-
15
- **Deferred to future:** PR Review adapter, Test Signal adapter, Deployment adapter, Behavioral Inference adapter
16
-
17
- ---
18
-
19
- ## File Structure
20
-
21
- ```
22
- New files:
23
- ├── src/lib/cortex/signals/types.ts — SignalEnvelope, SignalAdapter interfaces
24
- ├── src/lib/cortex/signals/pipeline.ts — Unified SignalPipeline
25
- ├── src/lib/cortex/signals/adapters/conversation.ts — Wraps existing IngestionPipeline
26
- ├── src/lib/cortex/signals/adapters/git.ts — Git history adapter
27
- ├── src/lib/cortex/signals/adapters/document.ts — Document/ADR adapter
28
- ├── src/lib/cortex/signals/index.ts — Barrel export
29
-
30
- Test files:
31
- ├── tests/lib/cortex/signals/pipeline.test.ts
32
- ├── tests/lib/cortex/signals/adapters/git.test.ts
33
- ├── tests/lib/cortex/signals/adapters/document.test.ts
34
- ```
35
-
36
- ---
37
-
38
- ## Chunk 1: Signal Types and Unified Pipeline
39
-
40
- ### Task 1: Signal types
41
-
42
- **Files:**
43
- - Create: `src/lib/cortex/signals/types.ts`
44
-
45
- - [ ] **Step 1: Create types file**
46
-
47
- ```typescript
48
- // src/lib/cortex/signals/types.ts
49
- import type { KnowledgeType, SensitivityClass, Origin, EntityLink } from '../knowledge/types';
50
-
51
- export interface SignalEnvelope {
52
- text: string;
53
- origin: Origin;
54
- entities: EntityLink[];
55
- suggested_type: KnowledgeType;
56
- suggested_sensitivity: SensitivityClass;
57
- raw_metadata: Record<string, unknown>;
58
- }
59
-
60
- export interface SignalAdapter {
61
- name: string;
62
- schedule: 'realtime' | 'polling' | 'webhook' | 'cron';
63
- extract(): AsyncIterable<SignalEnvelope>;
64
- healthCheck(): Promise<boolean>;
65
- }
66
-
67
- export interface IngestResult {
68
- accepted: number;
69
- skipped: number; // dedup
70
- errors: string[];
71
- }
72
-
73
- /**
74
- * Graph edge update carried in raw_metadata.
75
- * Adapters can include these to update the entity graph during ingestion.
76
- */
77
- export interface EdgeUpdate {
78
- source_id: string;
79
- target_id: string;
80
- relation: string;
81
- weight_delta: number; // increment (not absolute)
82
- }
83
- ```
84
-
85
- - [ ] **Step 2: Commit**
86
-
87
- ```bash
88
- git add src/lib/cortex/signals/types.ts
89
- git commit -m "feat(cortex): add signal ingestion type definitions"
90
- ```
91
-
92
- ---
93
-
94
- ### Task 2: Unified SignalPipeline
95
-
96
- **Files:**
97
- - Create: `src/lib/cortex/signals/pipeline.ts`
98
- - Create: `tests/lib/cortex/signals/pipeline.test.ts`
99
-
100
- - [ ] **Step 1: Write failing tests**
101
-
102
- ```typescript
103
- // tests/lib/cortex/signals/pipeline.test.ts
104
- import { describe, it, expect, vi, beforeEach } from 'vitest';
105
- import { SignalPipeline } from '@/lib/cortex/signals/pipeline';
106
- import type { SignalEnvelope } from '@/lib/cortex/signals/types';
107
-
108
- const mockStore = {
109
- add: vi.fn().mockResolvedValue(undefined),
110
- search: vi.fn().mockResolvedValue([]),
111
- };
112
-
113
- const mockEmbedding = {
114
- embed: vi.fn().mockResolvedValue([[0.1, 0.2, 0.3]]),
115
- dimensions: 3,
116
- name: 'mock',
117
- init: vi.fn(),
118
- };
119
-
120
- const mockGraph = {
121
- createEdge: vi.fn(),
122
- incrementEdgeWeight: vi.fn(),
123
- getEntity: vi.fn().mockReturnValue(null),
124
- };
125
-
126
- const mockResolver = {
127
- extractEntities: vi.fn().mockReturnValue([]),
128
- };
129
-
130
- function makeEnvelope(overrides: Partial<SignalEnvelope> = {}): SignalEnvelope {
131
- return {
132
- text: 'Fix auth timeout by increasing pool size',
133
- origin: { source_type: 'git_commit', source_ref: 'abc123', creator_entity_id: 'person-alice' },
134
- entities: [],
135
- suggested_type: 'error_fix',
136
- suggested_sensitivity: 'internal',
137
- raw_metadata: {},
138
- ...overrides,
139
- };
140
- }
141
-
142
- describe('SignalPipeline', () => {
143
- let pipeline: SignalPipeline;
144
-
145
- beforeEach(() => {
146
- vi.clearAllMocks();
147
- pipeline = new SignalPipeline({
148
- store: mockStore as any,
149
- embedding: mockEmbedding as any,
150
- graph: mockGraph as any,
151
- resolver: mockResolver as any,
152
- });
153
- });
154
-
155
- it('ingests a signal envelope and stores it', async () => {
156
- const result = await pipeline.ingest(makeEnvelope());
157
- expect(result.accepted).toBe(1);
158
- expect(mockEmbedding.embed).toHaveBeenCalledWith(['Fix auth timeout by increasing pool size']);
159
- expect(mockStore.add).toHaveBeenCalledTimes(1);
160
- });
161
-
162
- it('uses suggested_type from envelope', async () => {
163
- await pipeline.ingest(makeEnvelope({ suggested_type: 'decision' }));
164
- const addCall = mockStore.add.mock.calls[0];
165
- expect(addCall[1].type).toBe('decision');
166
- });
167
-
168
- it('auto-classifies sensitivity (most restrictive wins)', async () => {
169
- // Text contains API key → confidential, overrides suggested 'internal'
170
- await pipeline.ingest(makeEnvelope({
171
- text: 'Set API_KEY=sk-ant-abc123 in production',
172
- suggested_sensitivity: 'internal',
173
- }));
174
- const addCall = mockStore.add.mock.calls[0];
175
- expect(addCall[1].sensitivity).toBe('confidential');
176
- });
177
-
178
- it('keeps suggested_sensitivity when more restrictive than auto-classification', async () => {
179
- await pipeline.ingest(makeEnvelope({
180
- text: 'General technical note', // auto-classifies as internal
181
- suggested_sensitivity: 'restricted', // more restrictive
182
- }));
183
- const addCall = mockStore.add.mock.calls[0];
184
- expect(addCall[1].sensitivity).toBe('restricted');
185
- });
186
-
187
- it('processes edge updates from raw_metadata', async () => {
188
- await pipeline.ingest(makeEnvelope({
189
- raw_metadata: {
190
- edge_updates: [
191
- { source_id: 'person-alice', target_id: 'topic-auth', relation: 'expert_in', weight_delta: 0.05 },
192
- ],
193
- },
194
- }));
195
- expect(mockGraph.incrementEdgeWeight).toHaveBeenCalledWith(
196
- 'person-alice', 'topic-auth', 'expert_in', 0.05
197
- );
198
- });
199
-
200
- it('deduplicates by text hash', async () => {
201
- const envelope = makeEnvelope();
202
- await pipeline.ingest(envelope);
203
- const result = await pipeline.ingest(envelope); // same text
204
- expect(result.skipped).toBe(1);
205
- expect(result.accepted).toBe(0);
206
- expect(mockStore.add).toHaveBeenCalledTimes(1); // only first call
207
- });
208
-
209
- it('ingests batch of envelopes', async () => {
210
- const envelopes = [
211
- makeEnvelope({ text: 'First signal' }),
212
- makeEnvelope({ text: 'Second signal' }),
213
- makeEnvelope({ text: 'Third signal' }),
214
- ];
215
- const result = await pipeline.ingestBatch(envelopes);
216
- expect(result.accepted).toBe(3);
217
- expect(mockStore.add).toHaveBeenCalledTimes(3);
218
- });
219
-
220
- it('handles embedding failures gracefully', async () => {
221
- mockEmbedding.embed.mockRejectedValueOnce(new Error('embed failed'));
222
- const result = await pipeline.ingest(makeEnvelope());
223
- expect(result.errors).toHaveLength(1);
224
- expect(result.accepted).toBe(0);
225
- });
226
- });
227
- ```
228
-
229
- - [ ] **Step 2: Run tests to verify they fail**
230
-
231
- Run: `npx vitest run tests/lib/cortex/signals/pipeline.test.ts`
232
-
233
- - [ ] **Step 3: Implement SignalPipeline**
234
-
235
- ```typescript
236
- // src/lib/cortex/signals/pipeline.ts
237
- import { createHash } from 'crypto';
238
- import type { CortexStore } from '../store';
239
- import type { EmbeddingProvider } from '../embeddings';
240
- import type { EntityGraph } from '../graph/entity-graph';
241
- import type { EntityResolver } from '../graph/resolver';
242
- import type { KnowledgeUnit } from '../knowledge/types';
243
- import { classifySensitivity } from '../boundary/classifier';
244
- import { layerToScope, scopeToLayerKey } from '../knowledge/compat';
245
- import type { SignalEnvelope, IngestResult, EdgeUpdate } from './types';
246
-
247
- const SENSITIVITY_PRIORITY: Record<string, number> = {
248
- public: 0, internal: 1, restricted: 2, confidential: 3,
249
- };
250
-
251
- export interface SignalPipelineDeps {
252
- store: CortexStore;
253
- embedding: EmbeddingProvider;
254
- graph: EntityGraph;
255
- resolver: EntityResolver;
256
- }
257
-
258
- export class SignalPipeline {
259
- private hashSet = new Set<string>();
260
- private deps: SignalPipelineDeps;
261
-
262
- constructor(deps: SignalPipelineDeps) {
263
- this.deps = deps;
264
- }
265
-
266
- async ingest(envelope: SignalEnvelope): Promise<IngestResult> {
267
- const result: IngestResult = { accepted: 0, skipped: 0, errors: [] };
268
-
269
- try {
270
- // 1. Dedup by text hash
271
- const hash = createHash('sha256')
272
- .update(envelope.text.replace(/\s+/g, ' ').trim())
273
- .digest('hex');
274
-
275
- if (this.hashSet.has(hash)) {
276
- result.skipped = 1;
277
- return result;
278
- }
279
- this.hashSet.add(hash);
280
-
281
- // 2. Sensitivity: most restrictive wins between suggested and auto-classified
282
- const autoSensitivity = classifySensitivity(envelope.text);
283
- const suggestedPriority = SENSITIVITY_PRIORITY[envelope.suggested_sensitivity] ?? 1;
284
- const autoPriority = SENSITIVITY_PRIORITY[autoSensitivity] ?? 1;
285
- const sensitivity = suggestedPriority >= autoPriority
286
- ? envelope.suggested_sensitivity : autoSensitivity;
287
-
288
- // 3. Embed
289
- const [vector] = await this.deps.embedding.embed([envelope.text]);
290
-
291
- // 4. Build scope from origin
292
- const scope = layerToScope('personal', null, envelope.origin.creator_entity_id.replace('person-', ''));
293
- const layerKey = scopeToLayerKey(scope);
294
- const layer = 'personal' as const; // default; adapters can override via metadata
295
-
296
- // 5. Build KnowledgeUnit
297
- const unit: KnowledgeUnit = {
298
- id: crypto.randomUUID(),
299
- vector,
300
- text: envelope.text,
301
- type: envelope.suggested_type,
302
- layer,
303
- workspace_id: (envelope.raw_metadata.workspace_id as number) ?? null,
304
- session_id: (envelope.raw_metadata.session_id as string) ?? null,
305
- agent_type: 'claude',
306
- project_path: (envelope.raw_metadata.project_path as string) ?? null,
307
- file_refs: (envelope.raw_metadata.file_refs as string[]) ?? [],
308
- confidence: 0.8,
309
- created: new Date().toISOString(),
310
- source_timestamp: new Date().toISOString(),
311
- stale_score: 0,
312
- access_count: 0,
313
- last_accessed: null,
314
- metadata: { source: envelope.origin.source_type },
315
- // v2 fields
316
- scope,
317
- entity_links: envelope.entities,
318
- evidence_score: 0.8,
319
- corroborations: 0,
320
- contradiction_refs: [],
321
- sensitivity,
322
- creator_scope: null,
323
- origin: envelope.origin,
324
- propagation_path: [],
325
- };
326
-
327
- // 6. Store
328
- await this.deps.store.add(layerKey, unit);
329
- result.accepted = 1;
330
-
331
- // 7. Process edge updates
332
- const edgeUpdates = (envelope.raw_metadata.edge_updates as EdgeUpdate[]) ?? [];
333
- for (const update of edgeUpdates) {
334
- try {
335
- this.deps.graph.incrementEdgeWeight(
336
- update.source_id, update.target_id, update.relation as any, update.weight_delta
337
- );
338
- } catch {
339
- // Edge entities may not exist yet, skip
340
- }
341
- }
342
-
343
- } catch (err: any) {
344
- result.errors.push(err.message);
345
- }
346
-
347
- return result;
348
- }
349
-
350
- async ingestBatch(envelopes: SignalEnvelope[]): Promise<IngestResult> {
351
- const totals: IngestResult = { accepted: 0, skipped: 0, errors: [] };
352
- for (const envelope of envelopes) {
353
- const r = await this.ingest(envelope);
354
- totals.accepted += r.accepted;
355
- totals.skipped += r.skipped;
356
- totals.errors.push(...r.errors);
357
- }
358
- return totals;
359
- }
360
- }
361
- ```
362
-
363
- - [ ] **Step 4: Run tests to verify they pass**
364
-
365
- Run: `npx vitest run tests/lib/cortex/signals/pipeline.test.ts`
366
- Expected: PASS (8 tests)
367
-
368
- - [ ] **Step 5: Commit**
369
-
370
- ```bash
371
- git add src/lib/cortex/signals/pipeline.ts tests/lib/cortex/signals/pipeline.test.ts
372
- git commit -m "feat(cortex): add unified SignalPipeline for multi-source ingestion"
373
- ```
374
-
375
- ---
376
-
377
- ## Chunk 2: Core Adapters
378
-
379
- ### Task 3: Conversation adapter (wraps existing pipeline)
380
-
381
- **Files:**
382
- - Create: `src/lib/cortex/signals/adapters/conversation.ts`
383
-
384
- - [ ] **Step 1: Implement conversation adapter**
385
-
386
- This adapter wraps the existing `IngestionPipeline` to produce `SignalEnvelope` objects from Claude Code session transcripts. It does NOT replace the existing pipeline — it wraps it so conversations flow through the unified `SignalPipeline`.
387
-
388
- ```typescript
389
- // src/lib/cortex/signals/adapters/conversation.ts
390
- import type { SignalAdapter, SignalEnvelope } from '../types';
391
-
392
- /**
393
- * Conversation adapter — wraps the learn hook's output format.
394
- * This is a "pull" adapter: it doesn't actively extract.
395
- * Instead, the learn hook POSTs to the knowledge API, and this adapter
396
- * can be used to convert raw session messages into SignalEnvelopes
397
- * for batch processing.
398
- */
399
- export class ConversationAdapter implements SignalAdapter {
400
- name = 'conversation';
401
- schedule = 'realtime' as const;
402
-
403
- async *extract(): AsyncIterable<SignalEnvelope> {
404
- // No-op for the conversation adapter.
405
- // Conversations are ingested in real-time via the learn hook → knowledge API.
406
- // This adapter exists to satisfy the interface and for future batch reprocessing.
407
- }
408
-
409
- async healthCheck(): Promise<boolean> {
410
- return true;
411
- }
412
-
413
- /**
414
- * Convert a raw Q&A pair into a SignalEnvelope (used by learn hook).
415
- */
416
- static fromQA(question: string, answer: string, sessionId: string, type: string = 'conversation'): SignalEnvelope {
417
- return {
418
- text: `Q: ${question}\nA: ${answer}`,
419
- origin: {
420
- source_type: 'conversation',
421
- source_ref: sessionId,
422
- creator_entity_id: 'person-default-user',
423
- },
424
- entities: [],
425
- suggested_type: type as any,
426
- suggested_sensitivity: 'internal',
427
- raw_metadata: { session_id: sessionId },
428
- };
429
- }
430
- }
431
- ```
432
-
433
- - [ ] **Step 2: Commit**
434
-
435
- ```bash
436
- git add src/lib/cortex/signals/adapters/conversation.ts
437
- git commit -m "feat(cortex): add conversation signal adapter"
438
- ```
439
-
440
- ---
441
-
442
- ### Task 4: Git history adapter
443
-
444
- **Files:**
445
- - Create: `src/lib/cortex/signals/adapters/git.ts`
446
- - Create: `tests/lib/cortex/signals/adapters/git.test.ts`
447
-
448
- - [ ] **Step 1: Write failing tests**
449
-
450
- ```typescript
451
- // tests/lib/cortex/signals/adapters/git.test.ts
452
- import { describe, it, expect, vi } from 'vitest';
453
- import { GitAdapter, parseGitLog } from '@/lib/cortex/signals/adapters/git';
454
- import type { SignalEnvelope } from '@/lib/cortex/signals/types';
455
-
456
- describe('parseGitLog', () => {
457
- it('parses a commit into a SignalEnvelope', () => {
458
- const logEntry = {
459
- sha: 'abc123def',
460
- author: 'alice@acme.com',
461
- authorName: 'Alice Smith',
462
- date: '2026-03-15T10:00:00Z',
463
- message: 'fix(auth): increase connection pool to handle concurrent load\n\nThe default pool of 10 was exhausted under peak traffic.',
464
- files: ['src/services/auth/pool.ts', 'config/auth.yaml'],
465
- };
466
-
467
- const envelopes = parseGitLog(logEntry);
468
- expect(envelopes.length).toBeGreaterThanOrEqual(1);
469
-
470
- const main = envelopes[0];
471
- expect(main.origin.source_type).toBe('git_commit');
472
- expect(main.origin.source_ref).toBe('abc123def');
473
- expect(main.suggested_type).toBe('error_fix'); // "fix" in message
474
- expect(main.text).toContain('increase connection pool');
475
- expect(main.raw_metadata.file_refs).toEqual(['src/services/auth/pool.ts', 'config/auth.yaml']);
476
- });
477
-
478
- it('classifies refactor commits as decisions', () => {
479
- const logEntry = {
480
- sha: 'def456',
481
- author: 'bob@acme.com',
482
- authorName: 'Bob',
483
- date: '2026-03-15T11:00:00Z',
484
- message: 'refactor: migrate auth from Express to Fastify',
485
- files: ['src/server.ts'],
486
- };
487
-
488
- const envelopes = parseGitLog(logEntry);
489
- expect(envelopes[0].suggested_type).toBe('decision');
490
- });
491
-
492
- it('classifies generic commits as context', () => {
493
- const logEntry = {
494
- sha: 'ghi789',
495
- author: 'charlie@acme.com',
496
- authorName: 'Charlie',
497
- date: '2026-03-15T12:00:00Z',
498
- message: 'update dependencies',
499
- files: ['package.json'],
500
- };
501
-
502
- const envelopes = parseGitLog(logEntry);
503
- expect(envelopes[0].suggested_type).toBe('context');
504
- });
505
-
506
- it('includes edge updates for author TOUCHES files', () => {
507
- const logEntry = {
508
- sha: 'jkl012',
509
- author: 'alice@acme.com',
510
- authorName: 'Alice Smith',
511
- date: '2026-03-15T13:00:00Z',
512
- message: 'feat: add new endpoint',
513
- files: ['src/api/users.ts'],
514
- };
515
-
516
- const envelopes = parseGitLog(logEntry);
517
- const edgeUpdates = envelopes[0].raw_metadata.edge_updates as any[];
518
- expect(edgeUpdates).toBeDefined();
519
- expect(edgeUpdates.length).toBeGreaterThanOrEqual(1);
520
- expect(edgeUpdates[0].relation).toBe('touches');
521
- });
522
-
523
- it('skips merge commits', () => {
524
- const logEntry = {
525
- sha: 'mno345',
526
- author: 'alice@acme.com',
527
- authorName: 'Alice',
528
- date: '2026-03-15T14:00:00Z',
529
- message: 'Merge branch \'feature/foo\' into main',
530
- files: [],
531
- };
532
-
533
- const envelopes = parseGitLog(logEntry);
534
- expect(envelopes).toHaveLength(0);
535
- });
536
- });
537
- ```
538
-
539
- - [ ] **Step 2: Implement git adapter**
540
-
541
- ```typescript
542
- // src/lib/cortex/signals/adapters/git.ts
543
- import type { SignalAdapter, SignalEnvelope, EdgeUpdate } from '../types';
544
- import { slugify } from '../../graph/types';
545
-
546
- export interface GitLogEntry {
547
- sha: string;
548
- author: string; // email
549
- authorName: string;
550
- date: string; // ISO timestamp
551
- message: string;
552
- files: string[];
553
- }
554
-
555
- const FIX_PATTERNS = [/^fix[:(]/, /\bfix\b/i, /\bbug\b/i, /\bhotfix\b/i];
556
- const DECISION_PATTERNS = [/^refactor[:(]/, /\bmigrat/i, /\bswitch\s+to\b/i, /\breplace\b.*\bwith\b/i, /^feat[:(]/];
557
- const MERGE_PATTERN = /^Merge\s+(branch|pull\s+request|remote)/i;
558
-
559
- /**
560
- * Parse a git log entry into SignalEnvelopes.
561
- */
562
- export function parseGitLog(entry: GitLogEntry): SignalEnvelope[] {
563
- // Skip merge commits
564
- if (MERGE_PATTERN.test(entry.message)) return [];
565
-
566
- // Skip very short messages
567
- const body = entry.message.trim();
568
- if (body.length < 10) return [];
569
-
570
- // Classify commit type
571
- let suggestedType: string = 'context';
572
- if (FIX_PATTERNS.some(p => p.test(body))) suggestedType = 'error_fix';
573
- else if (DECISION_PATTERNS.some(p => p.test(body))) suggestedType = 'decision';
574
-
575
- const authorSlug = slugify(entry.authorName);
576
- const creatorEntityId = `person-${authorSlug}`;
577
-
578
- // Build edge updates: author TOUCHES each file
579
- const edgeUpdates: EdgeUpdate[] = entry.files.map(file => ({
580
- source_id: creatorEntityId,
581
- target_id: `module-${slugify(file)}`,
582
- relation: 'touches',
583
- weight_delta: 0.05,
584
- }));
585
-
586
- const envelope: SignalEnvelope = {
587
- text: body,
588
- origin: {
589
- source_type: 'git_commit',
590
- source_ref: entry.sha,
591
- creator_entity_id: creatorEntityId,
592
- },
593
- entities: [],
594
- suggested_type: suggestedType as any,
595
- suggested_sensitivity: 'internal',
596
- raw_metadata: {
597
- file_refs: entry.files,
598
- edge_updates: edgeUpdates,
599
- author_email: entry.author,
600
- commit_date: entry.date,
601
- },
602
- };
603
-
604
- return [envelope];
605
- }
606
-
607
- /**
608
- * Git adapter — extracts knowledge from git history.
609
- * Uses `git log` to scan recent commits.
610
- */
611
- export class GitAdapter implements SignalAdapter {
612
- name = 'git';
613
- schedule = 'polling' as const;
614
-
615
- constructor(private repoPath: string, private sinceDate?: string) {}
616
-
617
- async *extract(): AsyncIterable<SignalEnvelope> {
618
- const { execSync } = await import('child_process');
619
- const since = this.sinceDate ?? new Date(Date.now() - 86400000).toISOString(); // default: last 24h
620
-
621
- try {
622
- const log = execSync(
623
- `git log --since="${since}" --format="%H|%ae|%an|%aI|%s" --name-only`,
624
- { cwd: this.repoPath, encoding: 'utf-8', timeout: 10000 }
625
- );
626
-
627
- const entries = this.parseLogOutput(log);
628
- for (const entry of entries) {
629
- for (const envelope of parseGitLog(entry)) {
630
- yield envelope;
631
- }
632
- }
633
- } catch {
634
- // Git not available or not a repo, yield nothing
635
- }
636
- }
637
-
638
- async healthCheck(): Promise<boolean> {
639
- try {
640
- const { execSync } = await import('child_process');
641
- execSync('git rev-parse HEAD', { cwd: this.repoPath, encoding: 'utf-8', timeout: 5000 });
642
- return true;
643
- } catch {
644
- return false;
645
- }
646
- }
647
-
648
- private parseLogOutput(log: string): GitLogEntry[] {
649
- const entries: GitLogEntry[] = [];
650
- const lines = log.split('\n');
651
- let current: GitLogEntry | null = null;
652
-
653
- for (const line of lines) {
654
- if (line.includes('|') && line.split('|').length >= 5) {
655
- if (current) entries.push(current);
656
- const [sha, author, authorName, date, ...messageParts] = line.split('|');
657
- current = {
658
- sha, author, authorName, date,
659
- message: messageParts.join('|'),
660
- files: [],
661
- };
662
- } else if (line.trim() && current) {
663
- current.files.push(line.trim());
664
- }
665
- }
666
-
667
- if (current) entries.push(current);
668
- return entries;
669
- }
670
- }
671
- ```
672
-
673
- - [ ] **Step 3: Run tests, commit**
674
-
675
- Run: `npx vitest run tests/lib/cortex/signals/adapters/git.test.ts`
676
-
677
- ```bash
678
- git commit -m "feat(cortex): add git history signal adapter"
679
- ```
680
-
681
- ---
682
-
683
- ### Task 5: Document adapter
684
-
685
- **Files:**
686
- - Create: `src/lib/cortex/signals/adapters/document.ts`
687
- - Create: `tests/lib/cortex/signals/adapters/document.test.ts`
688
-
689
- - [ ] **Step 1: Write failing tests**
690
-
691
- ```typescript
692
- // tests/lib/cortex/signals/adapters/document.test.ts
693
- import { describe, it, expect } from 'vitest';
694
- import { parseDocument, classifyDocument } from '@/lib/cortex/signals/adapters/document';
695
-
696
- describe('classifyDocument', () => {
697
- it('classifies ADR files as decisions', () => {
698
- expect(classifyDocument('docs/adr/001-use-postgres.md')).toBe('decision');
699
- expect(classifyDocument('docs/ADR-002.md')).toBe('decision');
700
- });
701
-
702
- it('classifies runbook files as pattern', () => {
703
- expect(classifyDocument('docs/runbooks/deploy-production.md')).toBe('pattern');
704
- });
705
-
706
- it('classifies README as context', () => {
707
- expect(classifyDocument('README.md')).toBe('context');
708
- expect(classifyDocument('docs/getting-started.md')).toBe('context');
709
- });
710
- });
711
-
712
- describe('parseDocument', () => {
713
- it('creates envelope from document content', () => {
714
- const envelope = parseDocument({
715
- path: 'docs/adr/001-use-postgres.md',
716
- content: '# ADR-001: Use PostgreSQL\n\nWe decided to use PostgreSQL for all new services due to its reliability and JSON support.',
717
- });
718
-
719
- expect(envelope.origin.source_type).toBe('document');
720
- expect(envelope.origin.source_ref).toBe('docs/adr/001-use-postgres.md');
721
- expect(envelope.suggested_type).toBe('decision');
722
- expect(envelope.text).toContain('PostgreSQL');
723
- expect(envelope.suggested_sensitivity).toBe('internal');
724
- });
725
-
726
- it('truncates very long documents', () => {
727
- const longContent = 'x'.repeat(10000);
728
- const envelope = parseDocument({
729
- path: 'docs/guide.md',
730
- content: longContent,
731
- });
732
- expect(envelope.text.length).toBeLessThanOrEqual(4000);
733
- });
734
-
735
- it('sets higher authority via raw_metadata', () => {
736
- const envelope = parseDocument({
737
- path: 'docs/adr/001.md',
738
- content: 'ADR content',
739
- });
740
- expect(envelope.raw_metadata.authority_boost).toBe(true);
741
- });
742
- });
743
- ```
744
-
745
- - [ ] **Step 2: Implement document adapter**
746
-
747
- ```typescript
748
- // src/lib/cortex/signals/adapters/document.ts
749
- import type { SignalAdapter, SignalEnvelope } from '../types';
750
- import type { KnowledgeType } from '../../knowledge/types';
751
-
752
- const MAX_DOC_LENGTH = 4000;
753
-
754
- const DOC_TYPE_PATTERNS: [RegExp, KnowledgeType][] = [
755
- [/\badr[s]?\b/i, 'decision'],
756
- [/\bADR[-_]/i, 'decision'],
757
- [/\brunbook/i, 'pattern'],
758
- [/\bplaybook/i, 'pattern'],
759
- [/\bREADME/i, 'context'],
760
- [/\bguide/i, 'context'],
761
- [/\bchangelog/i, 'summary'],
762
- ];
763
-
764
- export function classifyDocument(filepath: string): KnowledgeType {
765
- for (const [pattern, type] of DOC_TYPE_PATTERNS) {
766
- if (pattern.test(filepath)) return type;
767
- }
768
- return 'context';
769
- }
770
-
771
- export interface DocumentInput {
772
- path: string;
773
- content: string;
774
- }
775
-
776
- export function parseDocument(input: DocumentInput): SignalEnvelope {
777
- const type = classifyDocument(input.path);
778
- const text = input.content.length > MAX_DOC_LENGTH
779
- ? input.content.slice(0, MAX_DOC_LENGTH)
780
- : input.content;
781
-
782
- return {
783
- text,
784
- origin: {
785
- source_type: 'document',
786
- source_ref: input.path,
787
- creator_entity_id: 'person-default-user',
788
- },
789
- entities: [],
790
- suggested_type: type,
791
- suggested_sensitivity: 'internal',
792
- raw_metadata: {
793
- file_path: input.path,
794
- authority_boost: true, // documents have higher authority
795
- },
796
- };
797
- }
798
-
799
- /**
800
- * Document adapter — scans docs directories for markdown files.
801
- */
802
- export class DocumentAdapter implements SignalAdapter {
803
- name = 'document';
804
- schedule = 'polling' as const;
805
-
806
- constructor(private docPaths: string[]) {}
807
-
808
- async *extract(): AsyncIterable<SignalEnvelope> {
809
- const fs = await import('fs');
810
- const path = await import('path');
811
-
812
- for (const docDir of this.docPaths) {
813
- try {
814
- const files = this.walkDir(docDir, fs, path);
815
- for (const file of files) {
816
- if (!file.endsWith('.md')) continue;
817
- try {
818
- const content = fs.readFileSync(file, 'utf-8');
819
- yield parseDocument({ path: file, content });
820
- } catch {
821
- // File not readable, skip
822
- }
823
- }
824
- } catch {
825
- // Directory not accessible, skip
826
- }
827
- }
828
- }
829
-
830
- async healthCheck(): Promise<boolean> {
831
- const fs = await import('fs');
832
- return this.docPaths.some(p => {
833
- try { return fs.statSync(p).isDirectory(); } catch { return false; }
834
- });
835
- }
836
-
837
- private walkDir(dir: string, fs: any, path: any): string[] {
838
- const results: string[] = [];
839
- try {
840
- const entries = fs.readdirSync(dir, { withFileTypes: true });
841
- for (const entry of entries) {
842
- const full = path.join(dir, entry.name);
843
- if (entry.isDirectory() && !entry.name.startsWith('.')) {
844
- results.push(...this.walkDir(full, fs, path));
845
- } else if (entry.isFile()) {
846
- results.push(full);
847
- }
848
- }
849
- } catch { /* not accessible */ }
850
- return results;
851
- }
852
- }
853
- ```
854
-
855
- - [ ] **Step 3: Run tests, commit**
856
-
857
- Run: `npx vitest run tests/lib/cortex/signals/adapters/document.test.ts`
858
-
859
- ```bash
860
- git commit -m "feat(cortex): add document signal adapter"
861
- ```
862
-
863
- ---
864
-
865
- ## Chunk 3: Integration and Barrel Export
866
-
867
- ### Task 6: Barrel export and CortexInstance integration
868
-
869
- **Files:**
870
- - Create: `src/lib/cortex/signals/index.ts`
871
- - Modify: `src/lib/cortex/index.ts`
872
-
873
- - [ ] **Step 1: Create barrel export**
874
-
875
- ```typescript
876
- // src/lib/cortex/signals/index.ts
877
- export { SignalPipeline } from './pipeline';
878
- export type { SignalPipelineDeps } from './pipeline';
879
- export { ConversationAdapter } from './adapters/conversation';
880
- export { GitAdapter, parseGitLog } from './adapters/git';
881
- export type { GitLogEntry } from './adapters/git';
882
- export { DocumentAdapter, parseDocument, classifyDocument } from './adapters/document';
883
- export type { DocumentInput } from './adapters/document';
884
- export type { SignalEnvelope, SignalAdapter, IngestResult, EdgeUpdate } from './types';
885
- ```
886
-
887
- - [ ] **Step 2: Add SignalPipeline to CortexInstance**
888
-
889
- Read `src/lib/cortex/index.ts`. Add:
890
-
891
- 1. Import: `import { SignalPipeline } from './signals/pipeline';`
892
- 2. Add `signalPipeline?: SignalPipeline` to CortexInstance interface
893
- 3. In getCortex(), after graph/resolver initialization:
894
-
895
- ```typescript
896
- const signalPipeline = new SignalPipeline({ store, embedding, graph, resolver });
897
- ```
898
-
899
- 4. Include in instance object.
900
-
901
- - [ ] **Step 3: Run full test suite**
902
-
903
- Run: `npx vitest run tests/lib/cortex/`
904
-
905
- - [ ] **Step 4: Commit**
906
-
907
- ```bash
908
- git add src/lib/cortex/signals/index.ts src/lib/cortex/index.ts
909
- git commit -m "feat(cortex): add signal module barrel export and CortexInstance integration"
910
- ```
911
-
912
- ---
913
-
914
- ## Summary
915
-
916
- | Task | Component | Tests | Status |
917
- |------|-----------|-------|--------|
918
- | 1 | Signal types | — | |
919
- | 2 | Unified SignalPipeline | 8 | |
920
- | 3 | Conversation adapter | — | |
921
- | 4 | Git history adapter | 5 | |
922
- | 5 | Document adapter | 6 | |
923
- | 6 | Barrel export + integration | regression | |
924
-
925
- **Total: 6 tasks, ~19 new tests, 3 chunks**
926
-
927
- **Deferred adapters** (require external APIs/webhooks — implement when infrastructure is ready):
928
- - PR Review adapter (GitHub API)
929
- - Test Signal adapter (CI pipeline webhook)
930
- - Deployment adapter (deploy system webhook)
931
- - Behavioral Inference adapter (daily cron analyzing accumulated signals)
932
-
933
- Each deferred adapter = implement `SignalAdapter` interface + test, zero changes to SignalPipeline.
1
+ # Cortex v2 — Pillar 5: Observable Signal Ingestion
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:** Build the adapter-based signal ingestion framework and implement the 3 core adapters (Conversations, Git History, Documents). The remaining 4 adapters (PR Reviews, Test Signals, Deployment, Behavioral) are deferred — they require external webhooks/APIs and can be added incrementally since the adapter interface is extensible.
6
+
7
+ **Architecture:** A new `src/lib/cortex/signals/` module with a `SignalPipeline` class that consumes `SignalEnvelope` objects from any adapter. Each adapter implements a `SignalAdapter` interface with `extract()` (AsyncIterable) and `healthCheck()`. The existing `IngestionPipeline` is wrapped as the Conversation adapter for backward compat. The Git adapter parses `git log` output. The Document adapter watches `docs/**` for ADRs/READMEs.
8
+
9
+ **Tech Stack:** TypeScript, vitest, child_process (for git), fs (for docs)
10
+
11
+ **Spec:** `docs/superpowers/specs/2026-03-14-cortex-v2-design.md` — Pillar 5
12
+
13
+ **Depends on:** Pillars 1-4 (all completed)
14
+
15
+ **Deferred to future:** PR Review adapter, Test Signal adapter, Deployment adapter, Behavioral Inference adapter
16
+
17
+ ---
18
+
19
+ ## File Structure
20
+
21
+ ```
22
+ New files:
23
+ ├── src/lib/cortex/signals/types.ts — SignalEnvelope, SignalAdapter interfaces
24
+ ├── src/lib/cortex/signals/pipeline.ts — Unified SignalPipeline
25
+ ├── src/lib/cortex/signals/adapters/conversation.ts — Wraps existing IngestionPipeline
26
+ ├── src/lib/cortex/signals/adapters/git.ts — Git history adapter
27
+ ├── src/lib/cortex/signals/adapters/document.ts — Document/ADR adapter
28
+ ├── src/lib/cortex/signals/index.ts — Barrel export
29
+
30
+ Test files:
31
+ ├── tests/lib/cortex/signals/pipeline.test.ts
32
+ ├── tests/lib/cortex/signals/adapters/git.test.ts
33
+ ├── tests/lib/cortex/signals/adapters/document.test.ts
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Chunk 1: Signal Types and Unified Pipeline
39
+
40
+ ### Task 1: Signal types
41
+
42
+ **Files:**
43
+ - Create: `src/lib/cortex/signals/types.ts`
44
+
45
+ - [ ] **Step 1: Create types file**
46
+
47
+ ```typescript
48
+ // src/lib/cortex/signals/types.ts
49
+ import type { KnowledgeType, SensitivityClass, Origin, EntityLink } from '../knowledge/types';
50
+
51
+ export interface SignalEnvelope {
52
+ text: string;
53
+ origin: Origin;
54
+ entities: EntityLink[];
55
+ suggested_type: KnowledgeType;
56
+ suggested_sensitivity: SensitivityClass;
57
+ raw_metadata: Record<string, unknown>;
58
+ }
59
+
60
+ export interface SignalAdapter {
61
+ name: string;
62
+ schedule: 'realtime' | 'polling' | 'webhook' | 'cron';
63
+ extract(): AsyncIterable<SignalEnvelope>;
64
+ healthCheck(): Promise<boolean>;
65
+ }
66
+
67
+ export interface IngestResult {
68
+ accepted: number;
69
+ skipped: number; // dedup
70
+ errors: string[];
71
+ }
72
+
73
+ /**
74
+ * Graph edge update carried in raw_metadata.
75
+ * Adapters can include these to update the entity graph during ingestion.
76
+ */
77
+ export interface EdgeUpdate {
78
+ source_id: string;
79
+ target_id: string;
80
+ relation: string;
81
+ weight_delta: number; // increment (not absolute)
82
+ }
83
+ ```
84
+
85
+ - [ ] **Step 2: Commit**
86
+
87
+ ```bash
88
+ git add src/lib/cortex/signals/types.ts
89
+ git commit -m "feat(cortex): add signal ingestion type definitions"
90
+ ```
91
+
92
+ ---
93
+
94
+ ### Task 2: Unified SignalPipeline
95
+
96
+ **Files:**
97
+ - Create: `src/lib/cortex/signals/pipeline.ts`
98
+ - Create: `tests/lib/cortex/signals/pipeline.test.ts`
99
+
100
+ - [ ] **Step 1: Write failing tests**
101
+
102
+ ```typescript
103
+ // tests/lib/cortex/signals/pipeline.test.ts
104
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
105
+ import { SignalPipeline } from '@/lib/cortex/signals/pipeline';
106
+ import type { SignalEnvelope } from '@/lib/cortex/signals/types';
107
+
108
+ const mockStore = {
109
+ add: vi.fn().mockResolvedValue(undefined),
110
+ search: vi.fn().mockResolvedValue([]),
111
+ };
112
+
113
+ const mockEmbedding = {
114
+ embed: vi.fn().mockResolvedValue([[0.1, 0.2, 0.3]]),
115
+ dimensions: 3,
116
+ name: 'mock',
117
+ init: vi.fn(),
118
+ };
119
+
120
+ const mockGraph = {
121
+ createEdge: vi.fn(),
122
+ incrementEdgeWeight: vi.fn(),
123
+ getEntity: vi.fn().mockReturnValue(null),
124
+ };
125
+
126
+ const mockResolver = {
127
+ extractEntities: vi.fn().mockReturnValue([]),
128
+ };
129
+
130
+ function makeEnvelope(overrides: Partial<SignalEnvelope> = {}): SignalEnvelope {
131
+ return {
132
+ text: 'Fix auth timeout by increasing pool size',
133
+ origin: { source_type: 'git_commit', source_ref: 'abc123', creator_entity_id: 'person-alice' },
134
+ entities: [],
135
+ suggested_type: 'error_fix',
136
+ suggested_sensitivity: 'internal',
137
+ raw_metadata: {},
138
+ ...overrides,
139
+ };
140
+ }
141
+
142
+ describe('SignalPipeline', () => {
143
+ let pipeline: SignalPipeline;
144
+
145
+ beforeEach(() => {
146
+ vi.clearAllMocks();
147
+ pipeline = new SignalPipeline({
148
+ store: mockStore as any,
149
+ embedding: mockEmbedding as any,
150
+ graph: mockGraph as any,
151
+ resolver: mockResolver as any,
152
+ });
153
+ });
154
+
155
+ it('ingests a signal envelope and stores it', async () => {
156
+ const result = await pipeline.ingest(makeEnvelope());
157
+ expect(result.accepted).toBe(1);
158
+ expect(mockEmbedding.embed).toHaveBeenCalledWith(['Fix auth timeout by increasing pool size']);
159
+ expect(mockStore.add).toHaveBeenCalledTimes(1);
160
+ });
161
+
162
+ it('uses suggested_type from envelope', async () => {
163
+ await pipeline.ingest(makeEnvelope({ suggested_type: 'decision' }));
164
+ const addCall = mockStore.add.mock.calls[0];
165
+ expect(addCall[1].type).toBe('decision');
166
+ });
167
+
168
+ it('auto-classifies sensitivity (most restrictive wins)', async () => {
169
+ // Text contains API key → confidential, overrides suggested 'internal'
170
+ await pipeline.ingest(makeEnvelope({
171
+ text: 'Set API_KEY=sk-ant-abc123 in production',
172
+ suggested_sensitivity: 'internal',
173
+ }));
174
+ const addCall = mockStore.add.mock.calls[0];
175
+ expect(addCall[1].sensitivity).toBe('confidential');
176
+ });
177
+
178
+ it('keeps suggested_sensitivity when more restrictive than auto-classification', async () => {
179
+ await pipeline.ingest(makeEnvelope({
180
+ text: 'General technical note', // auto-classifies as internal
181
+ suggested_sensitivity: 'restricted', // more restrictive
182
+ }));
183
+ const addCall = mockStore.add.mock.calls[0];
184
+ expect(addCall[1].sensitivity).toBe('restricted');
185
+ });
186
+
187
+ it('processes edge updates from raw_metadata', async () => {
188
+ await pipeline.ingest(makeEnvelope({
189
+ raw_metadata: {
190
+ edge_updates: [
191
+ { source_id: 'person-alice', target_id: 'topic-auth', relation: 'expert_in', weight_delta: 0.05 },
192
+ ],
193
+ },
194
+ }));
195
+ expect(mockGraph.incrementEdgeWeight).toHaveBeenCalledWith(
196
+ 'person-alice', 'topic-auth', 'expert_in', 0.05
197
+ );
198
+ });
199
+
200
+ it('deduplicates by text hash', async () => {
201
+ const envelope = makeEnvelope();
202
+ await pipeline.ingest(envelope);
203
+ const result = await pipeline.ingest(envelope); // same text
204
+ expect(result.skipped).toBe(1);
205
+ expect(result.accepted).toBe(0);
206
+ expect(mockStore.add).toHaveBeenCalledTimes(1); // only first call
207
+ });
208
+
209
+ it('ingests batch of envelopes', async () => {
210
+ const envelopes = [
211
+ makeEnvelope({ text: 'First signal' }),
212
+ makeEnvelope({ text: 'Second signal' }),
213
+ makeEnvelope({ text: 'Third signal' }),
214
+ ];
215
+ const result = await pipeline.ingestBatch(envelopes);
216
+ expect(result.accepted).toBe(3);
217
+ expect(mockStore.add).toHaveBeenCalledTimes(3);
218
+ });
219
+
220
+ it('handles embedding failures gracefully', async () => {
221
+ mockEmbedding.embed.mockRejectedValueOnce(new Error('embed failed'));
222
+ const result = await pipeline.ingest(makeEnvelope());
223
+ expect(result.errors).toHaveLength(1);
224
+ expect(result.accepted).toBe(0);
225
+ });
226
+ });
227
+ ```
228
+
229
+ - [ ] **Step 2: Run tests to verify they fail**
230
+
231
+ Run: `npx vitest run tests/lib/cortex/signals/pipeline.test.ts`
232
+
233
+ - [ ] **Step 3: Implement SignalPipeline**
234
+
235
+ ```typescript
236
+ // src/lib/cortex/signals/pipeline.ts
237
+ import { createHash } from 'crypto';
238
+ import type { CortexStore } from '../store';
239
+ import type { EmbeddingProvider } from '../embeddings';
240
+ import type { EntityGraph } from '../graph/entity-graph';
241
+ import type { EntityResolver } from '../graph/resolver';
242
+ import type { KnowledgeUnit } from '../knowledge/types';
243
+ import { classifySensitivity } from '../boundary/classifier';
244
+ import { layerToScope, scopeToLayerKey } from '../knowledge/compat';
245
+ import type { SignalEnvelope, IngestResult, EdgeUpdate } from './types';
246
+
247
+ const SENSITIVITY_PRIORITY: Record<string, number> = {
248
+ public: 0, internal: 1, restricted: 2, confidential: 3,
249
+ };
250
+
251
+ export interface SignalPipelineDeps {
252
+ store: CortexStore;
253
+ embedding: EmbeddingProvider;
254
+ graph: EntityGraph;
255
+ resolver: EntityResolver;
256
+ }
257
+
258
+ export class SignalPipeline {
259
+ private hashSet = new Set<string>();
260
+ private deps: SignalPipelineDeps;
261
+
262
+ constructor(deps: SignalPipelineDeps) {
263
+ this.deps = deps;
264
+ }
265
+
266
+ async ingest(envelope: SignalEnvelope): Promise<IngestResult> {
267
+ const result: IngestResult = { accepted: 0, skipped: 0, errors: [] };
268
+
269
+ try {
270
+ // 1. Dedup by text hash
271
+ const hash = createHash('sha256')
272
+ .update(envelope.text.replace(/\s+/g, ' ').trim())
273
+ .digest('hex');
274
+
275
+ if (this.hashSet.has(hash)) {
276
+ result.skipped = 1;
277
+ return result;
278
+ }
279
+ this.hashSet.add(hash);
280
+
281
+ // 2. Sensitivity: most restrictive wins between suggested and auto-classified
282
+ const autoSensitivity = classifySensitivity(envelope.text);
283
+ const suggestedPriority = SENSITIVITY_PRIORITY[envelope.suggested_sensitivity] ?? 1;
284
+ const autoPriority = SENSITIVITY_PRIORITY[autoSensitivity] ?? 1;
285
+ const sensitivity = suggestedPriority >= autoPriority
286
+ ? envelope.suggested_sensitivity : autoSensitivity;
287
+
288
+ // 3. Embed
289
+ const [vector] = await this.deps.embedding.embed([envelope.text]);
290
+
291
+ // 4. Build scope from origin
292
+ const scope = layerToScope('personal', null, envelope.origin.creator_entity_id.replace('person-', ''));
293
+ const layerKey = scopeToLayerKey(scope);
294
+ const layer = 'personal' as const; // default; adapters can override via metadata
295
+
296
+ // 5. Build KnowledgeUnit
297
+ const unit: KnowledgeUnit = {
298
+ id: crypto.randomUUID(),
299
+ vector,
300
+ text: envelope.text,
301
+ type: envelope.suggested_type,
302
+ layer,
303
+ workspace_id: (envelope.raw_metadata.workspace_id as number) ?? null,
304
+ session_id: (envelope.raw_metadata.session_id as string) ?? null,
305
+ agent_type: 'claude',
306
+ project_path: (envelope.raw_metadata.project_path as string) ?? null,
307
+ file_refs: (envelope.raw_metadata.file_refs as string[]) ?? [],
308
+ confidence: 0.8,
309
+ created: new Date().toISOString(),
310
+ source_timestamp: new Date().toISOString(),
311
+ stale_score: 0,
312
+ access_count: 0,
313
+ last_accessed: null,
314
+ metadata: { source: envelope.origin.source_type },
315
+ // v2 fields
316
+ scope,
317
+ entity_links: envelope.entities,
318
+ evidence_score: 0.8,
319
+ corroborations: 0,
320
+ contradiction_refs: [],
321
+ sensitivity,
322
+ creator_scope: null,
323
+ origin: envelope.origin,
324
+ propagation_path: [],
325
+ };
326
+
327
+ // 6. Store
328
+ await this.deps.store.add(layerKey, unit);
329
+ result.accepted = 1;
330
+
331
+ // 7. Process edge updates
332
+ const edgeUpdates = (envelope.raw_metadata.edge_updates as EdgeUpdate[]) ?? [];
333
+ for (const update of edgeUpdates) {
334
+ try {
335
+ this.deps.graph.incrementEdgeWeight(
336
+ update.source_id, update.target_id, update.relation as any, update.weight_delta
337
+ );
338
+ } catch {
339
+ // Edge entities may not exist yet, skip
340
+ }
341
+ }
342
+
343
+ } catch (err: any) {
344
+ result.errors.push(err.message);
345
+ }
346
+
347
+ return result;
348
+ }
349
+
350
+ async ingestBatch(envelopes: SignalEnvelope[]): Promise<IngestResult> {
351
+ const totals: IngestResult = { accepted: 0, skipped: 0, errors: [] };
352
+ for (const envelope of envelopes) {
353
+ const r = await this.ingest(envelope);
354
+ totals.accepted += r.accepted;
355
+ totals.skipped += r.skipped;
356
+ totals.errors.push(...r.errors);
357
+ }
358
+ return totals;
359
+ }
360
+ }
361
+ ```
362
+
363
+ - [ ] **Step 4: Run tests to verify they pass**
364
+
365
+ Run: `npx vitest run tests/lib/cortex/signals/pipeline.test.ts`
366
+ Expected: PASS (8 tests)
367
+
368
+ - [ ] **Step 5: Commit**
369
+
370
+ ```bash
371
+ git add src/lib/cortex/signals/pipeline.ts tests/lib/cortex/signals/pipeline.test.ts
372
+ git commit -m "feat(cortex): add unified SignalPipeline for multi-source ingestion"
373
+ ```
374
+
375
+ ---
376
+
377
+ ## Chunk 2: Core Adapters
378
+
379
+ ### Task 3: Conversation adapter (wraps existing pipeline)
380
+
381
+ **Files:**
382
+ - Create: `src/lib/cortex/signals/adapters/conversation.ts`
383
+
384
+ - [ ] **Step 1: Implement conversation adapter**
385
+
386
+ This adapter wraps the existing `IngestionPipeline` to produce `SignalEnvelope` objects from Claude Code session transcripts. It does NOT replace the existing pipeline — it wraps it so conversations flow through the unified `SignalPipeline`.
387
+
388
+ ```typescript
389
+ // src/lib/cortex/signals/adapters/conversation.ts
390
+ import type { SignalAdapter, SignalEnvelope } from '../types';
391
+
392
+ /**
393
+ * Conversation adapter — wraps the learn hook's output format.
394
+ * This is a "pull" adapter: it doesn't actively extract.
395
+ * Instead, the learn hook POSTs to the knowledge API, and this adapter
396
+ * can be used to convert raw session messages into SignalEnvelopes
397
+ * for batch processing.
398
+ */
399
+ export class ConversationAdapter implements SignalAdapter {
400
+ name = 'conversation';
401
+ schedule = 'realtime' as const;
402
+
403
+ async *extract(): AsyncIterable<SignalEnvelope> {
404
+ // No-op for the conversation adapter.
405
+ // Conversations are ingested in real-time via the learn hook → knowledge API.
406
+ // This adapter exists to satisfy the interface and for future batch reprocessing.
407
+ }
408
+
409
+ async healthCheck(): Promise<boolean> {
410
+ return true;
411
+ }
412
+
413
+ /**
414
+ * Convert a raw Q&A pair into a SignalEnvelope (used by learn hook).
415
+ */
416
+ static fromQA(question: string, answer: string, sessionId: string, type: string = 'conversation'): SignalEnvelope {
417
+ return {
418
+ text: `Q: ${question}\nA: ${answer}`,
419
+ origin: {
420
+ source_type: 'conversation',
421
+ source_ref: sessionId,
422
+ creator_entity_id: 'person-default-user',
423
+ },
424
+ entities: [],
425
+ suggested_type: type as any,
426
+ suggested_sensitivity: 'internal',
427
+ raw_metadata: { session_id: sessionId },
428
+ };
429
+ }
430
+ }
431
+ ```
432
+
433
+ - [ ] **Step 2: Commit**
434
+
435
+ ```bash
436
+ git add src/lib/cortex/signals/adapters/conversation.ts
437
+ git commit -m "feat(cortex): add conversation signal adapter"
438
+ ```
439
+
440
+ ---
441
+
442
+ ### Task 4: Git history adapter
443
+
444
+ **Files:**
445
+ - Create: `src/lib/cortex/signals/adapters/git.ts`
446
+ - Create: `tests/lib/cortex/signals/adapters/git.test.ts`
447
+
448
+ - [ ] **Step 1: Write failing tests**
449
+
450
+ ```typescript
451
+ // tests/lib/cortex/signals/adapters/git.test.ts
452
+ import { describe, it, expect, vi } from 'vitest';
453
+ import { GitAdapter, parseGitLog } from '@/lib/cortex/signals/adapters/git';
454
+ import type { SignalEnvelope } from '@/lib/cortex/signals/types';
455
+
456
+ describe('parseGitLog', () => {
457
+ it('parses a commit into a SignalEnvelope', () => {
458
+ const logEntry = {
459
+ sha: 'abc123def',
460
+ author: 'alice@acme.com',
461
+ authorName: 'Alice Smith',
462
+ date: '2026-03-15T10:00:00Z',
463
+ message: 'fix(auth): increase connection pool to handle concurrent load\n\nThe default pool of 10 was exhausted under peak traffic.',
464
+ files: ['src/services/auth/pool.ts', 'config/auth.yaml'],
465
+ };
466
+
467
+ const envelopes = parseGitLog(logEntry);
468
+ expect(envelopes.length).toBeGreaterThanOrEqual(1);
469
+
470
+ const main = envelopes[0];
471
+ expect(main.origin.source_type).toBe('git_commit');
472
+ expect(main.origin.source_ref).toBe('abc123def');
473
+ expect(main.suggested_type).toBe('error_fix'); // "fix" in message
474
+ expect(main.text).toContain('increase connection pool');
475
+ expect(main.raw_metadata.file_refs).toEqual(['src/services/auth/pool.ts', 'config/auth.yaml']);
476
+ });
477
+
478
+ it('classifies refactor commits as decisions', () => {
479
+ const logEntry = {
480
+ sha: 'def456',
481
+ author: 'bob@acme.com',
482
+ authorName: 'Bob',
483
+ date: '2026-03-15T11:00:00Z',
484
+ message: 'refactor: migrate auth from Express to Fastify',
485
+ files: ['src/server.ts'],
486
+ };
487
+
488
+ const envelopes = parseGitLog(logEntry);
489
+ expect(envelopes[0].suggested_type).toBe('decision');
490
+ });
491
+
492
+ it('classifies generic commits as context', () => {
493
+ const logEntry = {
494
+ sha: 'ghi789',
495
+ author: 'charlie@acme.com',
496
+ authorName: 'Charlie',
497
+ date: '2026-03-15T12:00:00Z',
498
+ message: 'update dependencies',
499
+ files: ['package.json'],
500
+ };
501
+
502
+ const envelopes = parseGitLog(logEntry);
503
+ expect(envelopes[0].suggested_type).toBe('context');
504
+ });
505
+
506
+ it('includes edge updates for author TOUCHES files', () => {
507
+ const logEntry = {
508
+ sha: 'jkl012',
509
+ author: 'alice@acme.com',
510
+ authorName: 'Alice Smith',
511
+ date: '2026-03-15T13:00:00Z',
512
+ message: 'feat: add new endpoint',
513
+ files: ['src/api/users.ts'],
514
+ };
515
+
516
+ const envelopes = parseGitLog(logEntry);
517
+ const edgeUpdates = envelopes[0].raw_metadata.edge_updates as any[];
518
+ expect(edgeUpdates).toBeDefined();
519
+ expect(edgeUpdates.length).toBeGreaterThanOrEqual(1);
520
+ expect(edgeUpdates[0].relation).toBe('touches');
521
+ });
522
+
523
+ it('skips merge commits', () => {
524
+ const logEntry = {
525
+ sha: 'mno345',
526
+ author: 'alice@acme.com',
527
+ authorName: 'Alice',
528
+ date: '2026-03-15T14:00:00Z',
529
+ message: 'Merge branch \'feature/foo\' into main',
530
+ files: [],
531
+ };
532
+
533
+ const envelopes = parseGitLog(logEntry);
534
+ expect(envelopes).toHaveLength(0);
535
+ });
536
+ });
537
+ ```
538
+
539
+ - [ ] **Step 2: Implement git adapter**
540
+
541
+ ```typescript
542
+ // src/lib/cortex/signals/adapters/git.ts
543
+ import type { SignalAdapter, SignalEnvelope, EdgeUpdate } from '../types';
544
+ import { slugify } from '../../graph/types';
545
+
546
+ export interface GitLogEntry {
547
+ sha: string;
548
+ author: string; // email
549
+ authorName: string;
550
+ date: string; // ISO timestamp
551
+ message: string;
552
+ files: string[];
553
+ }
554
+
555
+ const FIX_PATTERNS = [/^fix[:(]/, /\bfix\b/i, /\bbug\b/i, /\bhotfix\b/i];
556
+ const DECISION_PATTERNS = [/^refactor[:(]/, /\bmigrat/i, /\bswitch\s+to\b/i, /\breplace\b.*\bwith\b/i, /^feat[:(]/];
557
+ const MERGE_PATTERN = /^Merge\s+(branch|pull\s+request|remote)/i;
558
+
559
+ /**
560
+ * Parse a git log entry into SignalEnvelopes.
561
+ */
562
+ export function parseGitLog(entry: GitLogEntry): SignalEnvelope[] {
563
+ // Skip merge commits
564
+ if (MERGE_PATTERN.test(entry.message)) return [];
565
+
566
+ // Skip very short messages
567
+ const body = entry.message.trim();
568
+ if (body.length < 10) return [];
569
+
570
+ // Classify commit type
571
+ let suggestedType: string = 'context';
572
+ if (FIX_PATTERNS.some(p => p.test(body))) suggestedType = 'error_fix';
573
+ else if (DECISION_PATTERNS.some(p => p.test(body))) suggestedType = 'decision';
574
+
575
+ const authorSlug = slugify(entry.authorName);
576
+ const creatorEntityId = `person-${authorSlug}`;
577
+
578
+ // Build edge updates: author TOUCHES each file
579
+ const edgeUpdates: EdgeUpdate[] = entry.files.map(file => ({
580
+ source_id: creatorEntityId,
581
+ target_id: `module-${slugify(file)}`,
582
+ relation: 'touches',
583
+ weight_delta: 0.05,
584
+ }));
585
+
586
+ const envelope: SignalEnvelope = {
587
+ text: body,
588
+ origin: {
589
+ source_type: 'git_commit',
590
+ source_ref: entry.sha,
591
+ creator_entity_id: creatorEntityId,
592
+ },
593
+ entities: [],
594
+ suggested_type: suggestedType as any,
595
+ suggested_sensitivity: 'internal',
596
+ raw_metadata: {
597
+ file_refs: entry.files,
598
+ edge_updates: edgeUpdates,
599
+ author_email: entry.author,
600
+ commit_date: entry.date,
601
+ },
602
+ };
603
+
604
+ return [envelope];
605
+ }
606
+
607
+ /**
608
+ * Git adapter — extracts knowledge from git history.
609
+ * Uses `git log` to scan recent commits.
610
+ */
611
+ export class GitAdapter implements SignalAdapter {
612
+ name = 'git';
613
+ schedule = 'polling' as const;
614
+
615
+ constructor(private repoPath: string, private sinceDate?: string) {}
616
+
617
+ async *extract(): AsyncIterable<SignalEnvelope> {
618
+ const { execSync } = await import('child_process');
619
+ const since = this.sinceDate ?? new Date(Date.now() - 86400000).toISOString(); // default: last 24h
620
+
621
+ try {
622
+ const log = execSync(
623
+ `git log --since="${since}" --format="%H|%ae|%an|%aI|%s" --name-only`,
624
+ { cwd: this.repoPath, encoding: 'utf-8', timeout: 10000 }
625
+ );
626
+
627
+ const entries = this.parseLogOutput(log);
628
+ for (const entry of entries) {
629
+ for (const envelope of parseGitLog(entry)) {
630
+ yield envelope;
631
+ }
632
+ }
633
+ } catch {
634
+ // Git not available or not a repo, yield nothing
635
+ }
636
+ }
637
+
638
+ async healthCheck(): Promise<boolean> {
639
+ try {
640
+ const { execSync } = await import('child_process');
641
+ execSync('git rev-parse HEAD', { cwd: this.repoPath, encoding: 'utf-8', timeout: 5000 });
642
+ return true;
643
+ } catch {
644
+ return false;
645
+ }
646
+ }
647
+
648
+ private parseLogOutput(log: string): GitLogEntry[] {
649
+ const entries: GitLogEntry[] = [];
650
+ const lines = log.split('\n');
651
+ let current: GitLogEntry | null = null;
652
+
653
+ for (const line of lines) {
654
+ if (line.includes('|') && line.split('|').length >= 5) {
655
+ if (current) entries.push(current);
656
+ const [sha, author, authorName, date, ...messageParts] = line.split('|');
657
+ current = {
658
+ sha, author, authorName, date,
659
+ message: messageParts.join('|'),
660
+ files: [],
661
+ };
662
+ } else if (line.trim() && current) {
663
+ current.files.push(line.trim());
664
+ }
665
+ }
666
+
667
+ if (current) entries.push(current);
668
+ return entries;
669
+ }
670
+ }
671
+ ```
672
+
673
+ - [ ] **Step 3: Run tests, commit**
674
+
675
+ Run: `npx vitest run tests/lib/cortex/signals/adapters/git.test.ts`
676
+
677
+ ```bash
678
+ git commit -m "feat(cortex): add git history signal adapter"
679
+ ```
680
+
681
+ ---
682
+
683
+ ### Task 5: Document adapter
684
+
685
+ **Files:**
686
+ - Create: `src/lib/cortex/signals/adapters/document.ts`
687
+ - Create: `tests/lib/cortex/signals/adapters/document.test.ts`
688
+
689
+ - [ ] **Step 1: Write failing tests**
690
+
691
+ ```typescript
692
+ // tests/lib/cortex/signals/adapters/document.test.ts
693
+ import { describe, it, expect } from 'vitest';
694
+ import { parseDocument, classifyDocument } from '@/lib/cortex/signals/adapters/document';
695
+
696
+ describe('classifyDocument', () => {
697
+ it('classifies ADR files as decisions', () => {
698
+ expect(classifyDocument('docs/adr/001-use-postgres.md')).toBe('decision');
699
+ expect(classifyDocument('docs/ADR-002.md')).toBe('decision');
700
+ });
701
+
702
+ it('classifies runbook files as pattern', () => {
703
+ expect(classifyDocument('docs/runbooks/deploy-production.md')).toBe('pattern');
704
+ });
705
+
706
+ it('classifies README as context', () => {
707
+ expect(classifyDocument('README.md')).toBe('context');
708
+ expect(classifyDocument('docs/getting-started.md')).toBe('context');
709
+ });
710
+ });
711
+
712
+ describe('parseDocument', () => {
713
+ it('creates envelope from document content', () => {
714
+ const envelope = parseDocument({
715
+ path: 'docs/adr/001-use-postgres.md',
716
+ content: '# ADR-001: Use PostgreSQL\n\nWe decided to use PostgreSQL for all new services due to its reliability and JSON support.',
717
+ });
718
+
719
+ expect(envelope.origin.source_type).toBe('document');
720
+ expect(envelope.origin.source_ref).toBe('docs/adr/001-use-postgres.md');
721
+ expect(envelope.suggested_type).toBe('decision');
722
+ expect(envelope.text).toContain('PostgreSQL');
723
+ expect(envelope.suggested_sensitivity).toBe('internal');
724
+ });
725
+
726
+ it('truncates very long documents', () => {
727
+ const longContent = 'x'.repeat(10000);
728
+ const envelope = parseDocument({
729
+ path: 'docs/guide.md',
730
+ content: longContent,
731
+ });
732
+ expect(envelope.text.length).toBeLessThanOrEqual(4000);
733
+ });
734
+
735
+ it('sets higher authority via raw_metadata', () => {
736
+ const envelope = parseDocument({
737
+ path: 'docs/adr/001.md',
738
+ content: 'ADR content',
739
+ });
740
+ expect(envelope.raw_metadata.authority_boost).toBe(true);
741
+ });
742
+ });
743
+ ```
744
+
745
+ - [ ] **Step 2: Implement document adapter**
746
+
747
+ ```typescript
748
+ // src/lib/cortex/signals/adapters/document.ts
749
+ import type { SignalAdapter, SignalEnvelope } from '../types';
750
+ import type { KnowledgeType } from '../../knowledge/types';
751
+
752
+ const MAX_DOC_LENGTH = 4000;
753
+
754
+ const DOC_TYPE_PATTERNS: [RegExp, KnowledgeType][] = [
755
+ [/\badr[s]?\b/i, 'decision'],
756
+ [/\bADR[-_]/i, 'decision'],
757
+ [/\brunbook/i, 'pattern'],
758
+ [/\bplaybook/i, 'pattern'],
759
+ [/\bREADME/i, 'context'],
760
+ [/\bguide/i, 'context'],
761
+ [/\bchangelog/i, 'summary'],
762
+ ];
763
+
764
+ export function classifyDocument(filepath: string): KnowledgeType {
765
+ for (const [pattern, type] of DOC_TYPE_PATTERNS) {
766
+ if (pattern.test(filepath)) return type;
767
+ }
768
+ return 'context';
769
+ }
770
+
771
+ export interface DocumentInput {
772
+ path: string;
773
+ content: string;
774
+ }
775
+
776
+ export function parseDocument(input: DocumentInput): SignalEnvelope {
777
+ const type = classifyDocument(input.path);
778
+ const text = input.content.length > MAX_DOC_LENGTH
779
+ ? input.content.slice(0, MAX_DOC_LENGTH)
780
+ : input.content;
781
+
782
+ return {
783
+ text,
784
+ origin: {
785
+ source_type: 'document',
786
+ source_ref: input.path,
787
+ creator_entity_id: 'person-default-user',
788
+ },
789
+ entities: [],
790
+ suggested_type: type,
791
+ suggested_sensitivity: 'internal',
792
+ raw_metadata: {
793
+ file_path: input.path,
794
+ authority_boost: true, // documents have higher authority
795
+ },
796
+ };
797
+ }
798
+
799
+ /**
800
+ * Document adapter — scans docs directories for markdown files.
801
+ */
802
+ export class DocumentAdapter implements SignalAdapter {
803
+ name = 'document';
804
+ schedule = 'polling' as const;
805
+
806
+ constructor(private docPaths: string[]) {}
807
+
808
+ async *extract(): AsyncIterable<SignalEnvelope> {
809
+ const fs = await import('fs');
810
+ const path = await import('path');
811
+
812
+ for (const docDir of this.docPaths) {
813
+ try {
814
+ const files = this.walkDir(docDir, fs, path);
815
+ for (const file of files) {
816
+ if (!file.endsWith('.md')) continue;
817
+ try {
818
+ const content = fs.readFileSync(file, 'utf-8');
819
+ yield parseDocument({ path: file, content });
820
+ } catch {
821
+ // File not readable, skip
822
+ }
823
+ }
824
+ } catch {
825
+ // Directory not accessible, skip
826
+ }
827
+ }
828
+ }
829
+
830
+ async healthCheck(): Promise<boolean> {
831
+ const fs = await import('fs');
832
+ return this.docPaths.some(p => {
833
+ try { return fs.statSync(p).isDirectory(); } catch { return false; }
834
+ });
835
+ }
836
+
837
+ private walkDir(dir: string, fs: any, path: any): string[] {
838
+ const results: string[] = [];
839
+ try {
840
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
841
+ for (const entry of entries) {
842
+ const full = path.join(dir, entry.name);
843
+ if (entry.isDirectory() && !entry.name.startsWith('.')) {
844
+ results.push(...this.walkDir(full, fs, path));
845
+ } else if (entry.isFile()) {
846
+ results.push(full);
847
+ }
848
+ }
849
+ } catch { /* not accessible */ }
850
+ return results;
851
+ }
852
+ }
853
+ ```
854
+
855
+ - [ ] **Step 3: Run tests, commit**
856
+
857
+ Run: `npx vitest run tests/lib/cortex/signals/adapters/document.test.ts`
858
+
859
+ ```bash
860
+ git commit -m "feat(cortex): add document signal adapter"
861
+ ```
862
+
863
+ ---
864
+
865
+ ## Chunk 3: Integration and Barrel Export
866
+
867
+ ### Task 6: Barrel export and CortexInstance integration
868
+
869
+ **Files:**
870
+ - Create: `src/lib/cortex/signals/index.ts`
871
+ - Modify: `src/lib/cortex/index.ts`
872
+
873
+ - [ ] **Step 1: Create barrel export**
874
+
875
+ ```typescript
876
+ // src/lib/cortex/signals/index.ts
877
+ export { SignalPipeline } from './pipeline';
878
+ export type { SignalPipelineDeps } from './pipeline';
879
+ export { ConversationAdapter } from './adapters/conversation';
880
+ export { GitAdapter, parseGitLog } from './adapters/git';
881
+ export type { GitLogEntry } from './adapters/git';
882
+ export { DocumentAdapter, parseDocument, classifyDocument } from './adapters/document';
883
+ export type { DocumentInput } from './adapters/document';
884
+ export type { SignalEnvelope, SignalAdapter, IngestResult, EdgeUpdate } from './types';
885
+ ```
886
+
887
+ - [ ] **Step 2: Add SignalPipeline to CortexInstance**
888
+
889
+ Read `src/lib/cortex/index.ts`. Add:
890
+
891
+ 1. Import: `import { SignalPipeline } from './signals/pipeline';`
892
+ 2. Add `signalPipeline?: SignalPipeline` to CortexInstance interface
893
+ 3. In getCortex(), after graph/resolver initialization:
894
+
895
+ ```typescript
896
+ const signalPipeline = new SignalPipeline({ store, embedding, graph, resolver });
897
+ ```
898
+
899
+ 4. Include in instance object.
900
+
901
+ - [ ] **Step 3: Run full test suite**
902
+
903
+ Run: `npx vitest run tests/lib/cortex/`
904
+
905
+ - [ ] **Step 4: Commit**
906
+
907
+ ```bash
908
+ git add src/lib/cortex/signals/index.ts src/lib/cortex/index.ts
909
+ git commit -m "feat(cortex): add signal module barrel export and CortexInstance integration"
910
+ ```
911
+
912
+ ---
913
+
914
+ ## Summary
915
+
916
+ | Task | Component | Tests | Status |
917
+ |------|-----------|-------|--------|
918
+ | 1 | Signal types | — | |
919
+ | 2 | Unified SignalPipeline | 8 | |
920
+ | 3 | Conversation adapter | — | |
921
+ | 4 | Git history adapter | 5 | |
922
+ | 5 | Document adapter | 6 | |
923
+ | 6 | Barrel export + integration | regression | |
924
+
925
+ **Total: 6 tasks, ~19 new tests, 3 chunks**
926
+
927
+ **Deferred adapters** (require external APIs/webhooks — implement when infrastructure is ready):
928
+ - PR Review adapter (GitHub API)
929
+ - Test Signal adapter (CI pipeline webhook)
930
+ - Deployment adapter (deploy system webhook)
931
+ - Behavioral Inference adapter (daily cron analyzing accumulated signals)
932
+
933
+ Each deferred adapter = implement `SignalAdapter` interface + test, zero changes to SignalPipeline.