@jlongo78/agent-spaces 0.9.6 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (917) hide show
  1. package/.next/standalone/.claude/settings.local.json +68 -0
  2. package/.next/standalone/.claude/spaces-env.json +1 -0
  3. package/.next/standalone/.next/BUILD_ID +1 -1
  4. package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
  5. package/.next/standalone/.next/build-manifest.json +2 -2
  6. package/.next/standalone/.next/prerender-manifest.json +3 -3
  7. package/.next/standalone/.next/required-server-files.json +19 -19
  8. package/.next/standalone/.next/routes-manifest.json +6 -0
  9. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/(desktop)/cortex/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
  14. package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
  24. package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  26. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  27. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  28. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  29. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  30. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  31. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  32. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  33. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  34. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  35. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  36. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  37. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  38. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  39. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  40. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  41. package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
  42. package/.next/standalone/.next/server/app/admin/analytics.rsc +2 -2
  43. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +1 -1
  44. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
  45. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  46. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  47. package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +2 -2
  48. package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
  49. package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +2 -2
  50. package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
  51. package/.next/standalone/.next/server/app/admin/users.html +1 -1
  52. package/.next/standalone/.next/server/app/admin/users.rsc +2 -2
  53. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +1 -1
  54. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
  55. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  56. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  57. package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
  59. package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +2 -2
  60. package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
  61. package/.next/standalone/.next/server/app/analytics.html +1 -1
  62. package/.next/standalone/.next/server/app/analytics.rsc +2 -2
  63. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +1 -1
  64. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
  65. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  66. package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +2 -2
  67. package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
  68. package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +2 -2
  69. package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  70. package/.next/standalone/.next/server/app/api/analytics/overview/route.js +1 -1
  71. package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
  72. package/.next/standalone/.next/server/app/api/benchmark/lobes/route.js +1 -1
  73. package/.next/standalone/.next/server/app/api/benchmark/lobes/route.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/api/benchmark/run/route.js +1 -1
  75. package/.next/standalone/.next/server/app/api/benchmark/run/route.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route.js +1 -1
  77. package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/api/benchmark/runs/route.js +1 -1
  79. package/.next/standalone/.next/server/app/api/benchmark/runs/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/benchmark/status/route.js +1 -1
  81. package/.next/standalone/.next/server/app/api/benchmark/status/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/bulk/route.js +1 -1
  83. package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/api/config/route.js +1 -1
  85. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  86. package/.next/standalone/.next/server/app/api/cortex/context/route.js +1 -1
  87. package/.next/standalone/.next/server/app/api/cortex/context/route.js.nft.json +1 -1
  88. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js +1 -1
  89. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js +1 -1
  91. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js +1 -1
  93. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js +1 -1
  95. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js +1 -1
  97. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/api/cortex/export/route.js +1 -1
  99. package/.next/standalone/.next/server/app/api/cortex/export/route.js.nft.json +1 -1
  100. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js +1 -1
  101. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js.nft.json +1 -1
  102. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js +1 -1
  103. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js +1 -1
  105. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js +1 -1
  107. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js.nft.json +1 -1
  108. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js +1 -1
  109. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js.nft.json +1 -1
  110. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js +1 -1
  111. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js +1 -1
  113. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js +1 -1
  115. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js.nft.json +1 -1
  116. package/.next/standalone/.next/server/app/api/cortex/import/route.js +1 -1
  117. package/.next/standalone/.next/server/app/api/cortex/import/route.js.nft.json +1 -1
  118. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js +1 -1
  119. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js +1 -1
  121. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js.nft.json +1 -1
  122. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js +1 -1
  123. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js +1 -1
  125. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js.nft.json +1 -1
  126. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js +1 -1
  127. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js.nft.json +1 -1
  128. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js +1 -1
  129. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js.nft.json +1 -1
  130. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js +1 -1
  131. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js.nft.json +1 -1
  132. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js +1 -1
  133. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js.nft.json +1 -1
  134. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js +1 -1
  135. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.nft.json +1 -1
  136. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js +1 -1
  137. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.nft.json +1 -1
  138. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js +1 -1
  139. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js.nft.json +1 -1
  140. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js +1 -1
  141. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js.nft.json +1 -1
  142. package/.next/standalone/.next/server/app/api/cortex/search/route.js +1 -1
  143. package/.next/standalone/.next/server/app/api/cortex/search/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/cortex/settings/route.js +1 -1
  145. package/.next/standalone/.next/server/app/api/cortex/settings/route.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/api/cortex/status/route.js +1 -1
  147. package/.next/standalone/.next/server/app/api/cortex/status/route.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js +1 -1
  149. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/api/cortex/usage/route.js +1 -1
  151. package/.next/standalone/.next/server/app/api/cortex/usage/route.js.nft.json +1 -1
  152. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js +1 -1
  153. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js.nft.json +1 -1
  154. package/.next/standalone/.next/server/app/api/events/route.js +1 -1
  155. package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
  156. package/.next/standalone/.next/server/app/api/files/route.js +1 -1
  157. package/.next/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  158. package/.next/standalone/.next/server/app/api/folders/route.js +1 -1
  159. package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
  160. package/.next/standalone/.next/server/app/api/network/handshake/route.js +1 -1
  161. package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
  162. package/.next/standalone/.next/server/app/api/network/panes/[id]/route.js +1 -1
  163. package/.next/standalone/.next/server/app/api/network/panes/[id]/route.js.nft.json +1 -1
  164. package/.next/standalone/.next/server/app/api/network/panes/route.js +1 -1
  165. package/.next/standalone/.next/server/app/api/network/panes/route.js.nft.json +1 -1
  166. package/.next/standalone/.next/server/app/api/network/projects/route.js +1 -1
  167. package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
  168. package/.next/standalone/.next/server/app/api/network/search/route.js +1 -1
  169. package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
  170. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js +1 -1
  171. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
  172. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js +1 -1
  173. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
  174. package/.next/standalone/.next/server/app/api/network/sessions/route.js +1 -1
  175. package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
  176. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js +1 -1
  177. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
  178. package/.next/standalone/.next/server/app/api/network/workspaces/route.js +1 -1
  179. package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
  180. package/.next/standalone/.next/server/app/api/panes/[id]/diff/route.js +1 -1
  181. package/.next/standalone/.next/server/app/api/panes/[id]/diff/route.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/app/api/panes/[id]/route.js +1 -1
  183. package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
  184. package/.next/standalone/.next/server/app/api/panes/route.js +1 -1
  185. package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
  186. package/.next/standalone/.next/server/app/api/projects/route.js +1 -1
  187. package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  188. package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/[...path]/route.js +1 -1
  189. package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/[...path]/route.js.nft.json +1 -1
  190. package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/status/route.js +1 -1
  191. package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/status/route.js.nft.json +1 -1
  192. package/.next/standalone/.next/server/app/api/search/route.js +2 -2
  193. package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  194. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js +1 -1
  195. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
  196. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js +1 -1
  197. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
  198. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js +1 -1
  199. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  200. package/.next/standalone/.next/server/app/api/sessions/route.js +2 -2
  201. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  202. package/.next/standalone/.next/server/app/api/sync/route.js +1 -1
  203. package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
  204. package/.next/standalone/.next/server/app/api/tags/route.js +1 -1
  205. package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
  206. package/.next/standalone/.next/server/app/api/tier/route.js +1 -1
  207. package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
  208. package/.next/standalone/.next/server/app/api/whisper/config/route.js +1 -1
  209. package/.next/standalone/.next/server/app/api/whisper/config/route.js.nft.json +1 -1
  210. package/.next/standalone/.next/server/app/api/whisper/route.js.nft.json +1 -1
  211. package/.next/standalone/.next/server/app/api/wizard/chart/route/app-paths-manifest.json +3 -0
  212. package/.next/standalone/.next/server/app/api/wizard/chart/route/build-manifest.json +11 -0
  213. package/.next/standalone/.next/server/app/api/wizard/chart/route/server-reference-manifest.json +4 -0
  214. package/.next/standalone/.next/server/app/api/wizard/chart/route.js +7 -0
  215. package/.next/standalone/.next/server/app/api/wizard/chart/route.js.map +5 -0
  216. package/.next/standalone/.next/server/app/api/wizard/chart/route.js.nft.json +1 -0
  217. package/.next/standalone/.next/server/app/api/wizard/chart/route_client-reference-manifest.js +2 -0
  218. package/.next/standalone/.next/server/app/api/wizard/chat/route.js +1 -1
  219. package/.next/standalone/.next/server/app/api/wizard/chat/route.js.nft.json +1 -1
  220. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js +1 -1
  221. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
  222. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js +1 -1
  223. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
  224. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js +1 -1
  225. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
  226. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js +1 -1
  227. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
  228. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js +1 -1
  229. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
  230. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js +1 -1
  231. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
  232. package/.next/standalone/.next/server/app/api/workspaces/route.js +2 -2
  233. package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  234. package/.next/standalone/.next/server/app/cortex.html +1 -1
  235. package/.next/standalone/.next/server/app/cortex.rsc +3 -3
  236. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex/__PAGE__.segment.rsc +2 -2
  237. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex.segment.rsc +1 -1
  238. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  239. package/.next/standalone/.next/server/app/cortex.segments/_full.segment.rsc +3 -3
  240. package/.next/standalone/.next/server/app/cortex.segments/_head.segment.rsc +1 -1
  241. package/.next/standalone/.next/server/app/cortex.segments/_index.segment.rsc +2 -2
  242. package/.next/standalone/.next/server/app/cortex.segments/_tree.segment.rsc +2 -2
  243. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  244. package/.next/standalone/.next/server/app/login.html +1 -1
  245. package/.next/standalone/.next/server/app/login.rsc +2 -2
  246. package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
  247. package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
  248. package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +2 -2
  249. package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  250. package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  251. package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
  252. package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
  253. package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
  254. package/.next/standalone/.next/server/app/m/projects.html +1 -1
  255. package/.next/standalone/.next/server/app/m/projects.rsc +2 -2
  256. package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +2 -2
  257. package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
  258. package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +2 -2
  259. package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
  260. package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +1 -1
  261. package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
  262. package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +1 -1
  263. package/.next/standalone/.next/server/app/m/sessions/[id]/page.js.nft.json +1 -1
  264. package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
  265. package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
  266. package/.next/standalone/.next/server/app/m/sessions.html +1 -1
  267. package/.next/standalone/.next/server/app/m/sessions.rsc +2 -2
  268. package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +2 -2
  269. package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
  270. package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +2 -2
  271. package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
  272. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +1 -1
  273. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
  274. package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +1 -1
  275. package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
  276. package/.next/standalone/.next/server/app/m/settings.html +1 -1
  277. package/.next/standalone/.next/server/app/m/settings.rsc +2 -2
  278. package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +2 -2
  279. package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
  280. package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +2 -2
  281. package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
  282. package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +1 -1
  283. package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
  284. package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +1 -1
  285. package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
  286. package/.next/standalone/.next/server/app/m/terminal.html +1 -1
  287. package/.next/standalone/.next/server/app/m/terminal.rsc +3 -3
  288. package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +3 -3
  289. package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
  290. package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +2 -2
  291. package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
  292. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
  293. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
  294. package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +1 -1
  295. package/.next/standalone/.next/server/app/m.html +1 -1
  296. package/.next/standalone/.next/server/app/m.rsc +2 -2
  297. package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +2 -2
  298. package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
  299. package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +2 -2
  300. package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
  301. package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +1 -1
  302. package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +1 -1
  303. package/.next/standalone/.next/server/app/network.html +1 -1
  304. package/.next/standalone/.next/server/app/network.rsc +2 -2
  305. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +1 -1
  306. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
  307. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  308. package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +2 -2
  309. package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
  310. package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +2 -2
  311. package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
  312. package/.next/standalone/.next/server/app/projects.html +1 -1
  313. package/.next/standalone/.next/server/app/projects.rsc +2 -2
  314. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +1 -1
  315. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
  316. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  317. package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +2 -2
  318. package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  319. package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +2 -2
  320. package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  321. package/.next/standalone/.next/server/app/sessions.html +1 -1
  322. package/.next/standalone/.next/server/app/sessions.rsc +2 -2
  323. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +1 -1
  324. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
  325. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  326. package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +2 -2
  327. package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
  328. package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +2 -2
  329. package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
  330. package/.next/standalone/.next/server/app/settings.html +1 -1
  331. package/.next/standalone/.next/server/app/settings.rsc +2 -2
  332. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +1 -1
  333. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
  334. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  335. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +2 -2
  336. package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  337. package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  338. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  339. package/.next/standalone/.next/server/app/terminal.html +1 -1
  340. package/.next/standalone/.next/server/app/terminal.rsc +3 -3
  341. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
  342. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
  343. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  344. package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +3 -3
  345. package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
  346. package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +2 -2
  347. package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
  348. package/.next/standalone/.next/server/app/vr/page/react-loadable-manifest.json +1 -1
  349. package/.next/standalone/.next/server/app/vr/page_client-reference-manifest.js +1 -1
  350. package/.next/standalone/.next/server/app/vr.html +1 -1
  351. package/.next/standalone/.next/server/app/vr.rsc +3 -3
  352. package/.next/standalone/.next/server/app/vr.segments/_full.segment.rsc +3 -3
  353. package/.next/standalone/.next/server/app/vr.segments/_head.segment.rsc +1 -1
  354. package/.next/standalone/.next/server/app/vr.segments/_index.segment.rsc +2 -2
  355. package/.next/standalone/.next/server/app/vr.segments/_tree.segment.rsc +2 -2
  356. package/.next/standalone/.next/server/app/vr.segments/vr/__PAGE__.segment.rsc +2 -2
  357. package/.next/standalone/.next/server/app/vr.segments/vr.segment.rsc +1 -1
  358. package/.next/standalone/.next/server/app/workspaces.html +1 -1
  359. package/.next/standalone/.next/server/app/workspaces.rsc +2 -2
  360. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +1 -1
  361. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
  362. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
  363. package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +2 -2
  364. package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
  365. package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +2 -2
  366. package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
  367. package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00e90fc6._.js +98 -0
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01ab8675._.js +98 -0
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03974f05._.js +98 -0
  371. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__bb331da9._.js → [root-of-the-server]__046c9b91._.js} +3 -3
  372. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04ae6bf0._.js +98 -0
  373. package/.next/standalone/.next/server/chunks/[root-of-the-server]__056fa416._.js +1 -1
  374. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ac4ea3f._.js +3 -0
  375. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b8e64cb._.js +98 -0
  376. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__d95165f0._.js → [root-of-the-server]__0facd39e._.js} +3 -3
  377. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10bc76a3._.js +3 -0
  378. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__9d68157b._.js → [root-of-the-server]__115f3934._.js} +3 -3
  379. package/.next/standalone/.next/server/chunks/[root-of-the-server]__11f155f1._.js +3 -0
  380. package/.next/standalone/.next/server/chunks/[root-of-the-server]__160e7c73._.js +22 -33
  381. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__91e23c96._.js → [root-of-the-server]__17a3b966._.js} +3 -3
  382. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__277d9445._.js → [root-of-the-server]__17d3a2b2._.js} +3 -3
  383. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a86c055._.js +98 -0
  384. package/.next/standalone/.next/server/chunks/[root-of-the-server]__20b5e9c4._.js +3 -0
  385. package/.next/standalone/.next/server/chunks/[root-of-the-server]__28d6fbd8._.js +98 -0
  386. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__04f04898._.js → [root-of-the-server]__2a3f866b._.js} +2 -2
  387. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__a95bb38b._.js → [root-of-the-server]__316617e7._.js} +2 -2
  388. package/.next/standalone/.next/server/chunks/[root-of-the-server]__32ad8f71._.js +98 -0
  389. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__6fe5e6c8._.js → [root-of-the-server]__35457394._.js} +2 -2
  390. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1f054c65._.js → [root-of-the-server]__35de78e6._.js} +3 -3
  391. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3685ffcb._.js +98 -0
  392. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__614458b7._.js → [root-of-the-server]__38954988._.js} +3 -3
  393. package/.next/standalone/.next/server/chunks/[root-of-the-server]__426ad936._.js +106 -0
  394. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4985c034._.js +98 -0
  395. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c6ce9ed._.js +98 -0
  396. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5cebe58a._.js +98 -0
  397. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5d5e4789._.js +98 -0
  398. package/.next/standalone/.next/server/chunks/[root-of-the-server]__65676930._.js +3 -0
  399. package/.next/standalone/.next/server/chunks/[root-of-the-server]__67cab326._.js +58 -0
  400. package/.next/standalone/.next/server/chunks/[root-of-the-server]__698c6f01._.js +98 -0
  401. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c64af29._.js +131 -0
  402. package/.next/standalone/.next/server/chunks/[root-of-the-server]__73aed9f5._.js +98 -0
  403. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__ac84b704._.js → [root-of-the-server]__79b6a9bb._.js} +3 -3
  404. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__e56abacf._.js → [root-of-the-server]__7db704c6._.js} +4 -4
  405. package/.next/standalone/.next/server/chunks/[root-of-the-server]__812ca02b._.js +98 -0
  406. package/.next/standalone/.next/server/chunks/[root-of-the-server]__821f50fa._.js +98 -0
  407. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8716b86e._.js +98 -0
  408. package/.next/standalone/.next/server/chunks/[root-of-the-server]__884ef754._.js +98 -0
  409. package/.next/standalone/.next/server/chunks/[root-of-the-server]__88cdbd68._.js +98 -0
  410. package/.next/standalone/.next/server/chunks/[root-of-the-server]__89d9aba9._.js +98 -0
  411. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8d536cb5._.js +98 -0
  412. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8df8c5d1._.js +98 -0
  413. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2d7a454e._.js → [root-of-the-server]__8f2ccc41._.js} +3 -3
  414. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2a2c5fc5._.js → [root-of-the-server]__95c9d682._.js} +4 -4
  415. package/.next/standalone/.next/server/chunks/[root-of-the-server]__9e5d7774._.js +98 -0
  416. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__cc6e2885._.js → [root-of-the-server]__9edcff87._.js} +2 -2
  417. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a049dfc2._.js +98 -0
  418. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a5b4bb9a._.js +98 -0
  419. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__929ea03a._.js → [root-of-the-server]__a83262a1._.js} +2 -2
  420. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9cd1240._.js +98 -0
  421. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9d7f822._.js +98 -0
  422. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ad08c221._.js +98 -0
  423. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ad585f2f._.js +98 -0
  424. package/.next/standalone/.next/server/chunks/[root-of-the-server]__afcb8f7d._.js +98 -0
  425. package/.next/standalone/.next/server/chunks/[root-of-the-server]__bc250d43._.js +98 -0
  426. package/.next/standalone/.next/server/chunks/[root-of-the-server]__bce2a6e7._.js +98 -0
  427. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c011bf91._.js +98 -0
  428. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c0ac2895._.js +3 -0
  429. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c130a00c._.js +1 -1
  430. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c37d6380._.js +3 -0
  431. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cae392eb._.js +98 -0
  432. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cc2616bb._.js +3 -3
  433. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d501fa9b._.js +98 -0
  434. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d59c6c15._.js +98 -0
  435. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d5c1db32._.js +98 -0
  436. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d5d92527._.js +1 -1
  437. package/.next/standalone/.next/server/chunks/[root-of-the-server]__dba60c86._.js +98 -0
  438. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__2384f98e._.js → [root-of-the-server]__de14b9ae._.js} +3 -3
  439. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e10643d1._.js +98 -0
  440. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__00fdfbda._.js → [root-of-the-server]__e2a996e5._.js} +2 -2
  441. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__4d903941._.js → [root-of-the-server]__e3477417._.js} +3 -3
  442. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__32dc5513._.js → [root-of-the-server]__e4db362e._.js} +2 -2
  443. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__49e42a3a._.js → [root-of-the-server]__e4e70b86._.js} +3 -3
  444. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__ac39ecc7._.js → [root-of-the-server]__e54925af._.js} +3 -3
  445. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e8edc5b0._.js +98 -0
  446. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__eafd040b._.js → [root-of-the-server]__eab4d83b._.js} +2 -2
  447. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ead29015._.js +1 -1
  448. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__194955d4._.js → [root-of-the-server]__f056fd83._.js} +3 -3
  449. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f0e99572._.js +98 -0
  450. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fe1e16d0._.js +98 -0
  451. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ff9cd277._.js +98 -0
  452. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ffaea2ce._.js +98 -0
  453. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wizard_chart_route_actions_888e2ec1.js +3 -0
  454. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__2cffc362._.js +3 -0
  455. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__f1050870._.js → [root-of-the-server]__47c97637._.js} +2 -2
  456. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
  457. package/.next/standalone/.next/server/chunks/ssr/_17b946fd._.js +3 -0
  458. package/.next/standalone/.next/server/chunks/ssr/_2a1d79e7._.js +1 -1
  459. package/.next/standalone/.next/server/chunks/ssr/_5c3c4cfa._.js +7 -5
  460. package/.next/standalone/.next/server/chunks/ssr/_ba432382._.js +7 -5
  461. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_cortex_page_tsx_0f33d8b3._.js +1 -1
  462. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_terminal_page_tsx_de5e8d85._.js +4 -4
  463. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__90eeddae._.js +1 -1
  464. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  465. package/.next/standalone/.next/server/pages/404.html +1 -1
  466. package/.next/standalone/.next/server/pages/500.html +2 -2
  467. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  468. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  469. package/.next/standalone/.next/static/chunks/0852575eb90c1e8d.js +85 -0
  470. package/.next/standalone/.next/static/chunks/{74d0ac0b1d0a1b79.js → 10b00b4f66102dcf.js} +1 -1
  471. package/.next/standalone/.next/static/chunks/{16eb77953dee9ea3.js → 19c71a8376c23c58.js} +1 -1
  472. package/.next/standalone/.next/static/chunks/2b769d1597e4fc1c.css +3 -0
  473. package/.next/standalone/.next/static/chunks/{3e91fc608659c524.js → 350271fe79509caf.js} +1 -1
  474. package/.next/standalone/.next/static/chunks/{70423c7afd8abf5f.js → 597847c22200c212.js} +1 -1
  475. package/.next/standalone/.next/static/chunks/{fb0abd1933b2b2e1.js → 7f6a14f1849fa94d.js} +1 -1
  476. package/.next/standalone/.next/static/chunks/{7ecd9bbb0ce4d68a.js → b7c8fe9b7275a84f.js} +1 -1
  477. package/.next/standalone/.next/static/chunks/{6245135a7afb8c7b.js → c9b10fc55516d142.js} +8 -6
  478. package/.next/standalone/.next/static/chunks/d0065f48eab94944.js +1 -0
  479. package/.next/standalone/.next/static/chunks/{180c1b9ff31b979f.js → f7b34c807badf95d.js} +8 -6
  480. package/.next/standalone/.spaces/cortex-context.md +50 -144
  481. package/.next/standalone/LICENSE +661 -661
  482. package/.next/standalone/NOTICE +5 -5
  483. package/.next/standalone/README.md +131 -131
  484. package/.next/standalone/bin/cortex-hook.js +79 -79
  485. package/.next/standalone/bin/cortex-hook.sh +62 -62
  486. package/.next/standalone/bin/cortex-learn-hook.js +138 -138
  487. package/.next/standalone/bin/cortex-mcp.js +60 -60
  488. package/.next/standalone/bin/cortex-pi-extension.ts +170 -170
  489. package/.next/standalone/bin/fix-standalone-externals.js +79 -79
  490. package/.next/standalone/bin/lib/auto-setup.js +110 -110
  491. package/.next/standalone/bin/mdns-service.js +171 -171
  492. package/.next/standalone/bin/postinstall.js +35 -35
  493. package/.next/standalone/bin/setup-admin.js +195 -195
  494. package/.next/standalone/bin/spaces-dev.js +247 -247
  495. package/.next/standalone/bin/spaces-install.js +660 -660
  496. package/.next/standalone/bin/spaces-postinstall.js +50 -50
  497. package/.next/standalone/bin/spaces-reset-totp.js +50 -50
  498. package/.next/standalone/bin/spaces-service.js +1046 -1046
  499. package/.next/standalone/bin/spaces-setup.js +253 -253
  500. package/.next/standalone/bin/spaces.js +808 -805
  501. package/.next/standalone/bin/ssh-auth-keys.sh +68 -68
  502. package/.next/standalone/bin/terminal-server.js +2819 -2781
  503. package/.next/standalone/cortex-hook-debug.log +57 -23
  504. package/.next/standalone/docker-compose.yml +28 -28
  505. package/.next/standalone/docs/architecture.md +387 -387
  506. package/.next/standalone/docs/cortex-integration-reference.md +268 -268
  507. package/.next/standalone/docs/cortex.md +293 -293
  508. package/.next/standalone/docs/getting-started.md +96 -96
  509. package/.next/standalone/docs/plans/2026-02-24-multi-agent-sessions-design.md +133 -133
  510. package/.next/standalone/docs/plans/2026-02-24-multi-agent-sessions-plan.md +959 -959
  511. package/.next/standalone/docs/plans/2026-03-02-security-audit.md +229 -229
  512. package/.next/standalone/docs/plans/2026-03-07-service-command-design.md +146 -146
  513. package/.next/standalone/docs/plans/2026-03-07-service-command-plan.md +254 -254
  514. package/.next/standalone/docs/server-install.md +564 -564
  515. package/.next/standalone/docs/social-card.html +150 -150
  516. package/.next/standalone/docs/superpowers/plans/2026-03-12-spaces-cortex.md +5270 -5270
  517. package/.next/standalone/docs/superpowers/plans/2026-03-13-cortex-wiring.md +1387 -1387
  518. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-entity-graph.md +1923 -1923
  519. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-knowledge-evolution.md +1113 -1113
  520. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-boundary-engine.md +853 -853
  521. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-context-engine.md +1274 -1274
  522. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-signal-ingestion.md +933 -933
  523. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-lobes.md +1080 -1080
  524. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-gravity-system.md +768 -768
  525. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-ui.md +1108 -1108
  526. package/.next/standalone/docs/superpowers/plans/2026-03-18-cortex-ui-integration.md +1846 -1846
  527. package/.next/standalone/docs/superpowers/plans/2026-03-19-vr-phase1-shell.md +1639 -1639
  528. package/.next/standalone/docs/superpowers/plans/2026-03-27-dockview-pane-layout.md +98 -98
  529. package/.next/standalone/docs/superpowers/specs/2026-03-11-universe-view-design.md +320 -320
  530. package/.next/standalone/docs/superpowers/specs/2026-03-12-spaces-brain-design.md +720 -720
  531. package/.next/standalone/docs/superpowers/specs/2026-03-13-cortex-wiring-design.md +268 -268
  532. package/.next/standalone/docs/superpowers/specs/2026-03-14-cortex-v2-design.md +623 -623
  533. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-lobes-design.md +263 -263
  534. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md +240 -240
  535. package/.next/standalone/docs/superpowers/specs/2026-03-16-pane-ux-design.md +77 -77
  536. package/.next/standalone/docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md +341 -341
  537. package/.next/standalone/docs/superpowers/specs/2026-03-19-vr-phase1-shell-design.md +288 -288
  538. package/.next/standalone/docs/superpowers/specs/2026-03-27-pane-diff-review-and-project-wizard-design.md +322 -322
  539. package/.next/standalone/docs/tiers.md +104 -104
  540. package/.next/standalone/eslint.config.mjs +18 -18
  541. package/.next/standalone/next.config.ts +20 -20
  542. package/.next/standalone/nginx.conf +53 -53
  543. package/.next/standalone/node_modules/@img/sharp-win32-x64/lib/sharp-win32-x64.node +0 -0
  544. package/.next/standalone/node_modules/@img/{sharp-linux-x64 → sharp-win32-x64}/package.json +39 -46
  545. package/.next/standalone/package-lock.json +14985 -14986
  546. package/.next/standalone/package.json +111 -111
  547. package/.next/standalone/postcss.config.mjs +7 -7
  548. package/.next/standalone/scripts/rebuild.cmd +65 -65
  549. package/.next/standalone/scripts/rebuild.sh +59 -59
  550. package/.next/standalone/server.js +1 -1
  551. package/.next/standalone/src/app/(desktop)/admin/analytics/page.tsx +266 -266
  552. package/.next/standalone/src/app/(desktop)/admin/users/page.tsx +399 -399
  553. package/.next/standalone/src/app/(desktop)/analytics/page.tsx +166 -166
  554. package/.next/standalone/src/app/(desktop)/cortex/page.tsx +81 -81
  555. package/.next/standalone/src/app/(desktop)/dashboard-client.tsx +56 -56
  556. package/.next/standalone/src/app/(desktop)/layout.tsx +18 -18
  557. package/.next/standalone/src/app/(desktop)/network/page.tsx +137 -137
  558. package/.next/standalone/src/app/(desktop)/page.tsx +17 -17
  559. package/.next/standalone/src/app/(desktop)/projects/page.tsx +68 -68
  560. package/.next/standalone/src/app/(desktop)/sessions/[id]/page.tsx +519 -519
  561. package/.next/standalone/src/app/(desktop)/sessions/page.tsx +145 -145
  562. package/.next/standalone/src/app/(desktop)/settings/page.tsx +446 -446
  563. package/.next/standalone/src/app/(desktop)/terminal/layout.tsx +7 -7
  564. package/.next/standalone/src/app/(desktop)/terminal/page.tsx +1330 -1291
  565. package/.next/standalone/src/app/(desktop)/terminal/pane/[id]/page.tsx +211 -211
  566. package/.next/standalone/src/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.tsx +252 -252
  567. package/.next/standalone/src/app/(desktop)/workspaces/page.tsx +12 -12
  568. package/.next/standalone/src/app/api/admin/analytics/route.ts +10 -10
  569. package/.next/standalone/src/app/api/admin/users/[id]/route.ts +20 -20
  570. package/.next/standalone/src/app/api/admin/users/route.ts +15 -15
  571. package/.next/standalone/src/app/api/analytics/overview/route.ts +80 -80
  572. package/.next/standalone/src/app/api/auth/login/route.ts +10 -10
  573. package/.next/standalone/src/app/api/auth/logout/route.ts +9 -9
  574. package/.next/standalone/src/app/api/auth/me/route.ts +22 -22
  575. package/.next/standalone/src/app/api/auth/totp/setup/route.ts +10 -10
  576. package/.next/standalone/src/app/api/auth/totp/status/route.ts +10 -10
  577. package/.next/standalone/src/app/api/auth/totp/verify/route.ts +10 -10
  578. package/.next/standalone/src/app/api/benchmark/lobes/route.ts +16 -16
  579. package/.next/standalone/src/app/api/benchmark/run/route.ts +113 -92
  580. package/.next/standalone/src/app/api/benchmark/runs/[id]/route.ts +26 -26
  581. package/.next/standalone/src/app/api/benchmark/runs/route.ts +16 -16
  582. package/.next/standalone/src/app/api/benchmark/status/route.ts +35 -35
  583. package/.next/standalone/src/app/api/bulk/route.ts +34 -34
  584. package/.next/standalone/src/app/api/chat/route.ts +85 -85
  585. package/.next/standalone/src/app/api/config/route.ts +30 -30
  586. package/.next/standalone/src/app/api/cortex/context/route.ts +78 -78
  587. package/.next/standalone/src/app/api/cortex/curation/assess/route.ts +27 -27
  588. package/.next/standalone/src/app/api/cortex/curation/publish/route.ts +23 -23
  589. package/.next/standalone/src/app/api/cortex/curation/refine/route.ts +23 -23
  590. package/.next/standalone/src/app/api/cortex/curation/review/route.ts +29 -29
  591. package/.next/standalone/src/app/api/cortex/curation/seed/route.ts +23 -23
  592. package/.next/standalone/src/app/api/cortex/export/route.ts +40 -40
  593. package/.next/standalone/src/app/api/cortex/federation/pending/route.ts +20 -20
  594. package/.next/standalone/src/app/api/cortex/federation/resolve/route.ts +43 -43
  595. package/.next/standalone/src/app/api/cortex/federation/search/route.ts +35 -35
  596. package/.next/standalone/src/app/api/cortex/federation/teach/route.ts +76 -76
  597. package/.next/standalone/src/app/api/cortex/graph/edges/route.ts +112 -112
  598. package/.next/standalone/src/app/api/cortex/graph/entities/[id]/route.ts +73 -73
  599. package/.next/standalone/src/app/api/cortex/graph/entities/route.ts +75 -75
  600. package/.next/standalone/src/app/api/cortex/graph/populate/route.ts +203 -203
  601. package/.next/standalone/src/app/api/cortex/import/route.ts +75 -75
  602. package/.next/standalone/src/app/api/cortex/import/status/route.ts +15 -15
  603. package/.next/standalone/src/app/api/cortex/ingest/bootstrap/route.ts +39 -39
  604. package/.next/standalone/src/app/api/cortex/ingest/status/route.ts +15 -15
  605. package/.next/standalone/src/app/api/cortex/knowledge/[id]/route.ts +91 -91
  606. package/.next/standalone/src/app/api/cortex/knowledge/route.ts +97 -97
  607. package/.next/standalone/src/app/api/cortex/lobes/[id]/route.ts +67 -67
  608. package/.next/standalone/src/app/api/cortex/lobes/route.ts +22 -22
  609. package/.next/standalone/src/app/api/cortex/lobes/share/route.ts +80 -80
  610. package/.next/standalone/src/app/api/cortex/marketplace/browse/route.ts +43 -43
  611. package/.next/standalone/src/app/api/cortex/marketplace/preview/route.ts +46 -46
  612. package/.next/standalone/src/app/api/cortex/mcp/call/route.ts +11 -11
  613. package/.next/standalone/src/app/api/cortex/mcp/tools/route.ts +8 -8
  614. package/.next/standalone/src/app/api/cortex/search/route.ts +57 -45
  615. package/.next/standalone/src/app/api/cortex/settings/route.ts +35 -35
  616. package/.next/standalone/src/app/api/cortex/status/route.ts +169 -169
  617. package/.next/standalone/src/app/api/cortex/timeline/route.ts +42 -42
  618. package/.next/standalone/src/app/api/cortex/usage/route.ts +31 -31
  619. package/.next/standalone/src/app/api/cortex/workspace/[id]/context/route.ts +41 -41
  620. package/.next/standalone/src/app/api/events/route.ts +40 -40
  621. package/.next/standalone/src/app/api/files/route.ts +187 -187
  622. package/.next/standalone/src/app/api/folders/route.ts +107 -97
  623. package/.next/standalone/src/app/api/network/connect-callback/route.ts +11 -11
  624. package/.next/standalone/src/app/api/network/connect-request/[id]/route.ts +11 -11
  625. package/.next/standalone/src/app/api/network/connect-request/route.ts +17 -17
  626. package/.next/standalone/src/app/api/network/discovered/route.ts +9 -9
  627. package/.next/standalone/src/app/api/network/handshake/route.ts +25 -25
  628. package/.next/standalone/src/app/api/network/health/route.ts +10 -10
  629. package/.next/standalone/src/app/api/network/identity/route.ts +15 -15
  630. package/.next/standalone/src/app/api/network/keys/[id]/route.ts +10 -10
  631. package/.next/standalone/src/app/api/network/keys/route.ts +15 -15
  632. package/.next/standalone/src/app/api/network/nodes/[id]/route.ts +15 -15
  633. package/.next/standalone/src/app/api/network/nodes/check/route.ts +9 -9
  634. package/.next/standalone/src/app/api/network/nodes/route.ts +15 -15
  635. package/.next/standalone/src/app/api/network/panes/[id]/route.ts +78 -62
  636. package/.next/standalone/src/app/api/network/panes/route.ts +61 -50
  637. package/.next/standalone/src/app/api/network/projects/route.ts +32 -25
  638. package/.next/standalone/src/app/api/network/proxy/[nodeId]/[...path]/route.ts +25 -25
  639. package/.next/standalone/src/app/api/network/search/route.ts +45 -38
  640. package/.next/standalone/src/app/api/network/sessions/[id]/messages/route.ts +43 -36
  641. package/.next/standalone/src/app/api/network/sessions/[id]/route.ts +41 -34
  642. package/.next/standalone/src/app/api/network/sessions/route.ts +50 -43
  643. package/.next/standalone/src/app/api/network/terminal/token/route.ts +10 -10
  644. package/.next/standalone/src/app/api/network/workspaces/[id]/route.ts +80 -71
  645. package/.next/standalone/src/app/api/network/workspaces/route.ts +87 -85
  646. package/.next/standalone/src/app/api/panes/[id]/diff/route.ts +121 -121
  647. package/.next/standalone/src/app/api/panes/[id]/route.ts +60 -60
  648. package/.next/standalone/src/app/api/panes/route.ts +39 -39
  649. package/.next/standalone/src/app/api/projects/route.ts +13 -13
  650. package/.next/standalone/src/app/api/proxy/models/[modelId]/[...path]/route.ts +80 -80
  651. package/.next/standalone/src/app/api/proxy/models/[modelId]/status/route.ts +33 -33
  652. package/.next/standalone/src/app/api/search/route.ts +47 -47
  653. package/.next/standalone/src/app/api/sessions/[id]/chat/route.ts +120 -120
  654. package/.next/standalone/src/app/api/sessions/[id]/messages/route.ts +34 -34
  655. package/.next/standalone/src/app/api/sessions/[id]/route.ts +73 -73
  656. package/.next/standalone/src/app/api/sessions/route.ts +64 -64
  657. package/.next/standalone/src/app/api/sync/route.ts +24 -24
  658. package/.next/standalone/src/app/api/tags/route.ts +35 -35
  659. package/.next/standalone/src/app/api/tier/route.ts +16 -16
  660. package/.next/standalone/src/app/api/updates/route.ts +65 -65
  661. package/.next/standalone/src/app/api/whisper/config/route.ts +50 -42
  662. package/.next/standalone/src/app/api/whisper/route.ts +91 -91
  663. package/.next/standalone/src/app/api/wizard/chart/route.ts +129 -0
  664. package/.next/standalone/src/app/api/wizard/chat/route.ts +113 -113
  665. package/.next/standalone/src/app/api/workspaces/[id]/context/[key]/route.ts +39 -39
  666. package/.next/standalone/src/app/api/workspaces/[id]/context/route.ts +28 -28
  667. package/.next/standalone/src/app/api/workspaces/[id]/messages/[msgId]/route.ts +17 -17
  668. package/.next/standalone/src/app/api/workspaces/[id]/messages/route.ts +39 -39
  669. package/.next/standalone/src/app/api/workspaces/[id]/route.ts +47 -47
  670. package/.next/standalone/src/app/api/workspaces/[id]/sessions/route.ts +62 -62
  671. package/.next/standalone/src/app/api/workspaces/route.ts +79 -79
  672. package/.next/standalone/src/app/globals.css +88 -88
  673. package/.next/standalone/src/app/layout.tsx +33 -33
  674. package/.next/standalone/src/app/login/layout.tsx +7 -7
  675. package/.next/standalone/src/app/login/page.tsx +315 -315
  676. package/.next/standalone/src/app/m/layout.tsx +16 -16
  677. package/.next/standalone/src/app/m/page.tsx +118 -118
  678. package/.next/standalone/src/app/m/projects/page.tsx +64 -64
  679. package/.next/standalone/src/app/m/sessions/[id]/page.tsx +168 -168
  680. package/.next/standalone/src/app/m/sessions/page.tsx +177 -177
  681. package/.next/standalone/src/app/m/settings/page.tsx +230 -230
  682. package/.next/standalone/src/app/m/terminal/page.tsx +413 -413
  683. package/.next/standalone/src/app/vr/page.tsx +21 -21
  684. package/.next/standalone/src/app/vr/vr-app.tsx +163 -163
  685. package/.next/standalone/src/app/vr/vr-controls.tsx +139 -139
  686. package/.next/standalone/src/app/vr/vr-door.tsx +82 -82
  687. package/.next/standalone/src/app/vr/vr-environment.tsx +71 -71
  688. package/.next/standalone/src/app/vr/vr-gaze.tsx +89 -89
  689. package/.next/standalone/src/app/vr/vr-layout.ts +49 -49
  690. package/.next/standalone/src/app/vr/vr-lobby.tsx +97 -97
  691. package/.next/standalone/src/app/vr/vr-pane.tsx +195 -195
  692. package/.next/standalone/src/app/vr/vr-room.tsx +79 -79
  693. package/.next/standalone/src/app/vr/vr-terminal.tsx +303 -303
  694. package/.next/standalone/src/components/auth/totp-gate.tsx +183 -183
  695. package/.next/standalone/src/components/bus/activity-panel.tsx +261 -261
  696. package/.next/standalone/src/components/common/color-picker.tsx +35 -35
  697. package/.next/standalone/src/components/common/dev-directory-picker.tsx +339 -339
  698. package/.next/standalone/src/components/common/folder-picker.tsx +200 -200
  699. package/.next/standalone/src/components/common/tag-picker.tsx +190 -190
  700. package/.next/standalone/src/components/common/workspace-picker.tsx +113 -113
  701. package/.next/standalone/src/components/cortex/benchmark-tab.tsx +894 -880
  702. package/.next/standalone/src/components/cortex/constants.ts +29 -29
  703. package/.next/standalone/src/components/cortex/cortex-dashboard.tsx +304 -304
  704. package/.next/standalone/src/components/cortex/cortex-indicator.tsx +44 -44
  705. package/.next/standalone/src/components/cortex/cortex-panel.tsx +140 -140
  706. package/.next/standalone/src/components/cortex/cortex-settings.tsx +280 -280
  707. package/.next/standalone/src/components/cortex/curation-tab.tsx +810 -810
  708. package/.next/standalone/src/components/cortex/entity-detail.tsx +101 -101
  709. package/.next/standalone/src/components/cortex/entity-graph.tsx +382 -382
  710. package/.next/standalone/src/components/cortex/import-dialog.tsx +212 -212
  711. package/.next/standalone/src/components/cortex/injection-badge.tsx +72 -72
  712. package/.next/standalone/src/components/cortex/knowledge-card.tsx +109 -109
  713. package/.next/standalone/src/components/cortex/knowledge-tab.tsx +158 -158
  714. package/.next/standalone/src/components/cortex/lobe-settings.tsx +215 -215
  715. package/.next/standalone/src/components/cortex/marketplace-card.tsx +126 -126
  716. package/.next/standalone/src/components/cortex/marketplace-tab.tsx +113 -113
  717. package/.next/standalone/src/components/dashboard/activity-chart.tsx +41 -41
  718. package/.next/standalone/src/components/dashboard/model-usage-chart.tsx +61 -61
  719. package/.next/standalone/src/components/dashboard/recent-sessions.tsx +68 -68
  720. package/.next/standalone/src/components/dashboard/stats-cards.tsx +36 -36
  721. package/.next/standalone/src/components/files/file-explorer.tsx +703 -703
  722. package/.next/standalone/src/components/layout/providers.tsx +38 -38
  723. package/.next/standalone/src/components/layout/sidebar.tsx +170 -170
  724. package/.next/standalone/src/components/layout/tier-provider.tsx +53 -53
  725. package/.next/standalone/src/components/layout/update-banner.tsx +92 -92
  726. package/.next/standalone/src/components/mobile/bottom-nav.tsx +46 -46
  727. package/.next/standalone/src/components/mobile/immersive-voice-button.tsx +123 -123
  728. package/.next/standalone/src/components/mobile/mobile-chat-input.tsx +244 -244
  729. package/.next/standalone/src/components/mobile/mobile-header.tsx +44 -44
  730. package/.next/standalone/src/components/mobile/mobile-session-card.tsx +56 -56
  731. package/.next/standalone/src/components/mobile/mobile-terminal-input.tsx +74 -74
  732. package/.next/standalone/src/components/mobile/mobile-terminal-pane.tsx +302 -302
  733. package/.next/standalone/src/components/mobile/mobile-terminal-toolbar.tsx +76 -76
  734. package/.next/standalone/src/components/mobile/pull-to-refresh.tsx +82 -82
  735. package/.next/standalone/src/components/mobile/voice-input.tsx +53 -53
  736. package/.next/standalone/src/components/network/api-key-list.tsx +190 -190
  737. package/.next/standalone/src/components/network/connection-requests.tsx +94 -94
  738. package/.next/standalone/src/components/network/node-add-dialog.tsx +131 -131
  739. package/.next/standalone/src/components/network/node-badge.tsx +26 -26
  740. package/.next/standalone/src/components/network/node-list.tsx +207 -207
  741. package/.next/standalone/src/components/network/node-selector.tsx +49 -49
  742. package/.next/standalone/src/components/sessions/session-filters.tsx +116 -116
  743. package/.next/standalone/src/components/sessions/session-list.tsx +485 -485
  744. package/.next/standalone/src/components/terminal/pane-diff-panel.tsx +179 -179
  745. package/.next/standalone/src/components/terminal/terminal-pane.tsx +1530 -1464
  746. package/.next/standalone/src/components/viewer/chat-input.tsx +275 -275
  747. package/.next/standalone/src/components/viewer/message-renderer.tsx +551 -551
  748. package/.next/standalone/src/components/wizard/chart-wizard.tsx +405 -0
  749. package/.next/standalone/src/components/wizard/project-wizard.tsx +153 -153
  750. package/.next/standalone/src/components/wizard/wizard-chat.tsx +99 -99
  751. package/.next/standalone/src/components/wizard/wizard-plan-summary.tsx +103 -103
  752. package/.next/standalone/src/components/wizard/wizard-review.tsx +225 -225
  753. package/.next/standalone/src/components/workspace/universe-cluster.tsx +131 -131
  754. package/.next/standalone/src/components/workspace/universe-orb.tsx +128 -128
  755. package/.next/standalone/src/components/workspace/universe-types.ts +22 -22
  756. package/.next/standalone/src/components/workspace/universe-utils.ts +11 -11
  757. package/.next/standalone/src/components/workspace/universe-view.tsx +397 -397
  758. package/.next/standalone/src/components/workspace/workspace-chooser.tsx +634 -634
  759. package/.next/standalone/src/hooks/use-benchmark.ts +72 -71
  760. package/.next/standalone/src/hooks/use-bus.ts +147 -147
  761. package/.next/standalone/src/hooks/use-idle-detection.ts +79 -79
  762. package/.next/standalone/src/hooks/use-network.ts +229 -229
  763. package/.next/standalone/src/hooks/use-sessions.ts +437 -437
  764. package/.next/standalone/src/hooks/use-speech-recognition.ts +114 -113
  765. package/.next/standalone/src/hooks/use-sse.ts +35 -35
  766. package/.next/standalone/src/hooks/use-tier.ts +39 -39
  767. package/.next/standalone/src/lib/agents.ts +97 -97
  768. package/.next/standalone/src/lib/aider/parser.ts +111 -111
  769. package/.next/standalone/src/lib/api.ts +19 -19
  770. package/.next/standalone/src/lib/auth.ts +47 -47
  771. package/.next/standalone/src/lib/claude/parser.ts +212 -212
  772. package/.next/standalone/src/lib/claude/stats.ts +204 -204
  773. package/.next/standalone/src/lib/codex/parser.test.ts +111 -111
  774. package/.next/standalone/src/lib/codex/parser.ts +287 -287
  775. package/.next/standalone/src/lib/config.ts +132 -132
  776. package/.next/standalone/src/lib/cortex/benchmark.ts +83 -67
  777. package/.next/standalone/src/lib/cortex/config.ts +42 -42
  778. package/.next/standalone/src/lib/cortex/debug.ts +10 -10
  779. package/.next/standalone/src/lib/cortex/distillation/usage-store.ts +18 -18
  780. package/.next/standalone/src/lib/cortex/graph/resolver.ts +10 -10
  781. package/.next/standalone/src/lib/cortex/graph/types.ts +22 -22
  782. package/.next/standalone/src/lib/cortex/index.ts +109 -56
  783. package/.next/standalone/src/lib/cortex/ingestion/bootstrap.ts +14 -14
  784. package/.next/standalone/src/lib/cortex/knowledge/compat.ts +14 -14
  785. package/.next/standalone/src/lib/cortex/knowledge/contradiction.ts +10 -10
  786. package/.next/standalone/src/lib/cortex/knowledge/types.ts +67 -67
  787. package/.next/standalone/src/lib/cortex/lobes/config.ts +16 -16
  788. package/.next/standalone/src/lib/cortex/lobes/resolver.ts +8 -8
  789. package/.next/standalone/src/lib/cortex/lobes/shares.ts +14 -14
  790. package/.next/standalone/src/lib/cortex/mcp/server.ts +12 -12
  791. package/.next/standalone/src/lib/cortex/portability/exporter.ts +6 -6
  792. package/.next/standalone/src/lib/cortex/portability/importer.ts +10 -10
  793. package/.next/standalone/src/lib/cortex/retrieval/context-engine.ts +10 -10
  794. package/.next/standalone/src/lib/cortex/types.ts +39 -39
  795. package/.next/standalone/src/lib/cost-calculator.ts +48 -48
  796. package/.next/standalone/src/lib/db/init.ts +71 -71
  797. package/.next/standalone/src/lib/db/queries.ts +740 -827
  798. package/.next/standalone/src/lib/db/schema.ts +206 -206
  799. package/.next/standalone/src/lib/events/sse.ts +36 -36
  800. package/.next/standalone/src/lib/forge/parser.ts +52 -52
  801. package/.next/standalone/src/lib/gemini/parser.ts +258 -258
  802. package/.next/standalone/src/lib/license.ts +56 -56
  803. package/.next/standalone/src/lib/pro.ts +31 -31
  804. package/.next/standalone/src/lib/shell-user.ts +101 -0
  805. package/.next/standalone/src/lib/sync/indexer.ts +504 -504
  806. package/.next/standalone/src/lib/sync/watcher.ts +64 -64
  807. package/.next/standalone/src/lib/teams.ts +31 -31
  808. package/.next/standalone/src/lib/telemetry.ts +75 -75
  809. package/.next/standalone/src/lib/terminal/server.ts +188 -188
  810. package/.next/standalone/src/lib/tier.ts +38 -38
  811. package/.next/standalone/src/lib/utils.ts +72 -72
  812. package/.next/standalone/src/lib/vms/manager.ts +121 -121
  813. package/.next/standalone/src/middleware.ts +133 -133
  814. package/.next/standalone/src/types/claude.ts +208 -208
  815. package/.next/standalone/src/types/network.ts +61 -61
  816. package/.next/standalone/tests/setup.ts +8 -8
  817. package/.next/standalone/tsconfig.json +34 -34
  818. package/.next/standalone/vitest.config.ts +24 -24
  819. package/LICENSE +661 -661
  820. package/README.md +131 -131
  821. package/bin/cortex-hook.js +79 -79
  822. package/bin/cortex-hook.sh +62 -62
  823. package/bin/cortex-learn-hook.js +138 -138
  824. package/bin/cortex-mcp.js +60 -60
  825. package/bin/cortex-pi-extension.ts +170 -170
  826. package/bin/fix-standalone-externals.js +79 -79
  827. package/bin/lib/auto-setup.js +110 -110
  828. package/bin/mdns-service.js +171 -171
  829. package/bin/postinstall.js +35 -35
  830. package/bin/setup-admin.js +195 -195
  831. package/bin/spaces-dev.js +247 -247
  832. package/bin/spaces-install.js +660 -660
  833. package/bin/spaces-postinstall.js +50 -50
  834. package/bin/spaces-reset-totp.js +50 -50
  835. package/bin/spaces-service.js +1046 -1046
  836. package/bin/spaces-setup.js +253 -253
  837. package/bin/spaces.js +808 -805
  838. package/bin/ssh-auth-keys.sh +68 -68
  839. package/bin/terminal-server.js +2819 -2781
  840. package/package.json +111 -111
  841. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0903a426._.js +0 -98
  842. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09e8ccc9._.js +0 -98
  843. package/.next/standalone/.next/server/chunks/[root-of-the-server]__11c684b1._.js +0 -98
  844. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1572d4ef._.js +0 -98
  845. package/.next/standalone/.next/server/chunks/[root-of-the-server]__186cd0bb._.js +0 -3
  846. package/.next/standalone/.next/server/chunks/[root-of-the-server]__212760e6._.js +0 -98
  847. package/.next/standalone/.next/server/chunks/[root-of-the-server]__228595ec._.js +0 -98
  848. package/.next/standalone/.next/server/chunks/[root-of-the-server]__283c890f._.js +0 -3
  849. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2f300a68._.js +0 -98
  850. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2f452778._.js +0 -98
  851. package/.next/standalone/.next/server/chunks/[root-of-the-server]__35f8e77e._.js +0 -98
  852. package/.next/standalone/.next/server/chunks/[root-of-the-server]__379fc2e9._.js +0 -98
  853. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3b40d79f._.js +0 -98
  854. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3d3dca2b._.js +0 -98
  855. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4d5b78d2._.js +0 -98
  856. package/.next/standalone/.next/server/chunks/[root-of-the-server]__54163e52._.js +0 -98
  857. package/.next/standalone/.next/server/chunks/[root-of-the-server]__563c0817._.js +0 -3
  858. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5812f90a._.js +0 -98
  859. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c5e87f5._.js +0 -98
  860. package/.next/standalone/.next/server/chunks/[root-of-the-server]__60d15b16._.js +0 -98
  861. package/.next/standalone/.next/server/chunks/[root-of-the-server]__69d315e5._.js +0 -3
  862. package/.next/standalone/.next/server/chunks/[root-of-the-server]__71f29038._.js +0 -98
  863. package/.next/standalone/.next/server/chunks/[root-of-the-server]__74084e07._.js +0 -3
  864. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7921aa80._.js +0 -98
  865. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e077dd8._.js +0 -98
  866. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7ebc4280._.js +0 -131
  867. package/.next/standalone/.next/server/chunks/[root-of-the-server]__857c60bb._.js +0 -98
  868. package/.next/standalone/.next/server/chunks/[root-of-the-server]__874fe565._.js +0 -98
  869. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8e2171f7._.js +0 -98
  870. package/.next/standalone/.next/server/chunks/[root-of-the-server]__95659b2d._.js +0 -98
  871. package/.next/standalone/.next/server/chunks/[root-of-the-server]__9679b91e._.js +0 -98
  872. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a90729a1._.js +0 -98
  873. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ad4346fa._.js +0 -98
  874. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b0862d69._.js +0 -98
  875. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b43306ee._.js +0 -98
  876. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b689ff5e._.js +0 -106
  877. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ba87daaa._.js +0 -98
  878. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c0461005._.js +0 -98
  879. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c1deb5f3._.js +0 -98
  880. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c8a62f42._.js +0 -98
  881. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cabaac2b._.js +0 -98
  882. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cb027619._.js +0 -98
  883. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cf608218._.js +0 -98
  884. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cfc1290d._.js +0 -98
  885. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d0109b9b._.js +0 -98
  886. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d0125483._.js +0 -3
  887. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d048ee6b._.js +0 -98
  888. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d12644e7._.js +0 -98
  889. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e3cc946c._.js +0 -98
  890. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e6fd27f8._.js +0 -98
  891. package/.next/standalone/.next/server/chunks/[root-of-the-server]__efb8251e._.js +0 -98
  892. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f44c6882._.js +0 -98
  893. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f85283de._.js +0 -98
  894. package/.next/standalone/.next/server/chunks/[root-of-the-server]__feceb3e4._.js +0 -98
  895. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__843070a6._.js +0 -3
  896. package/.next/standalone/.next/server/chunks/ssr/_e84a0c06._.js +0 -3
  897. package/.next/standalone/.next/static/chunks/470cade58d4eceeb.css +0 -3
  898. package/.next/standalone/.next/static/chunks/9d4164833c2c1fd6.js +0 -85
  899. package/.next/standalone/.next/static/chunks/f091f4bf8d80fd07.js +0 -1
  900. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/README.md +0 -46
  901. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  902. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/index.js +0 -1
  903. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  904. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/package.json +0 -42
  905. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
  906. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  907. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
  908. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  909. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
  910. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
  911. package/.next/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  912. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  913. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
  914. /package/.next/standalone/.next/static/{5S4TviTCiNiTjf6KjXjBo → u1pHON3drz1mBi7owkbBP}/_buildManifest.js +0 -0
  915. /package/.next/standalone/.next/static/{5S4TviTCiNiTjf6KjXjBo → u1pHON3drz1mBi7owkbBP}/_clientMiddlewareManifest.json +0 -0
  916. /package/.next/standalone/.next/static/{5S4TviTCiNiTjf6KjXjBo → u1pHON3drz1mBi7owkbBP}/_ssgManifest.js +0 -0
  917. /package/.next/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-win32-x64}/versions.json +0 -0
@@ -1,1080 +1,1080 @@
1
- # Cortex Lobes Implementation Plan
2
-
3
- > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
4
-
5
- **Goal:** Add knowledge compartmentalization ("lobes") to Cortex so workspaces control which knowledge sources they can pull from — open by default within a user, closed by default across users, with privacy, exclusions, and cross-user sharing.
6
-
7
- **Architecture:** A new `src/lib/cortex/lobes/` module containing lobe config types, a resolver that computes accessible lobes for a workspace, and sharing logic. The ContextEngine's `computeSourceWeights()` is modified to use the lobe resolver instead of hardcoded layers. Lobe config is stored as a JSON column on the workspaces table. Cross-user shares live in the entity graph's SQLite database.
8
-
9
- **Tech Stack:** TypeScript, better-sqlite3 (entity graph DB), vitest
10
-
11
- **Spec:** `docs/superpowers/specs/2026-03-16-cortex-lobes-design.md`
12
-
13
- ---
14
-
15
- ## File Structure
16
-
17
- ```
18
- New files:
19
- ├── src/lib/cortex/lobes/config.ts — LobeConfig types and defaults
20
- ├── src/lib/cortex/lobes/resolver.ts — Resolve accessible lobes for a workspace
21
- ├── src/lib/cortex/lobes/shares.ts — Cross-user sharing (lobe_shares table)
22
- ├── src/lib/cortex/lobes/index.ts — Barrel export
23
- ├── src/app/api/cortex/lobes/route.ts — List lobes, update config
24
- ├── src/app/api/cortex/lobes/share/route.ts — Share management
25
- ├── src/components/cortex/lobe-settings.tsx — UI component for workspace settings
26
-
27
- Test files:
28
- ├── tests/lib/cortex/lobes/resolver.test.ts
29
- ├── tests/lib/cortex/lobes/shares.test.ts
30
-
31
- Modified files:
32
- ├── src/lib/db/schema.ts — Add lobe_config column to workspaces
33
- ├── src/lib/cortex/retrieval/context-engine.ts — Use lobe resolver for search scopes
34
- ```
35
-
36
- ---
37
-
38
- ## Chunk 1: Types, DB Migration, and Lobe Resolver
39
-
40
- ### Task 1: Lobe config types and defaults
41
-
42
- **Files:**
43
- - Create: `src/lib/cortex/lobes/config.ts`
44
-
45
- - [ ] **Step 1: Create the types file**
46
-
47
- ```typescript
48
- // src/lib/cortex/lobes/config.ts
49
-
50
- export interface LobeSubscription {
51
- type: 'workspace' | 'user' | 'tag' | 'team' | 'department' | 'organization';
52
- id: string; // workspace ID, user entity ID, tag name, etc.
53
- label: string; // display name
54
- }
55
-
56
- export interface LobeConfig {
57
- isPrivate: boolean;
58
- excludedFrom: number[]; // workspace IDs blocked from accessing this lobe
59
- subscriptions: LobeSubscription[];
60
- tags: string[];
61
- }
62
-
63
- export const DEFAULT_LOBE_CONFIG: LobeConfig = {
64
- isPrivate: false,
65
- excludedFrom: [],
66
- subscriptions: [],
67
- tags: [],
68
- };
69
-
70
- export function parseLobeConfig(raw: string | null | undefined): LobeConfig {
71
- if (!raw) return { ...DEFAULT_LOBE_CONFIG };
72
- try {
73
- const parsed = JSON.parse(raw);
74
- return {
75
- isPrivate: parsed.isPrivate ?? false,
76
- excludedFrom: Array.isArray(parsed.excludedFrom) ? parsed.excludedFrom : [],
77
- subscriptions: Array.isArray(parsed.subscriptions) ? parsed.subscriptions : [],
78
- tags: Array.isArray(parsed.tags) ? parsed.tags : [],
79
- };
80
- } catch {
81
- return { ...DEFAULT_LOBE_CONFIG };
82
- }
83
- }
84
-
85
- export function serializeLobeConfig(config: LobeConfig): string {
86
- return JSON.stringify(config);
87
- }
88
- ```
89
-
90
- - [ ] **Step 2: Commit**
91
-
92
- ```bash
93
- git add src/lib/cortex/lobes/config.ts
94
- git commit -m "feat(cortex): add lobe config types and defaults"
95
- ```
96
-
97
- ---
98
-
99
- ### Task 2: Database migration — add lobe_config column
100
-
101
- **Files:**
102
- - Modify: `src/lib/db/schema.ts`
103
-
104
- - [ ] **Step 1: Read schema.ts to find the migration section**
105
-
106
- Read `src/lib/db/schema.ts`. Find the section with `addCol` calls (around line 120+). Add:
107
-
108
- ```typescript
109
- addCol('workspaces', 'lobe_config', "TEXT DEFAULT '{}'");
110
- ```
111
-
112
- This adds a JSON text column to the existing workspaces table with an empty config default.
113
-
114
- - [ ] **Step 2: Commit**
115
-
116
- ```bash
117
- git add src/lib/db/schema.ts
118
- git commit -m "feat(cortex): add lobe_config column to workspaces table"
119
- ```
120
-
121
- ---
122
-
123
- ### Task 3: Lobe resolver — compute accessible lobes for a workspace
124
-
125
- **Files:**
126
- - Create: `src/lib/cortex/lobes/resolver.ts`
127
- - Create: `tests/lib/cortex/lobes/resolver.test.ts`
128
-
129
- - [ ] **Step 1: Write failing tests**
130
-
131
- ```typescript
132
- // tests/lib/cortex/lobes/resolver.test.ts
133
- import { describe, it, expect } from 'vitest';
134
- import { resolveLobes } from '@/lib/cortex/lobes/resolver';
135
- import type { LobeConfig } from '@/lib/cortex/lobes/config';
136
- import { DEFAULT_LOBE_CONFIG } from '@/lib/cortex/lobes/config';
137
-
138
- // Minimal workspace shape for testing
139
- interface TestWorkspace {
140
- id: number;
141
- name: string;
142
- lobeConfig: LobeConfig;
143
- }
144
-
145
- describe('resolveLobes', () => {
146
- const workspaces: TestWorkspace[] = [
147
- { id: 1, name: 'Auth Service', lobeConfig: DEFAULT_LOBE_CONFIG },
148
- { id: 2, name: 'Frontend', lobeConfig: DEFAULT_LOBE_CONFIG },
149
- { id: 3, name: 'Private Project', lobeConfig: { ...DEFAULT_LOBE_CONFIG, isPrivate: true } },
150
- { id: 4, name: 'Excluded', lobeConfig: { ...DEFAULT_LOBE_CONFIG, excludedFrom: [1] } },
151
- ];
152
-
153
- it('includes own workspace lobe', () => {
154
- const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
155
- const keys = lobes.map(l => l.layerKey);
156
- expect(keys).toContain('workspace/1');
157
- });
158
-
159
- it('includes personal lobe', () => {
160
- const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
161
- const keys = lobes.map(l => l.layerKey);
162
- expect(keys).toContain('personal');
163
- });
164
-
165
- it('includes other non-private workspaces by default', () => {
166
- const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
167
- const keys = lobes.map(l => l.layerKey);
168
- expect(keys).toContain('workspace/2');
169
- });
170
-
171
- it('excludes private workspaces', () => {
172
- const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
173
- const keys = lobes.map(l => l.layerKey);
174
- expect(keys).not.toContain('workspace/3');
175
- });
176
-
177
- it('excludes workspaces that exclude the requester', () => {
178
- // Workspace 4 excludes workspace 1
179
- const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
180
- const keys = lobes.map(l => l.layerKey);
181
- expect(keys).not.toContain('workspace/4');
182
- });
183
-
184
- it('includes team lobe by default', () => {
185
- const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
186
- const keys = lobes.map(l => l.layerKey);
187
- expect(keys).toContain('team');
188
- });
189
-
190
- it('includes explicit subscriptions', () => {
191
- const ws: TestWorkspace[] = [
192
- {
193
- id: 1, name: 'Main',
194
- lobeConfig: {
195
- ...DEFAULT_LOBE_CONFIG,
196
- subscriptions: [{ type: 'tag', id: 'infrastructure', label: 'Infrastructure' }],
197
- },
198
- },
199
- ];
200
- const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: ws });
201
- const tags = lobes.filter(l => l.type === 'tag');
202
- expect(tags).toHaveLength(1);
203
- expect(tags[0].id).toBe('infrastructure');
204
- });
205
-
206
- it('assigns lower weight to subscribed lobes vs inherited', () => {
207
- const ws: TestWorkspace[] = [
208
- {
209
- id: 1, name: 'Main',
210
- lobeConfig: {
211
- ...DEFAULT_LOBE_CONFIG,
212
- subscriptions: [{ type: 'workspace', id: '99', label: 'Remote' }],
213
- },
214
- },
215
- ];
216
- const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: ws });
217
- const own = lobes.find(l => l.layerKey === 'workspace/1');
218
- const subscribed = lobes.find(l => l.layerKey === 'workspace/99');
219
- expect(own!.baseWeight).toBeGreaterThan(subscribed!.baseWeight);
220
- });
221
- });
222
- ```
223
-
224
- - [ ] **Step 2: Run tests to verify they fail**
225
-
226
- Run: `npx vitest run tests/lib/cortex/lobes/resolver.test.ts`
227
-
228
- - [ ] **Step 3: Implement lobe resolver**
229
-
230
- ```typescript
231
- // src/lib/cortex/lobes/resolver.ts
232
- import type { LobeConfig, LobeSubscription } from './config';
233
-
234
- export interface ResolvedLobe {
235
- layerKey: string; // LanceDB storage path (e.g., 'workspace/42', 'personal', 'team')
236
- label: string; // display name
237
- type: 'own' | 'personal' | 'workspace' | 'team' | 'department' | 'organization' | 'tag' | 'user';
238
- id: string; // source identifier
239
- baseWeight: number; // base retrieval weight (before graph proximity)
240
- inherited: boolean; // true if auto-inherited, false if explicitly subscribed
241
- }
242
-
243
- interface WorkspaceInfo {
244
- id: number;
245
- name: string;
246
- lobeConfig: LobeConfig;
247
- }
248
-
249
- interface ResolveInput {
250
- workspaceId: number;
251
- allWorkspaces: WorkspaceInfo[];
252
- userId?: string; // for personal lobe entity ID
253
- }
254
-
255
- /**
256
- * Resolve the list of accessible knowledge lobes for a workspace.
257
- *
258
- * Default behavior: own workspace + personal + all non-private sibling workspaces + team + org.
259
- * Respects privacy, exclusions, and explicit subscriptions.
260
- */
261
- export function resolveLobes(input: ResolveInput): ResolvedLobe[] {
262
- const { workspaceId, allWorkspaces, userId } = input;
263
- const lobes: ResolvedLobe[] = [];
264
-
265
- const thisWs = allWorkspaces.find(w => w.id === workspaceId);
266
- const thisConfig = thisWs?.lobeConfig;
267
-
268
- // 1. Own workspace lobe (always included)
269
- lobes.push({
270
- layerKey: `workspace/${workspaceId}`,
271
- label: thisWs?.name ?? 'This workspace',
272
- type: 'own',
273
- id: String(workspaceId),
274
- baseWeight: 1.0,
275
- inherited: true,
276
- });
277
-
278
- // 2. Personal lobe (always included)
279
- lobes.push({
280
- layerKey: 'personal',
281
- label: 'Personal',
282
- type: 'personal',
283
- id: userId ?? 'personal',
284
- baseWeight: 0.9,
285
- inherited: true,
286
- });
287
-
288
- // 3. Other workspaces (same user) — included unless private or excluded
289
- for (const ws of allWorkspaces) {
290
- if (ws.id === workspaceId) continue;
291
-
292
- // Skip if the other workspace is private
293
- if (ws.lobeConfig.isPrivate) continue;
294
-
295
- // Skip if the other workspace excludes this workspace
296
- if (ws.lobeConfig.excludedFrom.includes(workspaceId)) continue;
297
-
298
- lobes.push({
299
- layerKey: `workspace/${ws.id}`,
300
- label: ws.name,
301
- type: 'workspace',
302
- id: String(ws.id),
303
- baseWeight: 0.6,
304
- inherited: true,
305
- });
306
- }
307
-
308
- // 4. Team / org inherited lobes
309
- lobes.push({
310
- layerKey: 'team',
311
- label: 'Team',
312
- type: 'team',
313
- id: 'team',
314
- baseWeight: 0.5,
315
- inherited: true,
316
- });
317
-
318
- // 5. Explicit subscriptions from this workspace's config
319
- if (thisConfig?.subscriptions) {
320
- for (const sub of thisConfig.subscriptions) {
321
- // Avoid duplicates
322
- const layerKey = sub.type === 'workspace' ? `workspace/${sub.id}`
323
- : sub.type === 'tag' ? `tag/${sub.id}`
324
- : sub.type === 'team' ? `team/${sub.id}`
325
- : sub.type === 'user' ? `user/${sub.id}`
326
- : sub.id;
327
-
328
- if (lobes.some(l => l.layerKey === layerKey)) continue;
329
-
330
- lobes.push({
331
- layerKey,
332
- label: sub.label,
333
- type: sub.type as ResolvedLobe['type'],
334
- id: sub.id,
335
- baseWeight: 0.4, // subscribed = lower weight than inherited
336
- inherited: false,
337
- });
338
- }
339
- }
340
-
341
- return lobes;
342
- }
343
- ```
344
-
345
- - [ ] **Step 4: Run tests to verify they pass**
346
-
347
- Run: `npx vitest run tests/lib/cortex/lobes/resolver.test.ts`
348
- Expected: PASS (8 tests)
349
-
350
- - [ ] **Step 5: Commit**
351
-
352
- ```bash
353
- git add src/lib/cortex/lobes/resolver.ts tests/lib/cortex/lobes/resolver.test.ts
354
- git commit -m "feat(cortex): add lobe resolver for workspace knowledge scoping"
355
- ```
356
-
357
- ---
358
-
359
- ## Chunk 2: Cross-User Sharing and Context Engine Integration
360
-
361
- ### Task 4: Cross-user lobe sharing
362
-
363
- **Files:**
364
- - Create: `src/lib/cortex/lobes/shares.ts`
365
- - Create: `tests/lib/cortex/lobes/shares.test.ts`
366
-
367
- - [ ] **Step 1: Write failing tests**
368
-
369
- ```typescript
370
- // tests/lib/cortex/lobes/shares.test.ts
371
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
372
- import fs from 'fs';
373
- import path from 'path';
374
- import os from 'os';
375
- import Database from 'better-sqlite3';
376
- import { LobeShareStore } from '@/lib/cortex/lobes/shares';
377
-
378
- describe('LobeShareStore', () => {
379
- let tmpDir: string;
380
- let store: LobeShareStore;
381
-
382
- beforeEach(() => {
383
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'lobe-shares-'));
384
- const db = new Database(path.join(tmpDir, 'test.db'));
385
- store = new LobeShareStore(db);
386
- });
387
-
388
- afterEach(() => {
389
- fs.rmSync(tmpDir, { recursive: true, force: true });
390
- });
391
-
392
- it('creates a share', () => {
393
- const share = store.share({
394
- ownerUserId: 'person-alice',
395
- ownerWorkspaceId: 1,
396
- ownerLobeName: 'Auth Service',
397
- sharedWithUserId: 'person-bob',
398
- });
399
- expect(share.id).toBeDefined();
400
- expect(share.accepted).toBe(false);
401
- });
402
-
403
- it('accepts a share', () => {
404
- const share = store.share({
405
- ownerUserId: 'person-alice',
406
- ownerWorkspaceId: 1,
407
- ownerLobeName: 'Auth Service',
408
- sharedWithUserId: 'person-bob',
409
- });
410
- store.accept(share.id);
411
- const updated = store.getShare(share.id);
412
- expect(updated!.accepted).toBe(true);
413
- });
414
-
415
- it('lists incoming shares for a user', () => {
416
- store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
417
- store.share({ ownerUserId: 'person-charlie', ownerWorkspaceId: 2, ownerLobeName: 'WS2', sharedWithUserId: 'person-bob' });
418
- const incoming = store.listIncoming('person-bob');
419
- expect(incoming).toHaveLength(2);
420
- });
421
-
422
- it('lists outgoing shares for a user', () => {
423
- store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
424
- const outgoing = store.listOutgoing('person-alice');
425
- expect(outgoing).toHaveLength(1);
426
- });
427
-
428
- it('revokes a share', () => {
429
- const share = store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
430
- store.revoke(share.id);
431
- expect(store.getShare(share.id)).toBeNull();
432
- });
433
-
434
- it('prevents duplicate shares', () => {
435
- store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
436
- store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
437
- const incoming = store.listIncoming('person-bob');
438
- expect(incoming).toHaveLength(1);
439
- });
440
- });
441
- ```
442
-
443
- - [ ] **Step 2: Implement share store**
444
-
445
- ```typescript
446
- // src/lib/cortex/lobes/shares.ts
447
- import type Database from 'better-sqlite3';
448
-
449
- export interface LobeShare {
450
- id: string;
451
- ownerUserId: string;
452
- ownerWorkspaceId: number;
453
- ownerLobeName: string;
454
- sharedWithUserId: string;
455
- accepted: boolean;
456
- created: string;
457
- }
458
-
459
- interface ShareInput {
460
- ownerUserId: string;
461
- ownerWorkspaceId: number;
462
- ownerLobeName: string;
463
- sharedWithUserId: string;
464
- }
465
-
466
- export class LobeShareStore {
467
- private db: InstanceType<typeof Database>;
468
-
469
- constructor(db: InstanceType<typeof Database>) {
470
- this.db = db;
471
- this.db.exec(`
472
- CREATE TABLE IF NOT EXISTS lobe_shares (
473
- id TEXT PRIMARY KEY,
474
- owner_user_id TEXT NOT NULL,
475
- owner_workspace_id INTEGER NOT NULL,
476
- owner_lobe_name TEXT NOT NULL,
477
- shared_with_user_id TEXT NOT NULL,
478
- accepted INTEGER DEFAULT 0,
479
- created TEXT NOT NULL,
480
- UNIQUE(owner_user_id, owner_workspace_id, shared_with_user_id)
481
- );
482
- CREATE INDEX IF NOT EXISTS idx_lobe_shares_recipient ON lobe_shares(shared_with_user_id);
483
- CREATE INDEX IF NOT EXISTS idx_lobe_shares_owner ON lobe_shares(owner_user_id);
484
- `);
485
- }
486
-
487
- share(input: ShareInput): LobeShare {
488
- const id = crypto.randomUUID();
489
- const now = new Date().toISOString();
490
-
491
- this.db.prepare(`
492
- INSERT INTO lobe_shares (id, owner_user_id, owner_workspace_id, owner_lobe_name, shared_with_user_id, created)
493
- VALUES (?, ?, ?, ?, ?, ?)
494
- ON CONFLICT(owner_user_id, owner_workspace_id, shared_with_user_id) DO NOTHING
495
- `).run(id, input.ownerUserId, input.ownerWorkspaceId, input.ownerLobeName, input.sharedWithUserId, now);
496
-
497
- // Return existing if duplicate
498
- const existing = this.db.prepare(
499
- 'SELECT * FROM lobe_shares WHERE owner_user_id = ? AND owner_workspace_id = ? AND shared_with_user_id = ?'
500
- ).get(input.ownerUserId, input.ownerWorkspaceId, input.sharedWithUserId) as any;
501
-
502
- return this.rowToShare(existing);
503
- }
504
-
505
- accept(id: string): void {
506
- this.db.prepare('UPDATE lobe_shares SET accepted = 1 WHERE id = ?').run(id);
507
- }
508
-
509
- revoke(id: string): void {
510
- this.db.prepare('DELETE FROM lobe_shares WHERE id = ?').run(id);
511
- }
512
-
513
- getShare(id: string): LobeShare | null {
514
- const row = this.db.prepare('SELECT * FROM lobe_shares WHERE id = ?').get(id) as any;
515
- return row ? this.rowToShare(row) : null;
516
- }
517
-
518
- listIncoming(userId: string): LobeShare[] {
519
- const rows = this.db.prepare(
520
- 'SELECT * FROM lobe_shares WHERE shared_with_user_id = ? ORDER BY created DESC'
521
- ).all(userId) as any[];
522
- return rows.map(r => this.rowToShare(r));
523
- }
524
-
525
- listOutgoing(userId: string): LobeShare[] {
526
- const rows = this.db.prepare(
527
- 'SELECT * FROM lobe_shares WHERE owner_user_id = ? ORDER BY created DESC'
528
- ).all(userId) as any[];
529
- return rows.map(r => this.rowToShare(r));
530
- }
531
-
532
- listAcceptedForUser(userId: string): LobeShare[] {
533
- const rows = this.db.prepare(
534
- 'SELECT * FROM lobe_shares WHERE shared_with_user_id = ? AND accepted = 1'
535
- ).all(userId) as any[];
536
- return rows.map(r => this.rowToShare(r));
537
- }
538
-
539
- private rowToShare(row: any): LobeShare {
540
- return {
541
- id: row.id,
542
- ownerUserId: row.owner_user_id,
543
- ownerWorkspaceId: row.owner_workspace_id,
544
- ownerLobeName: row.owner_lobe_name,
545
- sharedWithUserId: row.shared_with_user_id,
546
- accepted: row.accepted === 1,
547
- created: row.created,
548
- };
549
- }
550
- }
551
- ```
552
-
553
- - [ ] **Step 3: Run tests, commit**
554
-
555
- Run: `npx vitest run tests/lib/cortex/lobes/shares.test.ts`
556
-
557
- ```bash
558
- git commit -m "feat(cortex): add cross-user lobe sharing with handshake"
559
- ```
560
-
561
- ---
562
-
563
- ### Task 5: Integrate lobe resolver with Context Assembly Engine
564
-
565
- **Files:**
566
- - Modify: `src/lib/cortex/retrieval/context-engine.ts`
567
-
568
- - [ ] **Step 1: Read context-engine.ts**
569
-
570
- Read the file. Find `computeSourceWeights()` — the private method that returns hardcoded layer definitions.
571
-
572
- - [ ] **Step 2: Add optional lobe-aware scope computation**
573
-
574
- Add to `ContextEngineDeps`:
575
- ```typescript
576
- resolvedLobes?: ResolvedLobe[]; // pre-computed accessible lobes for this workspace
577
- ```
578
-
579
- Import:
580
- ```typescript
581
- import type { ResolvedLobe } from '../lobes/resolver';
582
- ```
583
-
584
- Modify `computeSourceWeights()` to use resolved lobes when available:
585
-
586
- ```typescript
587
- private computeSourceWeights(
588
- intent: IntentResult,
589
- workspaceId: number | null,
590
- ): SourceConfig[] {
591
- // If lobes are provided, use them instead of hardcoded layers
592
- if (this.deps.resolvedLobes && this.deps.resolvedLobes.length > 0) {
593
- return this.deps.resolvedLobes.map(lobe => {
594
- const graphProximity = lobe.baseWeight; // lobes already have base weights
595
-
596
- const weight = computeScopeWeight({
597
- graphProximity,
598
- scopeLevel: lobe.type === 'personal' ? 'personal'
599
- : lobe.type === 'team' || lobe.type === 'department' ? 'team'
600
- : lobe.type === 'organization' ? 'organization'
601
- : 'team',
602
- intentBiases: intent.biases,
603
- authorityFactor: 1.0,
604
- });
605
-
606
- return {
607
- layerKey: lobe.layerKey,
608
- weight,
609
- limit: Math.max(3, Math.round(weight * 10)),
610
- };
611
- }).sort((a, b) => b.weight - a.weight);
612
- }
613
-
614
- // Fallback: hardcoded layers (backward compat when no lobe config)
615
- const layerDefs = [
616
- // ... existing code unchanged ...
617
- ];
618
- // ... rest of existing method unchanged ...
619
- }
620
- ```
621
-
622
- - [ ] **Step 3: Run existing context-engine tests to verify no regressions**
623
-
624
- Run: `npx vitest run tests/lib/cortex/retrieval/context-engine.test.ts`
625
-
626
- - [ ] **Step 4: Commit**
627
-
628
- ```bash
629
- git add src/lib/cortex/retrieval/context-engine.ts
630
- git commit -m "feat(cortex): integrate lobe resolver into context assembly engine"
631
- ```
632
-
633
- ---
634
-
635
- ## Chunk 3: API Routes and UI
636
-
637
- ### Task 6: Lobe API endpoints
638
-
639
- **Files:**
640
- - Create: `src/app/api/cortex/lobes/route.ts`
641
- - Create: `src/app/api/cortex/lobes/[id]/route.ts`
642
- - Create: `src/app/api/cortex/lobes/share/route.ts`
643
-
644
- - [ ] **Step 1: Create main lobes endpoint**
645
-
646
- ```typescript
647
- // src/app/api/cortex/lobes/route.ts
648
- import { NextResponse } from 'next/server';
649
- import type { NextRequest } from 'next/server';
650
- import { getAuthUser, withUser } from '@/lib/auth';
651
- import { getDb } from '@/lib/db';
652
- import { parseLobeConfig } from '@/lib/cortex/lobes/config';
653
-
654
- export async function GET(request: NextRequest) {
655
- const user = getAuthUser(request);
656
- return withUser(user, async () => {
657
- const db = getDb();
658
- const workspaces = db.prepare(
659
- 'SELECT id, name, color, lobe_config FROM workspaces ORDER BY name'
660
- ).all() as any[];
661
-
662
- const lobes = workspaces.map(ws => ({
663
- workspaceId: ws.id,
664
- name: ws.name,
665
- color: ws.color,
666
- config: parseLobeConfig(ws.lobe_config),
667
- }));
668
-
669
- return NextResponse.json({ lobes });
670
- });
671
- }
672
- ```
673
-
674
- - [ ] **Step 2: Create single workspace lobe config endpoint**
675
-
676
- ```typescript
677
- // src/app/api/cortex/lobes/[id]/route.ts
678
- import { NextResponse } from 'next/server';
679
- import type { NextRequest } from 'next/server';
680
- import { getAuthUser, withUser } from '@/lib/auth';
681
- import { getDb } from '@/lib/db';
682
- import { parseLobeConfig, serializeLobeConfig } from '@/lib/cortex/lobes/config';
683
- import type { LobeConfig } from '@/lib/cortex/lobes/config';
684
-
685
- export async function GET(
686
- request: NextRequest,
687
- { params }: { params: Promise<{ id: string }> },
688
- ) {
689
- const { id } = await params;
690
- const user = getAuthUser(request);
691
- return withUser(user, async () => {
692
- const db = getDb();
693
- const ws = db.prepare('SELECT id, name, lobe_config FROM workspaces WHERE id = ?').get(Number(id)) as any;
694
- if (!ws) return NextResponse.json({ error: 'Workspace not found' }, { status: 404 });
695
- return NextResponse.json({ workspaceId: ws.id, name: ws.name, config: parseLobeConfig(ws.lobe_config) });
696
- });
697
- }
698
-
699
- export async function PUT(
700
- request: NextRequest,
701
- { params }: { params: Promise<{ id: string }> },
702
- ) {
703
- const { id } = await params;
704
- const user = getAuthUser(request);
705
- return withUser(user, async () => {
706
- const db = getDb();
707
- const body = await request.json() as Partial<LobeConfig>;
708
-
709
- const ws = db.prepare('SELECT lobe_config FROM workspaces WHERE id = ?').get(Number(id)) as any;
710
- if (!ws) return NextResponse.json({ error: 'Workspace not found' }, { status: 404 });
711
-
712
- const current = parseLobeConfig(ws.lobe_config);
713
- const updated: LobeConfig = {
714
- isPrivate: body.isPrivate ?? current.isPrivate,
715
- excludedFrom: body.excludedFrom ?? current.excludedFrom,
716
- subscriptions: body.subscriptions ?? current.subscriptions,
717
- tags: body.tags ?? current.tags,
718
- };
719
-
720
- db.prepare('UPDATE workspaces SET lobe_config = ? WHERE id = ?').run(serializeLobeConfig(updated), Number(id));
721
- return NextResponse.json({ config: updated });
722
- });
723
- }
724
- ```
725
-
726
- - [ ] **Step 3: Create share endpoint**
727
-
728
- ```typescript
729
- // src/app/api/cortex/lobes/share/route.ts
730
- import { NextResponse } from 'next/server';
731
- import type { NextRequest } from 'next/server';
732
- import { getAuthUser, withUser } from '@/lib/auth';
733
- import { getCortex, isCortexAvailable } from '@/lib/cortex';
734
- import { LobeShareStore } from '@/lib/cortex/lobes/shares';
735
- import { slugify } from '@/lib/cortex/graph/types';
736
-
737
- export async function GET(request: NextRequest) {
738
- const user = getAuthUser(request);
739
- return withUser(user, async () => {
740
- if (!isCortexAvailable()) return NextResponse.json({ incoming: [], outgoing: [] });
741
- const cortex = await getCortex();
742
- if (!cortex) return NextResponse.json({ incoming: [], outgoing: [] });
743
-
744
- const shareStore = new LobeShareStore(cortex.graph['db']);
745
- const userId = `person-${slugify(user)}`;
746
-
747
- return NextResponse.json({
748
- incoming: shareStore.listIncoming(userId),
749
- outgoing: shareStore.listOutgoing(userId),
750
- });
751
- });
752
- }
753
-
754
- export async function POST(request: NextRequest) {
755
- const user = getAuthUser(request);
756
- return withUser(user, async () => {
757
- if (!isCortexAvailable()) return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
758
- const cortex = await getCortex();
759
- if (!cortex) return NextResponse.json({ error: 'Cortex unavailable' }, { status: 500 });
760
-
761
- const body = await request.json();
762
- const { action, shareId, workspaceId, lobeName, sharedWithUserId } = body;
763
- const shareStore = new LobeShareStore(cortex.graph['db']);
764
- const userId = `person-${slugify(user)}`;
765
-
766
- if (action === 'share') {
767
- const share = shareStore.share({
768
- ownerUserId: userId,
769
- ownerWorkspaceId: workspaceId,
770
- ownerLobeName: lobeName,
771
- sharedWithUserId,
772
- });
773
- return NextResponse.json({ share }, { status: 201 });
774
- }
775
-
776
- if (action === 'accept') {
777
- shareStore.accept(shareId);
778
- return NextResponse.json({ accepted: true });
779
- }
780
-
781
- if (action === 'revoke' || action === 'decline') {
782
- shareStore.revoke(shareId);
783
- return NextResponse.json({ revoked: true });
784
- }
785
-
786
- return NextResponse.json({ error: 'Invalid action' }, { status: 400 });
787
- });
788
- }
789
- ```
790
-
791
- - [ ] **Step 4: Commit**
792
-
793
- ```bash
794
- git add src/app/api/cortex/lobes/
795
- git commit -m "feat(cortex): add lobe API endpoints for config and sharing"
796
- ```
797
-
798
- ---
799
-
800
- ### Task 7: Lobe settings UI component
801
-
802
- **Files:**
803
- - Create: `src/components/cortex/lobe-settings.tsx`
804
-
805
- - [ ] **Step 1: Create the component**
806
-
807
- A settings panel showing the workspace's knowledge sources with toggles, tags, and subscription management.
808
-
809
- ```typescript
810
- 'use client';
811
-
812
- import { useState, useEffect, useCallback } from 'react';
813
- import { Shield, ShieldOff, Tag, Plus, X, Users } from 'lucide-react';
814
- import { api } from '@/lib/api';
815
- import type { LobeConfig, LobeSubscription } from '@/lib/cortex/lobes/config';
816
-
817
- interface LobeSettingsProps {
818
- workspaceId: number;
819
- workspaceName: string;
820
- }
821
-
822
- export function LobeSettings({ workspaceId, workspaceName }: LobeSettingsProps) {
823
- const [config, setConfig] = useState<LobeConfig | null>(null);
824
- const [allLobes, setAllLobes] = useState<any[]>([]);
825
- const [newTag, setNewTag] = useState('');
826
- const [saving, setSaving] = useState(false);
827
-
828
- const fetchConfig = useCallback(async () => {
829
- const res = await fetch(api(`/api/cortex/lobes/${workspaceId}`));
830
- if (res.ok) {
831
- const data = await res.json();
832
- setConfig(data.config);
833
- }
834
- }, [workspaceId]);
835
-
836
- const fetchAllLobes = useCallback(async () => {
837
- const res = await fetch(api('/api/cortex/lobes'));
838
- if (res.ok) {
839
- const data = await res.json();
840
- setAllLobes(data.lobes || []);
841
- }
842
- }, []);
843
-
844
- useEffect(() => { fetchConfig(); fetchAllLobes(); }, [fetchConfig, fetchAllLobes]);
845
-
846
- const save = async (updates: Partial<LobeConfig>) => {
847
- setSaving(true);
848
- await fetch(api(`/api/cortex/lobes/${workspaceId}`), {
849
- method: 'PUT',
850
- headers: { 'Content-Type': 'application/json' },
851
- body: JSON.stringify(updates),
852
- });
853
- await fetchConfig();
854
- setSaving(false);
855
- };
856
-
857
- if (!config) return <div className="text-gray-500 text-sm p-4">Loading...</div>;
858
-
859
- const activeSourceCount = allLobes.filter(l =>
860
- l.workspaceId !== workspaceId && !l.config.isPrivate && !l.config.excludedFrom?.includes(workspaceId)
861
- ).length + 2; // +2 for personal + team
862
-
863
- return (
864
- <div className="space-y-6">
865
- <div>
866
- <h3 className="text-sm font-medium text-gray-200 mb-1">Knowledge Lobes</h3>
867
- <p className="text-xs text-gray-500">
868
- This workspace draws from {activeSourceCount} lobes.
869
- {config.isPrivate && ' This lobe is private — other workspaces cannot access its knowledge.'}
870
- </p>
871
- </div>
872
-
873
- {/* Privacy toggle */}
874
- <div className="flex items-center justify-between py-3 border-t border-white/5">
875
- <div className="flex items-center gap-2">
876
- {config.isPrivate ? <ShieldOff className="w-4 h-4 text-red-400" /> : <Shield className="w-4 h-4 text-green-400" />}
877
- <div>
878
- <div className="text-sm text-gray-200">Private lobe</div>
879
- <div className="text-[10px] text-gray-500">Other workspaces cannot access this knowledge</div>
880
- </div>
881
- </div>
882
- <button
883
- onClick={() => save({ isPrivate: !config.isPrivate })}
884
- disabled={saving}
885
- className={`px-3 py-1 text-xs rounded ${config.isPrivate ? 'bg-red-500/20 text-red-400' : 'bg-white/5 text-gray-400'}`}
886
- >
887
- {config.isPrivate ? 'Private' : 'Open'}
888
- </button>
889
- </div>
890
-
891
- {/* Tags */}
892
- <div className="border-t border-white/5 pt-3">
893
- <div className="flex items-center gap-2 mb-2">
894
- <Tag className="w-3.5 h-3.5 text-gray-500" />
895
- <span className="text-xs text-gray-400">Tags</span>
896
- </div>
897
- <div className="flex flex-wrap gap-1.5 mb-2">
898
- {config.tags.map(tag => (
899
- <span key={tag} className="flex items-center gap-1 text-[11px] bg-purple-500/10 text-purple-400 px-2 py-0.5 rounded">
900
- {tag}
901
- <button onClick={() => save({ tags: config.tags.filter(t => t !== tag) })} className="hover:text-white">
902
- <X className="w-2.5 h-2.5" />
903
- </button>
904
- </span>
905
- ))}
906
- </div>
907
- <div className="flex gap-1.5">
908
- <input
909
- value={newTag}
910
- onChange={e => setNewTag(e.target.value)}
911
- onKeyDown={e => {
912
- if (e.key === 'Enter' && newTag.trim()) {
913
- save({ tags: [...config.tags, newTag.trim()] });
914
- setNewTag('');
915
- }
916
- }}
917
- placeholder="Add tag..."
918
- className="flex-1 px-2 py-1 text-xs bg-white/5 border border-white/10 rounded text-gray-300 focus:outline-none focus:border-purple-500/50"
919
- />
920
- </div>
921
- </div>
922
-
923
- {/* Subscriptions */}
924
- <div className="border-t border-white/5 pt-3">
925
- <div className="flex items-center gap-2 mb-2">
926
- <Plus className="w-3.5 h-3.5 text-gray-500" />
927
- <span className="text-xs text-gray-400">Additional sources</span>
928
- </div>
929
- {config.subscriptions.length === 0 ? (
930
- <p className="text-[11px] text-gray-600">No additional subscriptions. Using defaults.</p>
931
- ) : (
932
- <div className="space-y-1">
933
- {config.subscriptions.map((sub, i) => (
934
- <div key={i} className="flex items-center justify-between text-xs bg-white/[0.02] rounded px-2 py-1.5">
935
- <span className="text-gray-300">{sub.label} <span className="text-gray-600">({sub.type})</span></span>
936
- <button
937
- onClick={() => save({ subscriptions: config.subscriptions.filter((_, j) => j !== i) })}
938
- className="text-gray-600 hover:text-red-400"
939
- >
940
- <X className="w-3 h-3" />
941
- </button>
942
- </div>
943
- ))}
944
- </div>
945
- )}
946
- </div>
947
-
948
- {/* Exclusions */}
949
- <div className="border-t border-white/5 pt-3">
950
- <div className="flex items-center gap-2 mb-2">
951
- <Users className="w-3.5 h-3.5 text-gray-500" />
952
- <span className="text-xs text-gray-400">Excluded workspaces</span>
953
- </div>
954
- {config.excludedFrom.length === 0 ? (
955
- <p className="text-[11px] text-gray-600">No exclusions. All workspaces can access this lobe.</p>
956
- ) : (
957
- <div className="space-y-1">
958
- {config.excludedFrom.map(wsId => {
959
- const ws = allLobes.find(l => l.workspaceId === wsId);
960
- return (
961
- <div key={wsId} className="flex items-center justify-between text-xs bg-white/[0.02] rounded px-2 py-1.5">
962
- <span className="text-gray-300">{ws?.name || `Workspace ${wsId}`}</span>
963
- <button
964
- onClick={() => save({ excludedFrom: config.excludedFrom.filter(id => id !== wsId) })}
965
- className="text-gray-600 hover:text-red-400"
966
- >
967
- <X className="w-3 h-3" />
968
- </button>
969
- </div>
970
- );
971
- })}
972
- </div>
973
- )}
974
- </div>
975
- </div>
976
- );
977
- }
978
- ```
979
-
980
- - [ ] **Step 2: Commit**
981
-
982
- ```bash
983
- git add src/components/cortex/lobe-settings.tsx
984
- git commit -m "feat(cortex): add lobe settings UI component"
985
- ```
986
-
987
- ---
988
-
989
- ### Task 8: Barrel export and wiring
990
-
991
- **Files:**
992
- - Create: `src/lib/cortex/lobes/index.ts`
993
- - Modify: `src/app/(desktop)/cortex/page.tsx` — add Lobes section to Settings tab
994
-
995
- - [ ] **Step 1: Create barrel export**
996
-
997
- ```typescript
998
- // src/lib/cortex/lobes/index.ts
999
- export { parseLobeConfig, serializeLobeConfig, DEFAULT_LOBE_CONFIG } from './config';
1000
- export type { LobeConfig, LobeSubscription } from './config';
1001
- export { resolveLobes } from './resolver';
1002
- export type { ResolvedLobe } from './resolver';
1003
- export { LobeShareStore } from './shares';
1004
- export type { LobeShare } from './shares';
1005
- ```
1006
-
1007
- - [ ] **Step 2: Add LobeSettings to the Cortex page Settings tab**
1008
-
1009
- Read `src/app/(desktop)/cortex/page.tsx`. Find the Settings tab rendering. Currently it shows `<CortexSettings />`. Add `<LobeSettings>` below it, but only when a workspace is active. The workspace ID needs to come from somewhere — check how the terminal page gets `activeWorkspace`:
1010
-
1011
- Read `src/app/(desktop)/terminal/page.tsx` to see how `activeWorkspace` is loaded. The pattern is likely a fetch to `/api/workspaces` with `is_active=1`.
1012
-
1013
- For the Cortex page, add a simple workspace selector or use the active workspace. The simplest approach: fetch the active workspace and pass its ID to LobeSettings.
1014
-
1015
- ```typescript
1016
- // In CortexPage, add state:
1017
- const [activeWorkspace, setActiveWorkspace] = useState<any>(null);
1018
-
1019
- // Fetch active workspace:
1020
- useEffect(() => {
1021
- fetch(api('/api/workspaces'))
1022
- .then(r => r.json())
1023
- .then(data => {
1024
- const active = (data.workspaces || []).find((w: any) => w.isActive);
1025
- setActiveWorkspace(active);
1026
- })
1027
- .catch(() => {});
1028
- }, []);
1029
-
1030
- // In Settings tab rendering, add LobeSettings:
1031
- {tab === 'settings' && (
1032
- <div className="p-6 max-w-2xl space-y-8">
1033
- <CortexSettings />
1034
- {activeWorkspace && (
1035
- <LobeSettings
1036
- workspaceId={activeWorkspace.id}
1037
- workspaceName={activeWorkspace.name}
1038
- />
1039
- )}
1040
- </div>
1041
- )}
1042
- ```
1043
-
1044
- Import: `import { LobeSettings } from '@/components/cortex/lobe-settings';`
1045
-
1046
- - [ ] **Step 3: Run full test suite**
1047
-
1048
- Run: `npx vitest run tests/lib/cortex/`
1049
-
1050
- - [ ] **Step 4: Commit**
1051
-
1052
- ```bash
1053
- git add src/lib/cortex/lobes/index.ts src/app/(desktop)/cortex/page.tsx
1054
- git commit -m "feat(cortex): wire lobe settings into Cortex page"
1055
- ```
1056
-
1057
- ---
1058
-
1059
- ## Summary
1060
-
1061
- | Task | Component | Tests | Status |
1062
- |------|-----------|-------|--------|
1063
- | 1 | Lobe config types | — | |
1064
- | 2 | DB migration (lobe_config column) | — | |
1065
- | 3 | Lobe resolver | 8 | |
1066
- | 4 | Cross-user sharing | 6 | |
1067
- | 5 | Context Engine integration | regression | |
1068
- | 6 | API endpoints (3 files) | — | |
1069
- | 7 | Lobe settings UI component | — | |
1070
- | 8 | Barrel export + page wiring | regression | |
1071
-
1072
- **Total: 8 tasks, ~14 new tests, 3 chunks**
1073
-
1074
- **Key design decisions:**
1075
- - Lobe config stored as JSON column on workspaces table (simple, always loaded with workspace)
1076
- - Resolver computes accessible lobes at query time from workspace list + config
1077
- - Cross-user shares use a separate SQLite table in the entity graph DB with two-step handshake
1078
- - Context Engine uses resolved lobes when provided, falls back to hardcoded layers for backward compat
1079
- - Privacy is safe-by-default: private workspaces are excluded, cross-user is closed by default
1080
- - Base weights: own=1.0, personal=0.9, sibling workspaces=0.6, team=0.5, subscribed=0.4
1
+ # Cortex Lobes Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Add knowledge compartmentalization ("lobes") to Cortex so workspaces control which knowledge sources they can pull from — open by default within a user, closed by default across users, with privacy, exclusions, and cross-user sharing.
6
+
7
+ **Architecture:** A new `src/lib/cortex/lobes/` module containing lobe config types, a resolver that computes accessible lobes for a workspace, and sharing logic. The ContextEngine's `computeSourceWeights()` is modified to use the lobe resolver instead of hardcoded layers. Lobe config is stored as a JSON column on the workspaces table. Cross-user shares live in the entity graph's SQLite database.
8
+
9
+ **Tech Stack:** TypeScript, better-sqlite3 (entity graph DB), vitest
10
+
11
+ **Spec:** `docs/superpowers/specs/2026-03-16-cortex-lobes-design.md`
12
+
13
+ ---
14
+
15
+ ## File Structure
16
+
17
+ ```
18
+ New files:
19
+ ├── src/lib/cortex/lobes/config.ts — LobeConfig types and defaults
20
+ ├── src/lib/cortex/lobes/resolver.ts — Resolve accessible lobes for a workspace
21
+ ├── src/lib/cortex/lobes/shares.ts — Cross-user sharing (lobe_shares table)
22
+ ├── src/lib/cortex/lobes/index.ts — Barrel export
23
+ ├── src/app/api/cortex/lobes/route.ts — List lobes, update config
24
+ ├── src/app/api/cortex/lobes/share/route.ts — Share management
25
+ ├── src/components/cortex/lobe-settings.tsx — UI component for workspace settings
26
+
27
+ Test files:
28
+ ├── tests/lib/cortex/lobes/resolver.test.ts
29
+ ├── tests/lib/cortex/lobes/shares.test.ts
30
+
31
+ Modified files:
32
+ ├── src/lib/db/schema.ts — Add lobe_config column to workspaces
33
+ ├── src/lib/cortex/retrieval/context-engine.ts — Use lobe resolver for search scopes
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Chunk 1: Types, DB Migration, and Lobe Resolver
39
+
40
+ ### Task 1: Lobe config types and defaults
41
+
42
+ **Files:**
43
+ - Create: `src/lib/cortex/lobes/config.ts`
44
+
45
+ - [ ] **Step 1: Create the types file**
46
+
47
+ ```typescript
48
+ // src/lib/cortex/lobes/config.ts
49
+
50
+ export interface LobeSubscription {
51
+ type: 'workspace' | 'user' | 'tag' | 'team' | 'department' | 'organization';
52
+ id: string; // workspace ID, user entity ID, tag name, etc.
53
+ label: string; // display name
54
+ }
55
+
56
+ export interface LobeConfig {
57
+ isPrivate: boolean;
58
+ excludedFrom: number[]; // workspace IDs blocked from accessing this lobe
59
+ subscriptions: LobeSubscription[];
60
+ tags: string[];
61
+ }
62
+
63
+ export const DEFAULT_LOBE_CONFIG: LobeConfig = {
64
+ isPrivate: false,
65
+ excludedFrom: [],
66
+ subscriptions: [],
67
+ tags: [],
68
+ };
69
+
70
+ export function parseLobeConfig(raw: string | null | undefined): LobeConfig {
71
+ if (!raw) return { ...DEFAULT_LOBE_CONFIG };
72
+ try {
73
+ const parsed = JSON.parse(raw);
74
+ return {
75
+ isPrivate: parsed.isPrivate ?? false,
76
+ excludedFrom: Array.isArray(parsed.excludedFrom) ? parsed.excludedFrom : [],
77
+ subscriptions: Array.isArray(parsed.subscriptions) ? parsed.subscriptions : [],
78
+ tags: Array.isArray(parsed.tags) ? parsed.tags : [],
79
+ };
80
+ } catch {
81
+ return { ...DEFAULT_LOBE_CONFIG };
82
+ }
83
+ }
84
+
85
+ export function serializeLobeConfig(config: LobeConfig): string {
86
+ return JSON.stringify(config);
87
+ }
88
+ ```
89
+
90
+ - [ ] **Step 2: Commit**
91
+
92
+ ```bash
93
+ git add src/lib/cortex/lobes/config.ts
94
+ git commit -m "feat(cortex): add lobe config types and defaults"
95
+ ```
96
+
97
+ ---
98
+
99
+ ### Task 2: Database migration — add lobe_config column
100
+
101
+ **Files:**
102
+ - Modify: `src/lib/db/schema.ts`
103
+
104
+ - [ ] **Step 1: Read schema.ts to find the migration section**
105
+
106
+ Read `src/lib/db/schema.ts`. Find the section with `addCol` calls (around line 120+). Add:
107
+
108
+ ```typescript
109
+ addCol('workspaces', 'lobe_config', "TEXT DEFAULT '{}'");
110
+ ```
111
+
112
+ This adds a JSON text column to the existing workspaces table with an empty config default.
113
+
114
+ - [ ] **Step 2: Commit**
115
+
116
+ ```bash
117
+ git add src/lib/db/schema.ts
118
+ git commit -m "feat(cortex): add lobe_config column to workspaces table"
119
+ ```
120
+
121
+ ---
122
+
123
+ ### Task 3: Lobe resolver — compute accessible lobes for a workspace
124
+
125
+ **Files:**
126
+ - Create: `src/lib/cortex/lobes/resolver.ts`
127
+ - Create: `tests/lib/cortex/lobes/resolver.test.ts`
128
+
129
+ - [ ] **Step 1: Write failing tests**
130
+
131
+ ```typescript
132
+ // tests/lib/cortex/lobes/resolver.test.ts
133
+ import { describe, it, expect } from 'vitest';
134
+ import { resolveLobes } from '@/lib/cortex/lobes/resolver';
135
+ import type { LobeConfig } from '@/lib/cortex/lobes/config';
136
+ import { DEFAULT_LOBE_CONFIG } from '@/lib/cortex/lobes/config';
137
+
138
+ // Minimal workspace shape for testing
139
+ interface TestWorkspace {
140
+ id: number;
141
+ name: string;
142
+ lobeConfig: LobeConfig;
143
+ }
144
+
145
+ describe('resolveLobes', () => {
146
+ const workspaces: TestWorkspace[] = [
147
+ { id: 1, name: 'Auth Service', lobeConfig: DEFAULT_LOBE_CONFIG },
148
+ { id: 2, name: 'Frontend', lobeConfig: DEFAULT_LOBE_CONFIG },
149
+ { id: 3, name: 'Private Project', lobeConfig: { ...DEFAULT_LOBE_CONFIG, isPrivate: true } },
150
+ { id: 4, name: 'Excluded', lobeConfig: { ...DEFAULT_LOBE_CONFIG, excludedFrom: [1] } },
151
+ ];
152
+
153
+ it('includes own workspace lobe', () => {
154
+ const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
155
+ const keys = lobes.map(l => l.layerKey);
156
+ expect(keys).toContain('workspace/1');
157
+ });
158
+
159
+ it('includes personal lobe', () => {
160
+ const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
161
+ const keys = lobes.map(l => l.layerKey);
162
+ expect(keys).toContain('personal');
163
+ });
164
+
165
+ it('includes other non-private workspaces by default', () => {
166
+ const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
167
+ const keys = lobes.map(l => l.layerKey);
168
+ expect(keys).toContain('workspace/2');
169
+ });
170
+
171
+ it('excludes private workspaces', () => {
172
+ const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
173
+ const keys = lobes.map(l => l.layerKey);
174
+ expect(keys).not.toContain('workspace/3');
175
+ });
176
+
177
+ it('excludes workspaces that exclude the requester', () => {
178
+ // Workspace 4 excludes workspace 1
179
+ const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
180
+ const keys = lobes.map(l => l.layerKey);
181
+ expect(keys).not.toContain('workspace/4');
182
+ });
183
+
184
+ it('includes team lobe by default', () => {
185
+ const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: workspaces });
186
+ const keys = lobes.map(l => l.layerKey);
187
+ expect(keys).toContain('team');
188
+ });
189
+
190
+ it('includes explicit subscriptions', () => {
191
+ const ws: TestWorkspace[] = [
192
+ {
193
+ id: 1, name: 'Main',
194
+ lobeConfig: {
195
+ ...DEFAULT_LOBE_CONFIG,
196
+ subscriptions: [{ type: 'tag', id: 'infrastructure', label: 'Infrastructure' }],
197
+ },
198
+ },
199
+ ];
200
+ const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: ws });
201
+ const tags = lobes.filter(l => l.type === 'tag');
202
+ expect(tags).toHaveLength(1);
203
+ expect(tags[0].id).toBe('infrastructure');
204
+ });
205
+
206
+ it('assigns lower weight to subscribed lobes vs inherited', () => {
207
+ const ws: TestWorkspace[] = [
208
+ {
209
+ id: 1, name: 'Main',
210
+ lobeConfig: {
211
+ ...DEFAULT_LOBE_CONFIG,
212
+ subscriptions: [{ type: 'workspace', id: '99', label: 'Remote' }],
213
+ },
214
+ },
215
+ ];
216
+ const lobes = resolveLobes({ workspaceId: 1, allWorkspaces: ws });
217
+ const own = lobes.find(l => l.layerKey === 'workspace/1');
218
+ const subscribed = lobes.find(l => l.layerKey === 'workspace/99');
219
+ expect(own!.baseWeight).toBeGreaterThan(subscribed!.baseWeight);
220
+ });
221
+ });
222
+ ```
223
+
224
+ - [ ] **Step 2: Run tests to verify they fail**
225
+
226
+ Run: `npx vitest run tests/lib/cortex/lobes/resolver.test.ts`
227
+
228
+ - [ ] **Step 3: Implement lobe resolver**
229
+
230
+ ```typescript
231
+ // src/lib/cortex/lobes/resolver.ts
232
+ import type { LobeConfig, LobeSubscription } from './config';
233
+
234
+ export interface ResolvedLobe {
235
+ layerKey: string; // LanceDB storage path (e.g., 'workspace/42', 'personal', 'team')
236
+ label: string; // display name
237
+ type: 'own' | 'personal' | 'workspace' | 'team' | 'department' | 'organization' | 'tag' | 'user';
238
+ id: string; // source identifier
239
+ baseWeight: number; // base retrieval weight (before graph proximity)
240
+ inherited: boolean; // true if auto-inherited, false if explicitly subscribed
241
+ }
242
+
243
+ interface WorkspaceInfo {
244
+ id: number;
245
+ name: string;
246
+ lobeConfig: LobeConfig;
247
+ }
248
+
249
+ interface ResolveInput {
250
+ workspaceId: number;
251
+ allWorkspaces: WorkspaceInfo[];
252
+ userId?: string; // for personal lobe entity ID
253
+ }
254
+
255
+ /**
256
+ * Resolve the list of accessible knowledge lobes for a workspace.
257
+ *
258
+ * Default behavior: own workspace + personal + all non-private sibling workspaces + team + org.
259
+ * Respects privacy, exclusions, and explicit subscriptions.
260
+ */
261
+ export function resolveLobes(input: ResolveInput): ResolvedLobe[] {
262
+ const { workspaceId, allWorkspaces, userId } = input;
263
+ const lobes: ResolvedLobe[] = [];
264
+
265
+ const thisWs = allWorkspaces.find(w => w.id === workspaceId);
266
+ const thisConfig = thisWs?.lobeConfig;
267
+
268
+ // 1. Own workspace lobe (always included)
269
+ lobes.push({
270
+ layerKey: `workspace/${workspaceId}`,
271
+ label: thisWs?.name ?? 'This workspace',
272
+ type: 'own',
273
+ id: String(workspaceId),
274
+ baseWeight: 1.0,
275
+ inherited: true,
276
+ });
277
+
278
+ // 2. Personal lobe (always included)
279
+ lobes.push({
280
+ layerKey: 'personal',
281
+ label: 'Personal',
282
+ type: 'personal',
283
+ id: userId ?? 'personal',
284
+ baseWeight: 0.9,
285
+ inherited: true,
286
+ });
287
+
288
+ // 3. Other workspaces (same user) — included unless private or excluded
289
+ for (const ws of allWorkspaces) {
290
+ if (ws.id === workspaceId) continue;
291
+
292
+ // Skip if the other workspace is private
293
+ if (ws.lobeConfig.isPrivate) continue;
294
+
295
+ // Skip if the other workspace excludes this workspace
296
+ if (ws.lobeConfig.excludedFrom.includes(workspaceId)) continue;
297
+
298
+ lobes.push({
299
+ layerKey: `workspace/${ws.id}`,
300
+ label: ws.name,
301
+ type: 'workspace',
302
+ id: String(ws.id),
303
+ baseWeight: 0.6,
304
+ inherited: true,
305
+ });
306
+ }
307
+
308
+ // 4. Team / org inherited lobes
309
+ lobes.push({
310
+ layerKey: 'team',
311
+ label: 'Team',
312
+ type: 'team',
313
+ id: 'team',
314
+ baseWeight: 0.5,
315
+ inherited: true,
316
+ });
317
+
318
+ // 5. Explicit subscriptions from this workspace's config
319
+ if (thisConfig?.subscriptions) {
320
+ for (const sub of thisConfig.subscriptions) {
321
+ // Avoid duplicates
322
+ const layerKey = sub.type === 'workspace' ? `workspace/${sub.id}`
323
+ : sub.type === 'tag' ? `tag/${sub.id}`
324
+ : sub.type === 'team' ? `team/${sub.id}`
325
+ : sub.type === 'user' ? `user/${sub.id}`
326
+ : sub.id;
327
+
328
+ if (lobes.some(l => l.layerKey === layerKey)) continue;
329
+
330
+ lobes.push({
331
+ layerKey,
332
+ label: sub.label,
333
+ type: sub.type as ResolvedLobe['type'],
334
+ id: sub.id,
335
+ baseWeight: 0.4, // subscribed = lower weight than inherited
336
+ inherited: false,
337
+ });
338
+ }
339
+ }
340
+
341
+ return lobes;
342
+ }
343
+ ```
344
+
345
+ - [ ] **Step 4: Run tests to verify they pass**
346
+
347
+ Run: `npx vitest run tests/lib/cortex/lobes/resolver.test.ts`
348
+ Expected: PASS (8 tests)
349
+
350
+ - [ ] **Step 5: Commit**
351
+
352
+ ```bash
353
+ git add src/lib/cortex/lobes/resolver.ts tests/lib/cortex/lobes/resolver.test.ts
354
+ git commit -m "feat(cortex): add lobe resolver for workspace knowledge scoping"
355
+ ```
356
+
357
+ ---
358
+
359
+ ## Chunk 2: Cross-User Sharing and Context Engine Integration
360
+
361
+ ### Task 4: Cross-user lobe sharing
362
+
363
+ **Files:**
364
+ - Create: `src/lib/cortex/lobes/shares.ts`
365
+ - Create: `tests/lib/cortex/lobes/shares.test.ts`
366
+
367
+ - [ ] **Step 1: Write failing tests**
368
+
369
+ ```typescript
370
+ // tests/lib/cortex/lobes/shares.test.ts
371
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
372
+ import fs from 'fs';
373
+ import path from 'path';
374
+ import os from 'os';
375
+ import Database from 'better-sqlite3';
376
+ import { LobeShareStore } from '@/lib/cortex/lobes/shares';
377
+
378
+ describe('LobeShareStore', () => {
379
+ let tmpDir: string;
380
+ let store: LobeShareStore;
381
+
382
+ beforeEach(() => {
383
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'lobe-shares-'));
384
+ const db = new Database(path.join(tmpDir, 'test.db'));
385
+ store = new LobeShareStore(db);
386
+ });
387
+
388
+ afterEach(() => {
389
+ fs.rmSync(tmpDir, { recursive: true, force: true });
390
+ });
391
+
392
+ it('creates a share', () => {
393
+ const share = store.share({
394
+ ownerUserId: 'person-alice',
395
+ ownerWorkspaceId: 1,
396
+ ownerLobeName: 'Auth Service',
397
+ sharedWithUserId: 'person-bob',
398
+ });
399
+ expect(share.id).toBeDefined();
400
+ expect(share.accepted).toBe(false);
401
+ });
402
+
403
+ it('accepts a share', () => {
404
+ const share = store.share({
405
+ ownerUserId: 'person-alice',
406
+ ownerWorkspaceId: 1,
407
+ ownerLobeName: 'Auth Service',
408
+ sharedWithUserId: 'person-bob',
409
+ });
410
+ store.accept(share.id);
411
+ const updated = store.getShare(share.id);
412
+ expect(updated!.accepted).toBe(true);
413
+ });
414
+
415
+ it('lists incoming shares for a user', () => {
416
+ store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
417
+ store.share({ ownerUserId: 'person-charlie', ownerWorkspaceId: 2, ownerLobeName: 'WS2', sharedWithUserId: 'person-bob' });
418
+ const incoming = store.listIncoming('person-bob');
419
+ expect(incoming).toHaveLength(2);
420
+ });
421
+
422
+ it('lists outgoing shares for a user', () => {
423
+ store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
424
+ const outgoing = store.listOutgoing('person-alice');
425
+ expect(outgoing).toHaveLength(1);
426
+ });
427
+
428
+ it('revokes a share', () => {
429
+ const share = store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
430
+ store.revoke(share.id);
431
+ expect(store.getShare(share.id)).toBeNull();
432
+ });
433
+
434
+ it('prevents duplicate shares', () => {
435
+ store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
436
+ store.share({ ownerUserId: 'person-alice', ownerWorkspaceId: 1, ownerLobeName: 'WS1', sharedWithUserId: 'person-bob' });
437
+ const incoming = store.listIncoming('person-bob');
438
+ expect(incoming).toHaveLength(1);
439
+ });
440
+ });
441
+ ```
442
+
443
+ - [ ] **Step 2: Implement share store**
444
+
445
+ ```typescript
446
+ // src/lib/cortex/lobes/shares.ts
447
+ import type Database from 'better-sqlite3';
448
+
449
+ export interface LobeShare {
450
+ id: string;
451
+ ownerUserId: string;
452
+ ownerWorkspaceId: number;
453
+ ownerLobeName: string;
454
+ sharedWithUserId: string;
455
+ accepted: boolean;
456
+ created: string;
457
+ }
458
+
459
+ interface ShareInput {
460
+ ownerUserId: string;
461
+ ownerWorkspaceId: number;
462
+ ownerLobeName: string;
463
+ sharedWithUserId: string;
464
+ }
465
+
466
+ export class LobeShareStore {
467
+ private db: InstanceType<typeof Database>;
468
+
469
+ constructor(db: InstanceType<typeof Database>) {
470
+ this.db = db;
471
+ this.db.exec(`
472
+ CREATE TABLE IF NOT EXISTS lobe_shares (
473
+ id TEXT PRIMARY KEY,
474
+ owner_user_id TEXT NOT NULL,
475
+ owner_workspace_id INTEGER NOT NULL,
476
+ owner_lobe_name TEXT NOT NULL,
477
+ shared_with_user_id TEXT NOT NULL,
478
+ accepted INTEGER DEFAULT 0,
479
+ created TEXT NOT NULL,
480
+ UNIQUE(owner_user_id, owner_workspace_id, shared_with_user_id)
481
+ );
482
+ CREATE INDEX IF NOT EXISTS idx_lobe_shares_recipient ON lobe_shares(shared_with_user_id);
483
+ CREATE INDEX IF NOT EXISTS idx_lobe_shares_owner ON lobe_shares(owner_user_id);
484
+ `);
485
+ }
486
+
487
+ share(input: ShareInput): LobeShare {
488
+ const id = crypto.randomUUID();
489
+ const now = new Date().toISOString();
490
+
491
+ this.db.prepare(`
492
+ INSERT INTO lobe_shares (id, owner_user_id, owner_workspace_id, owner_lobe_name, shared_with_user_id, created)
493
+ VALUES (?, ?, ?, ?, ?, ?)
494
+ ON CONFLICT(owner_user_id, owner_workspace_id, shared_with_user_id) DO NOTHING
495
+ `).run(id, input.ownerUserId, input.ownerWorkspaceId, input.ownerLobeName, input.sharedWithUserId, now);
496
+
497
+ // Return existing if duplicate
498
+ const existing = this.db.prepare(
499
+ 'SELECT * FROM lobe_shares WHERE owner_user_id = ? AND owner_workspace_id = ? AND shared_with_user_id = ?'
500
+ ).get(input.ownerUserId, input.ownerWorkspaceId, input.sharedWithUserId) as any;
501
+
502
+ return this.rowToShare(existing);
503
+ }
504
+
505
+ accept(id: string): void {
506
+ this.db.prepare('UPDATE lobe_shares SET accepted = 1 WHERE id = ?').run(id);
507
+ }
508
+
509
+ revoke(id: string): void {
510
+ this.db.prepare('DELETE FROM lobe_shares WHERE id = ?').run(id);
511
+ }
512
+
513
+ getShare(id: string): LobeShare | null {
514
+ const row = this.db.prepare('SELECT * FROM lobe_shares WHERE id = ?').get(id) as any;
515
+ return row ? this.rowToShare(row) : null;
516
+ }
517
+
518
+ listIncoming(userId: string): LobeShare[] {
519
+ const rows = this.db.prepare(
520
+ 'SELECT * FROM lobe_shares WHERE shared_with_user_id = ? ORDER BY created DESC'
521
+ ).all(userId) as any[];
522
+ return rows.map(r => this.rowToShare(r));
523
+ }
524
+
525
+ listOutgoing(userId: string): LobeShare[] {
526
+ const rows = this.db.prepare(
527
+ 'SELECT * FROM lobe_shares WHERE owner_user_id = ? ORDER BY created DESC'
528
+ ).all(userId) as any[];
529
+ return rows.map(r => this.rowToShare(r));
530
+ }
531
+
532
+ listAcceptedForUser(userId: string): LobeShare[] {
533
+ const rows = this.db.prepare(
534
+ 'SELECT * FROM lobe_shares WHERE shared_with_user_id = ? AND accepted = 1'
535
+ ).all(userId) as any[];
536
+ return rows.map(r => this.rowToShare(r));
537
+ }
538
+
539
+ private rowToShare(row: any): LobeShare {
540
+ return {
541
+ id: row.id,
542
+ ownerUserId: row.owner_user_id,
543
+ ownerWorkspaceId: row.owner_workspace_id,
544
+ ownerLobeName: row.owner_lobe_name,
545
+ sharedWithUserId: row.shared_with_user_id,
546
+ accepted: row.accepted === 1,
547
+ created: row.created,
548
+ };
549
+ }
550
+ }
551
+ ```
552
+
553
+ - [ ] **Step 3: Run tests, commit**
554
+
555
+ Run: `npx vitest run tests/lib/cortex/lobes/shares.test.ts`
556
+
557
+ ```bash
558
+ git commit -m "feat(cortex): add cross-user lobe sharing with handshake"
559
+ ```
560
+
561
+ ---
562
+
563
+ ### Task 5: Integrate lobe resolver with Context Assembly Engine
564
+
565
+ **Files:**
566
+ - Modify: `src/lib/cortex/retrieval/context-engine.ts`
567
+
568
+ - [ ] **Step 1: Read context-engine.ts**
569
+
570
+ Read the file. Find `computeSourceWeights()` — the private method that returns hardcoded layer definitions.
571
+
572
+ - [ ] **Step 2: Add optional lobe-aware scope computation**
573
+
574
+ Add to `ContextEngineDeps`:
575
+ ```typescript
576
+ resolvedLobes?: ResolvedLobe[]; // pre-computed accessible lobes for this workspace
577
+ ```
578
+
579
+ Import:
580
+ ```typescript
581
+ import type { ResolvedLobe } from '../lobes/resolver';
582
+ ```
583
+
584
+ Modify `computeSourceWeights()` to use resolved lobes when available:
585
+
586
+ ```typescript
587
+ private computeSourceWeights(
588
+ intent: IntentResult,
589
+ workspaceId: number | null,
590
+ ): SourceConfig[] {
591
+ // If lobes are provided, use them instead of hardcoded layers
592
+ if (this.deps.resolvedLobes && this.deps.resolvedLobes.length > 0) {
593
+ return this.deps.resolvedLobes.map(lobe => {
594
+ const graphProximity = lobe.baseWeight; // lobes already have base weights
595
+
596
+ const weight = computeScopeWeight({
597
+ graphProximity,
598
+ scopeLevel: lobe.type === 'personal' ? 'personal'
599
+ : lobe.type === 'team' || lobe.type === 'department' ? 'team'
600
+ : lobe.type === 'organization' ? 'organization'
601
+ : 'team',
602
+ intentBiases: intent.biases,
603
+ authorityFactor: 1.0,
604
+ });
605
+
606
+ return {
607
+ layerKey: lobe.layerKey,
608
+ weight,
609
+ limit: Math.max(3, Math.round(weight * 10)),
610
+ };
611
+ }).sort((a, b) => b.weight - a.weight);
612
+ }
613
+
614
+ // Fallback: hardcoded layers (backward compat when no lobe config)
615
+ const layerDefs = [
616
+ // ... existing code unchanged ...
617
+ ];
618
+ // ... rest of existing method unchanged ...
619
+ }
620
+ ```
621
+
622
+ - [ ] **Step 3: Run existing context-engine tests to verify no regressions**
623
+
624
+ Run: `npx vitest run tests/lib/cortex/retrieval/context-engine.test.ts`
625
+
626
+ - [ ] **Step 4: Commit**
627
+
628
+ ```bash
629
+ git add src/lib/cortex/retrieval/context-engine.ts
630
+ git commit -m "feat(cortex): integrate lobe resolver into context assembly engine"
631
+ ```
632
+
633
+ ---
634
+
635
+ ## Chunk 3: API Routes and UI
636
+
637
+ ### Task 6: Lobe API endpoints
638
+
639
+ **Files:**
640
+ - Create: `src/app/api/cortex/lobes/route.ts`
641
+ - Create: `src/app/api/cortex/lobes/[id]/route.ts`
642
+ - Create: `src/app/api/cortex/lobes/share/route.ts`
643
+
644
+ - [ ] **Step 1: Create main lobes endpoint**
645
+
646
+ ```typescript
647
+ // src/app/api/cortex/lobes/route.ts
648
+ import { NextResponse } from 'next/server';
649
+ import type { NextRequest } from 'next/server';
650
+ import { getAuthUser, withUser } from '@/lib/auth';
651
+ import { getDb } from '@/lib/db';
652
+ import { parseLobeConfig } from '@/lib/cortex/lobes/config';
653
+
654
+ export async function GET(request: NextRequest) {
655
+ const user = getAuthUser(request);
656
+ return withUser(user, async () => {
657
+ const db = getDb();
658
+ const workspaces = db.prepare(
659
+ 'SELECT id, name, color, lobe_config FROM workspaces ORDER BY name'
660
+ ).all() as any[];
661
+
662
+ const lobes = workspaces.map(ws => ({
663
+ workspaceId: ws.id,
664
+ name: ws.name,
665
+ color: ws.color,
666
+ config: parseLobeConfig(ws.lobe_config),
667
+ }));
668
+
669
+ return NextResponse.json({ lobes });
670
+ });
671
+ }
672
+ ```
673
+
674
+ - [ ] **Step 2: Create single workspace lobe config endpoint**
675
+
676
+ ```typescript
677
+ // src/app/api/cortex/lobes/[id]/route.ts
678
+ import { NextResponse } from 'next/server';
679
+ import type { NextRequest } from 'next/server';
680
+ import { getAuthUser, withUser } from '@/lib/auth';
681
+ import { getDb } from '@/lib/db';
682
+ import { parseLobeConfig, serializeLobeConfig } from '@/lib/cortex/lobes/config';
683
+ import type { LobeConfig } from '@/lib/cortex/lobes/config';
684
+
685
+ export async function GET(
686
+ request: NextRequest,
687
+ { params }: { params: Promise<{ id: string }> },
688
+ ) {
689
+ const { id } = await params;
690
+ const user = getAuthUser(request);
691
+ return withUser(user, async () => {
692
+ const db = getDb();
693
+ const ws = db.prepare('SELECT id, name, lobe_config FROM workspaces WHERE id = ?').get(Number(id)) as any;
694
+ if (!ws) return NextResponse.json({ error: 'Workspace not found' }, { status: 404 });
695
+ return NextResponse.json({ workspaceId: ws.id, name: ws.name, config: parseLobeConfig(ws.lobe_config) });
696
+ });
697
+ }
698
+
699
+ export async function PUT(
700
+ request: NextRequest,
701
+ { params }: { params: Promise<{ id: string }> },
702
+ ) {
703
+ const { id } = await params;
704
+ const user = getAuthUser(request);
705
+ return withUser(user, async () => {
706
+ const db = getDb();
707
+ const body = await request.json() as Partial<LobeConfig>;
708
+
709
+ const ws = db.prepare('SELECT lobe_config FROM workspaces WHERE id = ?').get(Number(id)) as any;
710
+ if (!ws) return NextResponse.json({ error: 'Workspace not found' }, { status: 404 });
711
+
712
+ const current = parseLobeConfig(ws.lobe_config);
713
+ const updated: LobeConfig = {
714
+ isPrivate: body.isPrivate ?? current.isPrivate,
715
+ excludedFrom: body.excludedFrom ?? current.excludedFrom,
716
+ subscriptions: body.subscriptions ?? current.subscriptions,
717
+ tags: body.tags ?? current.tags,
718
+ };
719
+
720
+ db.prepare('UPDATE workspaces SET lobe_config = ? WHERE id = ?').run(serializeLobeConfig(updated), Number(id));
721
+ return NextResponse.json({ config: updated });
722
+ });
723
+ }
724
+ ```
725
+
726
+ - [ ] **Step 3: Create share endpoint**
727
+
728
+ ```typescript
729
+ // src/app/api/cortex/lobes/share/route.ts
730
+ import { NextResponse } from 'next/server';
731
+ import type { NextRequest } from 'next/server';
732
+ import { getAuthUser, withUser } from '@/lib/auth';
733
+ import { getCortex, isCortexAvailable } from '@/lib/cortex';
734
+ import { LobeShareStore } from '@/lib/cortex/lobes/shares';
735
+ import { slugify } from '@/lib/cortex/graph/types';
736
+
737
+ export async function GET(request: NextRequest) {
738
+ const user = getAuthUser(request);
739
+ return withUser(user, async () => {
740
+ if (!isCortexAvailable()) return NextResponse.json({ incoming: [], outgoing: [] });
741
+ const cortex = await getCortex();
742
+ if (!cortex) return NextResponse.json({ incoming: [], outgoing: [] });
743
+
744
+ const shareStore = new LobeShareStore(cortex.graph['db']);
745
+ const userId = `person-${slugify(user)}`;
746
+
747
+ return NextResponse.json({
748
+ incoming: shareStore.listIncoming(userId),
749
+ outgoing: shareStore.listOutgoing(userId),
750
+ });
751
+ });
752
+ }
753
+
754
+ export async function POST(request: NextRequest) {
755
+ const user = getAuthUser(request);
756
+ return withUser(user, async () => {
757
+ if (!isCortexAvailable()) return NextResponse.json({ error: 'Cortex unavailable' }, { status: 403 });
758
+ const cortex = await getCortex();
759
+ if (!cortex) return NextResponse.json({ error: 'Cortex unavailable' }, { status: 500 });
760
+
761
+ const body = await request.json();
762
+ const { action, shareId, workspaceId, lobeName, sharedWithUserId } = body;
763
+ const shareStore = new LobeShareStore(cortex.graph['db']);
764
+ const userId = `person-${slugify(user)}`;
765
+
766
+ if (action === 'share') {
767
+ const share = shareStore.share({
768
+ ownerUserId: userId,
769
+ ownerWorkspaceId: workspaceId,
770
+ ownerLobeName: lobeName,
771
+ sharedWithUserId,
772
+ });
773
+ return NextResponse.json({ share }, { status: 201 });
774
+ }
775
+
776
+ if (action === 'accept') {
777
+ shareStore.accept(shareId);
778
+ return NextResponse.json({ accepted: true });
779
+ }
780
+
781
+ if (action === 'revoke' || action === 'decline') {
782
+ shareStore.revoke(shareId);
783
+ return NextResponse.json({ revoked: true });
784
+ }
785
+
786
+ return NextResponse.json({ error: 'Invalid action' }, { status: 400 });
787
+ });
788
+ }
789
+ ```
790
+
791
+ - [ ] **Step 4: Commit**
792
+
793
+ ```bash
794
+ git add src/app/api/cortex/lobes/
795
+ git commit -m "feat(cortex): add lobe API endpoints for config and sharing"
796
+ ```
797
+
798
+ ---
799
+
800
+ ### Task 7: Lobe settings UI component
801
+
802
+ **Files:**
803
+ - Create: `src/components/cortex/lobe-settings.tsx`
804
+
805
+ - [ ] **Step 1: Create the component**
806
+
807
+ A settings panel showing the workspace's knowledge sources with toggles, tags, and subscription management.
808
+
809
+ ```typescript
810
+ 'use client';
811
+
812
+ import { useState, useEffect, useCallback } from 'react';
813
+ import { Shield, ShieldOff, Tag, Plus, X, Users } from 'lucide-react';
814
+ import { api } from '@/lib/api';
815
+ import type { LobeConfig, LobeSubscription } from '@/lib/cortex/lobes/config';
816
+
817
+ interface LobeSettingsProps {
818
+ workspaceId: number;
819
+ workspaceName: string;
820
+ }
821
+
822
+ export function LobeSettings({ workspaceId, workspaceName }: LobeSettingsProps) {
823
+ const [config, setConfig] = useState<LobeConfig | null>(null);
824
+ const [allLobes, setAllLobes] = useState<any[]>([]);
825
+ const [newTag, setNewTag] = useState('');
826
+ const [saving, setSaving] = useState(false);
827
+
828
+ const fetchConfig = useCallback(async () => {
829
+ const res = await fetch(api(`/api/cortex/lobes/${workspaceId}`));
830
+ if (res.ok) {
831
+ const data = await res.json();
832
+ setConfig(data.config);
833
+ }
834
+ }, [workspaceId]);
835
+
836
+ const fetchAllLobes = useCallback(async () => {
837
+ const res = await fetch(api('/api/cortex/lobes'));
838
+ if (res.ok) {
839
+ const data = await res.json();
840
+ setAllLobes(data.lobes || []);
841
+ }
842
+ }, []);
843
+
844
+ useEffect(() => { fetchConfig(); fetchAllLobes(); }, [fetchConfig, fetchAllLobes]);
845
+
846
+ const save = async (updates: Partial<LobeConfig>) => {
847
+ setSaving(true);
848
+ await fetch(api(`/api/cortex/lobes/${workspaceId}`), {
849
+ method: 'PUT',
850
+ headers: { 'Content-Type': 'application/json' },
851
+ body: JSON.stringify(updates),
852
+ });
853
+ await fetchConfig();
854
+ setSaving(false);
855
+ };
856
+
857
+ if (!config) return <div className="text-gray-500 text-sm p-4">Loading...</div>;
858
+
859
+ const activeSourceCount = allLobes.filter(l =>
860
+ l.workspaceId !== workspaceId && !l.config.isPrivate && !l.config.excludedFrom?.includes(workspaceId)
861
+ ).length + 2; // +2 for personal + team
862
+
863
+ return (
864
+ <div className="space-y-6">
865
+ <div>
866
+ <h3 className="text-sm font-medium text-gray-200 mb-1">Knowledge Lobes</h3>
867
+ <p className="text-xs text-gray-500">
868
+ This workspace draws from {activeSourceCount} lobes.
869
+ {config.isPrivate && ' This lobe is private — other workspaces cannot access its knowledge.'}
870
+ </p>
871
+ </div>
872
+
873
+ {/* Privacy toggle */}
874
+ <div className="flex items-center justify-between py-3 border-t border-white/5">
875
+ <div className="flex items-center gap-2">
876
+ {config.isPrivate ? <ShieldOff className="w-4 h-4 text-red-400" /> : <Shield className="w-4 h-4 text-green-400" />}
877
+ <div>
878
+ <div className="text-sm text-gray-200">Private lobe</div>
879
+ <div className="text-[10px] text-gray-500">Other workspaces cannot access this knowledge</div>
880
+ </div>
881
+ </div>
882
+ <button
883
+ onClick={() => save({ isPrivate: !config.isPrivate })}
884
+ disabled={saving}
885
+ className={`px-3 py-1 text-xs rounded ${config.isPrivate ? 'bg-red-500/20 text-red-400' : 'bg-white/5 text-gray-400'}`}
886
+ >
887
+ {config.isPrivate ? 'Private' : 'Open'}
888
+ </button>
889
+ </div>
890
+
891
+ {/* Tags */}
892
+ <div className="border-t border-white/5 pt-3">
893
+ <div className="flex items-center gap-2 mb-2">
894
+ <Tag className="w-3.5 h-3.5 text-gray-500" />
895
+ <span className="text-xs text-gray-400">Tags</span>
896
+ </div>
897
+ <div className="flex flex-wrap gap-1.5 mb-2">
898
+ {config.tags.map(tag => (
899
+ <span key={tag} className="flex items-center gap-1 text-[11px] bg-purple-500/10 text-purple-400 px-2 py-0.5 rounded">
900
+ {tag}
901
+ <button onClick={() => save({ tags: config.tags.filter(t => t !== tag) })} className="hover:text-white">
902
+ <X className="w-2.5 h-2.5" />
903
+ </button>
904
+ </span>
905
+ ))}
906
+ </div>
907
+ <div className="flex gap-1.5">
908
+ <input
909
+ value={newTag}
910
+ onChange={e => setNewTag(e.target.value)}
911
+ onKeyDown={e => {
912
+ if (e.key === 'Enter' && newTag.trim()) {
913
+ save({ tags: [...config.tags, newTag.trim()] });
914
+ setNewTag('');
915
+ }
916
+ }}
917
+ placeholder="Add tag..."
918
+ className="flex-1 px-2 py-1 text-xs bg-white/5 border border-white/10 rounded text-gray-300 focus:outline-none focus:border-purple-500/50"
919
+ />
920
+ </div>
921
+ </div>
922
+
923
+ {/* Subscriptions */}
924
+ <div className="border-t border-white/5 pt-3">
925
+ <div className="flex items-center gap-2 mb-2">
926
+ <Plus className="w-3.5 h-3.5 text-gray-500" />
927
+ <span className="text-xs text-gray-400">Additional sources</span>
928
+ </div>
929
+ {config.subscriptions.length === 0 ? (
930
+ <p className="text-[11px] text-gray-600">No additional subscriptions. Using defaults.</p>
931
+ ) : (
932
+ <div className="space-y-1">
933
+ {config.subscriptions.map((sub, i) => (
934
+ <div key={i} className="flex items-center justify-between text-xs bg-white/[0.02] rounded px-2 py-1.5">
935
+ <span className="text-gray-300">{sub.label} <span className="text-gray-600">({sub.type})</span></span>
936
+ <button
937
+ onClick={() => save({ subscriptions: config.subscriptions.filter((_, j) => j !== i) })}
938
+ className="text-gray-600 hover:text-red-400"
939
+ >
940
+ <X className="w-3 h-3" />
941
+ </button>
942
+ </div>
943
+ ))}
944
+ </div>
945
+ )}
946
+ </div>
947
+
948
+ {/* Exclusions */}
949
+ <div className="border-t border-white/5 pt-3">
950
+ <div className="flex items-center gap-2 mb-2">
951
+ <Users className="w-3.5 h-3.5 text-gray-500" />
952
+ <span className="text-xs text-gray-400">Excluded workspaces</span>
953
+ </div>
954
+ {config.excludedFrom.length === 0 ? (
955
+ <p className="text-[11px] text-gray-600">No exclusions. All workspaces can access this lobe.</p>
956
+ ) : (
957
+ <div className="space-y-1">
958
+ {config.excludedFrom.map(wsId => {
959
+ const ws = allLobes.find(l => l.workspaceId === wsId);
960
+ return (
961
+ <div key={wsId} className="flex items-center justify-between text-xs bg-white/[0.02] rounded px-2 py-1.5">
962
+ <span className="text-gray-300">{ws?.name || `Workspace ${wsId}`}</span>
963
+ <button
964
+ onClick={() => save({ excludedFrom: config.excludedFrom.filter(id => id !== wsId) })}
965
+ className="text-gray-600 hover:text-red-400"
966
+ >
967
+ <X className="w-3 h-3" />
968
+ </button>
969
+ </div>
970
+ );
971
+ })}
972
+ </div>
973
+ )}
974
+ </div>
975
+ </div>
976
+ );
977
+ }
978
+ ```
979
+
980
+ - [ ] **Step 2: Commit**
981
+
982
+ ```bash
983
+ git add src/components/cortex/lobe-settings.tsx
984
+ git commit -m "feat(cortex): add lobe settings UI component"
985
+ ```
986
+
987
+ ---
988
+
989
+ ### Task 8: Barrel export and wiring
990
+
991
+ **Files:**
992
+ - Create: `src/lib/cortex/lobes/index.ts`
993
+ - Modify: `src/app/(desktop)/cortex/page.tsx` — add Lobes section to Settings tab
994
+
995
+ - [ ] **Step 1: Create barrel export**
996
+
997
+ ```typescript
998
+ // src/lib/cortex/lobes/index.ts
999
+ export { parseLobeConfig, serializeLobeConfig, DEFAULT_LOBE_CONFIG } from './config';
1000
+ export type { LobeConfig, LobeSubscription } from './config';
1001
+ export { resolveLobes } from './resolver';
1002
+ export type { ResolvedLobe } from './resolver';
1003
+ export { LobeShareStore } from './shares';
1004
+ export type { LobeShare } from './shares';
1005
+ ```
1006
+
1007
+ - [ ] **Step 2: Add LobeSettings to the Cortex page Settings tab**
1008
+
1009
+ Read `src/app/(desktop)/cortex/page.tsx`. Find the Settings tab rendering. Currently it shows `<CortexSettings />`. Add `<LobeSettings>` below it, but only when a workspace is active. The workspace ID needs to come from somewhere — check how the terminal page gets `activeWorkspace`:
1010
+
1011
+ Read `src/app/(desktop)/terminal/page.tsx` to see how `activeWorkspace` is loaded. The pattern is likely a fetch to `/api/workspaces` with `is_active=1`.
1012
+
1013
+ For the Cortex page, add a simple workspace selector or use the active workspace. The simplest approach: fetch the active workspace and pass its ID to LobeSettings.
1014
+
1015
+ ```typescript
1016
+ // In CortexPage, add state:
1017
+ const [activeWorkspace, setActiveWorkspace] = useState<any>(null);
1018
+
1019
+ // Fetch active workspace:
1020
+ useEffect(() => {
1021
+ fetch(api('/api/workspaces'))
1022
+ .then(r => r.json())
1023
+ .then(data => {
1024
+ const active = (data.workspaces || []).find((w: any) => w.isActive);
1025
+ setActiveWorkspace(active);
1026
+ })
1027
+ .catch(() => {});
1028
+ }, []);
1029
+
1030
+ // In Settings tab rendering, add LobeSettings:
1031
+ {tab === 'settings' && (
1032
+ <div className="p-6 max-w-2xl space-y-8">
1033
+ <CortexSettings />
1034
+ {activeWorkspace && (
1035
+ <LobeSettings
1036
+ workspaceId={activeWorkspace.id}
1037
+ workspaceName={activeWorkspace.name}
1038
+ />
1039
+ )}
1040
+ </div>
1041
+ )}
1042
+ ```
1043
+
1044
+ Import: `import { LobeSettings } from '@/components/cortex/lobe-settings';`
1045
+
1046
+ - [ ] **Step 3: Run full test suite**
1047
+
1048
+ Run: `npx vitest run tests/lib/cortex/`
1049
+
1050
+ - [ ] **Step 4: Commit**
1051
+
1052
+ ```bash
1053
+ git add src/lib/cortex/lobes/index.ts src/app/(desktop)/cortex/page.tsx
1054
+ git commit -m "feat(cortex): wire lobe settings into Cortex page"
1055
+ ```
1056
+
1057
+ ---
1058
+
1059
+ ## Summary
1060
+
1061
+ | Task | Component | Tests | Status |
1062
+ |------|-----------|-------|--------|
1063
+ | 1 | Lobe config types | — | |
1064
+ | 2 | DB migration (lobe_config column) | — | |
1065
+ | 3 | Lobe resolver | 8 | |
1066
+ | 4 | Cross-user sharing | 6 | |
1067
+ | 5 | Context Engine integration | regression | |
1068
+ | 6 | API endpoints (3 files) | — | |
1069
+ | 7 | Lobe settings UI component | — | |
1070
+ | 8 | Barrel export + page wiring | regression | |
1071
+
1072
+ **Total: 8 tasks, ~14 new tests, 3 chunks**
1073
+
1074
+ **Key design decisions:**
1075
+ - Lobe config stored as JSON column on workspaces table (simple, always loaded with workspace)
1076
+ - Resolver computes accessible lobes at query time from workspace list + config
1077
+ - Cross-user shares use a separate SQLite table in the entity graph DB with two-step handshake
1078
+ - Context Engine uses resolved lobes when provided, falls back to hardcoded layers for backward compat
1079
+ - Privacy is safe-by-default: private workspaces are excluded, cross-user is closed by default
1080
+ - Base weights: own=1.0, personal=0.9, sibling workspaces=0.6, team=0.5, subscribed=0.4