agor-live 0.23.1 → 0.23.2

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 (469) hide show
  1. package/dist/core/claude/index.cjs +51 -27
  2. package/dist/core/claude/index.js +51 -27
  3. package/dist/core/claude-cli/index.cjs +13 -0
  4. package/dist/core/claude-cli/index.js +13 -0
  5. package/dist/core/claude-cli/pricing.d.ts.map +1 -1
  6. package/dist/core/client/index.cjs +17 -0
  7. package/dist/core/client/index.js +16 -0
  8. package/dist/core/db/index.cjs +618 -421
  9. package/dist/core/db/index.js +550 -353
  10. package/dist/core/db/repositories/boards.d.ts +27 -0
  11. package/dist/core/db/repositories/boards.d.ts.map +1 -1
  12. package/dist/core/db/repositories/branches.d.ts +11 -1
  13. package/dist/core/db/repositories/branches.d.ts.map +1 -1
  14. package/dist/core/db/repositories/gateway-channels.d.ts +9 -0
  15. package/dist/core/db/repositories/gateway-channels.d.ts.map +1 -1
  16. package/dist/core/db/repositories/sessions.d.ts +7 -0
  17. package/dist/core/db/repositories/sessions.d.ts.map +1 -1
  18. package/dist/core/environment/render-snapshot.cjs +6 -2
  19. package/dist/core/environment/render-snapshot.d.ts +2 -0
  20. package/dist/core/environment/render-snapshot.d.ts.map +1 -1
  21. package/dist/core/environment/render-snapshot.js +6 -2
  22. package/dist/core/environment/variable-resolver.cjs +3 -1
  23. package/dist/core/environment/variable-resolver.js +3 -1
  24. package/dist/core/index.cjs +684 -486
  25. package/dist/core/index.js +684 -486
  26. package/dist/core/lib/feathers-validation.cjs +3 -0
  27. package/dist/core/lib/feathers-validation.d.ts +1 -0
  28. package/dist/core/lib/feathers-validation.d.ts.map +1 -1
  29. package/dist/core/lib/feathers-validation.js +3 -0
  30. package/dist/core/local-actions/index.cjs +123 -56
  31. package/dist/core/local-actions/index.js +121 -54
  32. package/dist/core/mcp/index.cjs +21 -3
  33. package/dist/core/mcp/index.d.ts +1 -1
  34. package/dist/core/mcp/index.d.ts.map +1 -1
  35. package/dist/core/mcp/index.js +18 -3
  36. package/dist/core/mcp/template-patterns.d.ts +15 -0
  37. package/dist/core/mcp/template-patterns.d.ts.map +1 -0
  38. package/dist/core/mcp/template-resolver.d.ts +13 -0
  39. package/dist/core/mcp/template-resolver.d.ts.map +1 -1
  40. package/dist/core/models/browser.cjs +6 -0
  41. package/dist/core/models/browser.js +6 -0
  42. package/dist/core/models/claude.d.ts.map +1 -1
  43. package/dist/core/models/index.cjs +6 -0
  44. package/dist/core/models/index.js +6 -0
  45. package/dist/core/seed/index.cjs +360 -216
  46. package/dist/core/seed/index.js +329 -185
  47. package/dist/core/templates/handlebars-helpers.cjs +3 -1
  48. package/dist/core/templates/handlebars-helpers.d.ts +5 -0
  49. package/dist/core/templates/handlebars-helpers.d.ts.map +1 -1
  50. package/dist/core/templates/handlebars-helpers.js +3 -1
  51. package/dist/core/tools/mcp/auth-secrets.cjs +3460 -3
  52. package/dist/core/tools/mcp/auth-secrets.d.ts.map +1 -1
  53. package/dist/core/tools/mcp/auth-secrets.js +3477 -3
  54. package/dist/core/tools/mcp/http-headers.cjs +17 -1
  55. package/dist/core/tools/mcp/http-headers.d.ts.map +1 -1
  56. package/dist/core/tools/mcp/http-headers.js +15 -1
  57. package/dist/core/tools/mcp/oauth-refresh.cjs +67 -43
  58. package/dist/core/tools/mcp/oauth-refresh.js +65 -41
  59. package/dist/core/types/board.d.ts +12 -0
  60. package/dist/core/types/board.d.ts.map +1 -1
  61. package/dist/core/types/gateway.d.ts +14 -0
  62. package/dist/core/types/gateway.d.ts.map +1 -1
  63. package/dist/core/types/index.cjs +17 -0
  64. package/dist/core/types/index.js +16 -0
  65. package/dist/core/unix/index.cjs +67 -0
  66. package/dist/core/unix/index.js +67 -0
  67. package/dist/daemon/auth/executor-runtime-scope.d.ts.map +1 -1
  68. package/dist/daemon/auth/executor-runtime-scope.js +19 -5
  69. package/dist/daemon/auth/executor-session-token.d.ts +15 -0
  70. package/dist/daemon/auth/executor-session-token.d.ts.map +1 -0
  71. package/dist/daemon/auth/executor-session-token.js +17 -0
  72. package/dist/daemon/auth/issue-browser-tokens-hook.d.ts +24 -0
  73. package/dist/daemon/auth/issue-browser-tokens-hook.d.ts.map +1 -0
  74. package/dist/daemon/auth/issue-browser-tokens-hook.js +95 -0
  75. package/dist/daemon/auth/service-jwt-strategy.d.ts.map +1 -1
  76. package/dist/daemon/auth/service-jwt-strategy.js +14 -2
  77. package/dist/daemon/declarations.d.ts +1 -0
  78. package/dist/daemon/declarations.d.ts.map +1 -1
  79. package/dist/daemon/index.js +1365 -418
  80. package/dist/daemon/main.js +1365 -418
  81. package/dist/daemon/mcp/server.js +294 -31
  82. package/dist/daemon/mcp/tools/analytics.js +73 -24
  83. package/dist/daemon/mcp/tools/artifacts.js +73 -24
  84. package/dist/daemon/mcp/tools/boards.js +73 -24
  85. package/dist/daemon/mcp/tools/branches.js +73 -24
  86. package/dist/daemon/mcp/tools/card-types.js +73 -24
  87. package/dist/daemon/mcp/tools/cards.js +73 -24
  88. package/dist/daemon/mcp/tools/environment.js +73 -24
  89. package/dist/daemon/mcp/tools/gateway-channels.d.ts.map +1 -1
  90. package/dist/daemon/mcp/tools/gateway-channels.js +190 -38
  91. package/dist/daemon/mcp/tools/knowledge.js +73 -24
  92. package/dist/daemon/mcp/tools/mcp-servers.js +73 -24
  93. package/dist/daemon/mcp/tools/messages.js +73 -24
  94. package/dist/daemon/mcp/tools/proxies.js +73 -24
  95. package/dist/daemon/mcp/tools/repos.js +73 -24
  96. package/dist/daemon/mcp/tools/schedules.js +73 -24
  97. package/dist/daemon/mcp/tools/search.js +73 -24
  98. package/dist/daemon/mcp/tools/sessions.js +73 -24
  99. package/dist/daemon/mcp/tools/tasks.js +73 -24
  100. package/dist/daemon/mcp/tools/users.js +76 -27
  101. package/dist/daemon/mcp/tools/widgets.d.ts.map +1 -1
  102. package/dist/daemon/mcp/tools/widgets.js +257 -99
  103. package/dist/daemon/oauth-auth-helpers.d.ts +35 -0
  104. package/dist/daemon/oauth-auth-helpers.d.ts.map +1 -0
  105. package/dist/daemon/oauth-auth-helpers.js +14 -0
  106. package/dist/daemon/register-hooks.d.ts +1 -0
  107. package/dist/daemon/register-hooks.d.ts.map +1 -1
  108. package/dist/daemon/register-hooks.js +304 -53
  109. package/dist/daemon/register-routes.d.ts.map +1 -1
  110. package/dist/daemon/register-routes.js +738 -288
  111. package/dist/daemon/register-services.d.ts.map +1 -1
  112. package/dist/daemon/register-services.js +386 -155
  113. package/dist/daemon/services/boards.d.ts +5 -0
  114. package/dist/daemon/services/boards.d.ts.map +1 -1
  115. package/dist/daemon/services/boards.js +7 -0
  116. package/dist/daemon/services/branches.d.ts.map +1 -1
  117. package/dist/daemon/services/branches.js +31 -2
  118. package/dist/daemon/services/claude-models.d.ts.map +1 -1
  119. package/dist/daemon/services/claude-models.js +4 -1
  120. package/dist/daemon/services/gateway.d.ts +15 -0
  121. package/dist/daemon/services/gateway.d.ts.map +1 -1
  122. package/dist/daemon/services/gateway.js +34 -0
  123. package/dist/daemon/services/health-monitor.d.ts.map +1 -1
  124. package/dist/daemon/services/health-monitor.js +10 -7
  125. package/dist/daemon/services/session-streams.d.ts +29 -0
  126. package/dist/daemon/services/session-streams.d.ts.map +1 -0
  127. package/dist/daemon/services/session-streams.js +84 -0
  128. package/dist/daemon/services/session-token-service.d.ts.map +1 -1
  129. package/dist/daemon/services/session-token-service.js +8 -4
  130. package/dist/daemon/setup/index.js +43 -11
  131. package/dist/daemon/setup/socketio.d.ts.map +1 -1
  132. package/dist/daemon/setup/socketio.js +43 -11
  133. package/dist/daemon/startup.d.ts.map +1 -1
  134. package/dist/daemon/startup.js +37 -16
  135. package/dist/daemon/utils/authorization.js +19 -5
  136. package/dist/daemon/utils/emit-service-event.d.ts +56 -0
  137. package/dist/daemon/utils/emit-service-event.d.ts.map +1 -0
  138. package/dist/daemon/utils/emit-service-event.js +23 -0
  139. package/dist/daemon/utils/mcp-header-secrets.d.ts +3 -5
  140. package/dist/daemon/utils/mcp-header-secrets.d.ts.map +1 -1
  141. package/dist/daemon/utils/mcp-header-secrets.js +31 -2
  142. package/dist/daemon/utils/realtime-access-cache.d.ts +9 -0
  143. package/dist/daemon/utils/realtime-access-cache.d.ts.map +1 -1
  144. package/dist/daemon/utils/realtime-access-cache.js +24 -0
  145. package/dist/daemon/utils/realtime-publish.d.ts +24 -0
  146. package/dist/daemon/utils/realtime-publish.d.ts.map +1 -1
  147. package/dist/daemon/utils/realtime-publish.js +120 -2
  148. package/dist/daemon/utils/session-queue-tenant-scope.d.ts +24 -0
  149. package/dist/daemon/utils/session-queue-tenant-scope.d.ts.map +1 -0
  150. package/dist/daemon/utils/session-queue-tenant-scope.js +133 -0
  151. package/dist/daemon/widgets/gateway-token/index.d.ts +114 -0
  152. package/dist/daemon/widgets/gateway-token/index.d.ts.map +1 -0
  153. package/dist/daemon/widgets/gateway-token/index.js +14711 -0
  154. package/dist/daemon/widgets/index.d.ts.map +1 -1
  155. package/dist/daemon/widgets/index.js +190 -16
  156. package/dist/daemon/widgets/registry.d.ts +7 -0
  157. package/dist/daemon/widgets/registry.d.ts.map +1 -1
  158. package/dist/daemon/widgets/submissions.js +12 -9
  159. package/dist/executor/commands/git.d.ts.map +1 -1
  160. package/dist/executor/commands/git.js +2 -0
  161. package/dist/executor/db/feathers-repositories.d.ts +19 -1
  162. package/dist/executor/db/feathers-repositories.d.ts.map +1 -1
  163. package/dist/executor/db/feathers-repositories.js +31 -1
  164. package/dist/executor/handlers/sdk/claude.d.ts.map +1 -1
  165. package/dist/executor/handlers/sdk/claude.js +1 -1
  166. package/dist/executor/handlers/sdk/codex.d.ts.map +1 -1
  167. package/dist/executor/handlers/sdk/codex.js +1 -1
  168. package/dist/executor/handlers/sdk/copilot.d.ts.map +1 -1
  169. package/dist/executor/handlers/sdk/copilot.js +1 -1
  170. package/dist/executor/handlers/sdk/cursor.d.ts.map +1 -1
  171. package/dist/executor/handlers/sdk/cursor.js +1 -0
  172. package/dist/executor/handlers/sdk/gemini.d.ts.map +1 -1
  173. package/dist/executor/handlers/sdk/gemini.js +1 -1
  174. package/dist/executor/handlers/sdk/opencode.d.ts.map +1 -1
  175. package/dist/executor/handlers/sdk/opencode.js +1 -1
  176. package/dist/executor/payload-types.d.ts +5 -5
  177. package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts +8 -1
  178. package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts.map +1 -1
  179. package/dist/executor/sdk-handlers/base/mcp-scoping.js +58 -6
  180. package/dist/executor/sdk-handlers/claude/claude-tool.d.ts +2 -2
  181. package/dist/executor/sdk-handlers/claude/claude-tool.d.ts.map +1 -1
  182. package/dist/executor/sdk-handlers/claude/claude-tool.js +2 -2
  183. package/dist/executor/sdk-handlers/claude/prompt-service.d.ts +13 -3
  184. package/dist/executor/sdk-handlers/claude/prompt-service.d.ts.map +1 -1
  185. package/dist/executor/sdk-handlers/claude/prompt-service.js +16 -3
  186. package/dist/executor/sdk-handlers/claude/query-builder.d.ts +2 -1
  187. package/dist/executor/sdk-handlers/claude/query-builder.d.ts.map +1 -1
  188. package/dist/executor/sdk-handlers/claude/query-builder.js +2 -1
  189. package/dist/executor/sdk-handlers/codex/codex-tool.d.ts +2 -2
  190. package/dist/executor/sdk-handlers/codex/codex-tool.d.ts.map +1 -1
  191. package/dist/executor/sdk-handlers/codex/codex-tool.js +2 -2
  192. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts +3 -2
  193. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts.map +1 -1
  194. package/dist/executor/sdk-handlers/codex/prompt-service.js +70 -6
  195. package/dist/executor/sdk-handlers/copilot/copilot-tool.d.ts +2 -2
  196. package/dist/executor/sdk-handlers/copilot/copilot-tool.d.ts.map +1 -1
  197. package/dist/executor/sdk-handlers/copilot/copilot-tool.js +2 -2
  198. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts +3 -2
  199. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts.map +1 -1
  200. package/dist/executor/sdk-handlers/copilot/prompt-service.js +4 -1
  201. package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts +2 -2
  202. package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts.map +1 -1
  203. package/dist/executor/sdk-handlers/gemini/gemini-tool.js +2 -2
  204. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts +3 -2
  205. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts.map +1 -1
  206. package/dist/executor/sdk-handlers/gemini/prompt-service.js +4 -1
  207. package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts +3 -2
  208. package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts.map +1 -1
  209. package/dist/executor/sdk-handlers/opencode/opencode-tool.js +4 -1
  210. package/dist/executor/services/feathers-client.d.ts.map +1 -1
  211. package/dist/executor/services/feathers-client.js +119 -20
  212. package/dist/ui/assets/AgorEmojiPickerInner-leeNywMc.js +1 -0
  213. package/dist/ui/assets/App-Dpl4Cc0U.js +4 -0
  214. package/dist/ui/assets/App-Dpl4Cc0U.js.gz +0 -0
  215. package/dist/ui/assets/AppNode-wN3UZlFK.js +1 -0
  216. package/dist/ui/assets/AppNode-wN3UZlFK.js.gz +0 -0
  217. package/dist/ui/assets/{ArtifactConsentModal-oMMzRn8L.js → ArtifactConsentModal-DjzXcP_L.js} +1 -1
  218. package/dist/ui/assets/ArtifactConsentModal-DjzXcP_L.js.gz +0 -0
  219. package/dist/ui/assets/ArtifactFullscreenPage-B3b_EZ0F.js +9 -0
  220. package/dist/ui/assets/ArtifactFullscreenPage-B3b_EZ0F.js.gz +0 -0
  221. package/dist/ui/assets/ArtifactNode-DISy2T-6.js +9 -0
  222. package/dist/ui/assets/ArtifactNode-DISy2T-6.js.gz +0 -0
  223. package/dist/ui/assets/AutocompleteTextarea-DUpsoEGr.js +19 -0
  224. package/dist/ui/assets/AutocompleteTextarea-DUpsoEGr.js.gz +0 -0
  225. package/dist/ui/assets/BoardObjectNodes-BakeGpIX.js +34 -0
  226. package/dist/ui/assets/BoardObjectNodes-BakeGpIX.js.gz +0 -0
  227. package/dist/ui/assets/{CodeEditor.inner-Cuj6RuLL.js → CodeEditor.inner-HmSdTLW5.js} +1 -1
  228. package/dist/ui/assets/CodeEditor.inner-HmSdTLW5.js.gz +0 -0
  229. package/dist/ui/assets/ConversationView-mWaA-B1f.js +1 -0
  230. package/dist/ui/assets/ConversationView-mWaA-B1f.js.gz +0 -0
  231. package/dist/ui/assets/{EmbeddedTerminal-Lx5I9EOJ.js → EmbeddedTerminal-NNoyPA81.js} +1 -1
  232. package/dist/ui/assets/EmbeddedTerminal-NNoyPA81.js.gz +0 -0
  233. package/dist/ui/assets/KnowledgePage-CkxVnRvz.js +24 -0
  234. package/dist/ui/assets/KnowledgePage-CkxVnRvz.js.gz +0 -0
  235. package/dist/ui/assets/{MarketingScreenshotPage-CmDPBHOl.js → MarketingScreenshotPage-B86Gs8jx.js} +2 -2
  236. package/dist/ui/assets/MarketingScreenshotPage-B86Gs8jx.js.gz +0 -0
  237. package/dist/ui/assets/MobileApp-BPs-SXvz.js +1 -0
  238. package/dist/ui/assets/MobileApp-BPs-SXvz.js.gz +0 -0
  239. package/dist/ui/assets/SessionCanvas-xVfDoEtz.js +13 -0
  240. package/dist/ui/assets/SessionCanvas-xVfDoEtz.js.gz +0 -0
  241. package/dist/ui/assets/{StreamdownDemoPage-okKKR2QH.js → StreamdownDemoPage-CvWLzVsv.js} +2 -2
  242. package/dist/ui/assets/StreamdownDemoPage-CvWLzVsv.js.gz +0 -0
  243. package/dist/ui/assets/{TerminalModal-D9jMGZXv.js → TerminalModal-ExOgsuOP.js} +2 -2
  244. package/dist/ui/assets/TerminalModal-ExOgsuOP.js.gz +0 -0
  245. package/dist/ui/assets/ThemeSwitcher-Cgyp5ruu.js +1 -0
  246. package/dist/ui/assets/ThemeSwitcher-Cgyp5ruu.js.gz +0 -0
  247. package/dist/ui/assets/{ThemedSyntaxHighlighter.inner-C1FdIHn0.js → ThemedSyntaxHighlighter.inner-rpCN9S6K.js} +1 -1
  248. package/dist/ui/assets/{antd-DT5ackd0.js → antd-BCqimh1J.js} +5 -5
  249. package/dist/ui/assets/{antd-DT5ackd0.js.gz → antd-BCqimh1J.js.gz} +0 -0
  250. package/dist/ui/assets/architecture-U656AL7Q-BxSQIjrE.js +1 -0
  251. package/dist/ui/assets/{architectureDiagram-VXUJARFQ-DwTJGGoj.js → architectureDiagram-VXUJARFQ-pDpGHSqT.js} +1 -1
  252. package/dist/ui/assets/architectureDiagram-VXUJARFQ-pDpGHSqT.js.gz +0 -0
  253. package/dist/ui/assets/{blockDiagram-VD42YOAC-Dh1_TVW2.js → blockDiagram-VD42YOAC-uP8JTJpK.js} +1 -1
  254. package/dist/ui/assets/blockDiagram-VD42YOAC-uP8JTJpK.js.gz +0 -0
  255. package/dist/ui/assets/{c4Diagram-YG6GDRKO-B1e96AcB.js → c4Diagram-YG6GDRKO-qQe72Mm7.js} +1 -1
  256. package/dist/ui/assets/c4Diagram-YG6GDRKO-qQe72Mm7.js.gz +0 -0
  257. package/dist/ui/assets/channel-CoUBs6Zn.js +1 -0
  258. package/dist/ui/assets/{chunk-4BX2VUAB-BODpCjJx.js → chunk-4BX2VUAB-sz-YE8Nt.js} +1 -1
  259. package/dist/ui/assets/chunk-4ZMWKKQ3-3oKtfWXp.js +3 -0
  260. package/dist/ui/assets/chunk-4ZMWKKQ3-3oKtfWXp.js.gz +0 -0
  261. package/dist/ui/assets/chunk-55IACEB6-BS04dgKF.js +1 -0
  262. package/dist/ui/assets/{chunk-ABZYJK2D-DCTXWSzV.js → chunk-ABZYJK2D-t3Gkphds.js} +3 -3
  263. package/dist/ui/assets/chunk-ABZYJK2D-t3Gkphds.js.gz +0 -0
  264. package/dist/ui/assets/{chunk-AGHRB4JF-CbNphBjE.js → chunk-AGHRB4JF-D_QmWxbY.js} +1 -1
  265. package/dist/ui/assets/chunk-AGHRB4JF-D_QmWxbY.js.gz +0 -0
  266. package/dist/ui/assets/{chunk-ATLVNIR6-rWg3qxof.js → chunk-ATLVNIR6-Bmg7-Ufz.js} +1 -1
  267. package/dist/ui/assets/chunk-ATLVNIR6-Bmg7-Ufz.js.gz +0 -0
  268. package/dist/ui/assets/{chunk-B4BG7PRW-CgtLCbpE.js → chunk-B4BG7PRW-dnSEE1u-.js} +1 -1
  269. package/dist/ui/assets/chunk-B4BG7PRW-dnSEE1u-.js.gz +0 -0
  270. package/dist/ui/assets/{chunk-CVBHYZKI-DTL6Zgr0.js → chunk-CVBHYZKI-BStaYnF0.js} +1 -1
  271. package/dist/ui/assets/{chunk-DI55MBZ5-Dwvx2Kva.js → chunk-DI55MBZ5-28dvx6o3.js} +1 -1
  272. package/dist/ui/assets/chunk-DI55MBZ5-28dvx6o3.js.gz +0 -0
  273. package/dist/ui/assets/chunk-EXTU4WIE-X-FURkEh.js +1 -0
  274. package/dist/ui/assets/{chunk-FMBD7UC4-BogA_9CV.js → chunk-FMBD7UC4-C_63gC9S.js} +1 -1
  275. package/dist/ui/assets/{chunk-HN2XXSSU-2blQO3Gb.js → chunk-HN2XXSSU-UFD374KI.js} +1 -1
  276. package/dist/ui/assets/chunk-HN2XXSSU-UFD374KI.js.gz +0 -0
  277. package/dist/ui/assets/{chunk-JA3XYJ7Z-Cr1rmOui.js → chunk-JA3XYJ7Z-B60hLNeR.js} +1 -1
  278. package/dist/ui/assets/chunk-JA3XYJ7Z-B60hLNeR.js.gz +0 -0
  279. package/dist/ui/assets/{chunk-JZLCHNYA-BsgZ79Fa.js → chunk-JZLCHNYA-ButC6pwN.js} +1 -1
  280. package/dist/ui/assets/chunk-JZLCHNYA-ButC6pwN.js.gz +0 -0
  281. package/dist/ui/assets/{chunk-MI3HLSF2-dwYeUy5S.js → chunk-MI3HLSF2-BivYzoSV.js} +1 -1
  282. package/dist/ui/assets/chunk-MI3HLSF2-BivYzoSV.js.gz +0 -0
  283. package/dist/ui/assets/chunk-N4CR4FBY-mVWzo5wJ.js +2 -0
  284. package/dist/ui/assets/chunk-N4CR4FBY-mVWzo5wJ.js.gz +0 -0
  285. package/dist/ui/assets/{chunk-QN33PNHL-DxdIDCAa.js → chunk-QN33PNHL-tXtHZpaG.js} +1 -1
  286. package/dist/ui/assets/{chunk-QXUST7PY-BCK2V0i-.js → chunk-QXUST7PY-DATib_Vv.js} +1 -1
  287. package/dist/ui/assets/chunk-QXUST7PY-DATib_Vv.js.gz +0 -0
  288. package/dist/ui/assets/chunk-QZHKN3VN-y6l249e5.js +1 -0
  289. package/dist/ui/assets/{chunk-S3R3BYOJ-GP3zIxrB.js → chunk-S3R3BYOJ-BEtfmflI.js} +1 -1
  290. package/dist/ui/assets/chunk-S3R3BYOJ-BEtfmflI.js.gz +0 -0
  291. package/dist/ui/assets/{chunk-TZMSLE5B-dX5RaM6g.js → chunk-TZMSLE5B-BY1ZtogK.js} +1 -1
  292. package/dist/ui/assets/chunk-TZMSLE5B-BY1ZtogK.js.gz +0 -0
  293. package/dist/ui/assets/classDiagram-2ON5EDUG-BYvq-uPY.js +1 -0
  294. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-BYvq-uPY.js +1 -0
  295. package/dist/ui/assets/constants-CYzQKfD1.js +1 -0
  296. package/dist/ui/assets/{cose-bilkent-S5V4N54A-Dx0BJVDl.js → cose-bilkent-S5V4N54A-DPvYrqGG.js} +1 -1
  297. package/dist/ui/assets/cose-bilkent-S5V4N54A-DPvYrqGG.js.gz +0 -0
  298. package/dist/ui/assets/{dagre-6UL2VRFP-DiQSUxqN.js → dagre-6UL2VRFP-D800J6qb.js} +1 -1
  299. package/dist/ui/assets/dagre-6UL2VRFP-D800J6qb.js.gz +0 -0
  300. package/dist/ui/assets/{dagre-Bekd9Vdj.js → dagre-TNc4wezg.js} +1 -1
  301. package/dist/ui/assets/dagre-TNc4wezg.js.gz +0 -0
  302. package/dist/ui/assets/{diagram-PSM6KHXK-DtJnDQjc.js → diagram-PSM6KHXK-CGdP9F-X.js} +1 -1
  303. package/dist/ui/assets/diagram-PSM6KHXK-CGdP9F-X.js.gz +0 -0
  304. package/dist/ui/assets/{diagram-QEK2KX5R-CobkCRdj.js → diagram-QEK2KX5R-BD5lOCe5.js} +1 -1
  305. package/dist/ui/assets/diagram-QEK2KX5R-BD5lOCe5.js.gz +0 -0
  306. package/dist/ui/assets/{diagram-S2PKOQOG-DHEZYivc.js → diagram-S2PKOQOG-cp3l22vN.js} +1 -1
  307. package/dist/ui/assets/diagram-S2PKOQOG-cp3l22vN.js.gz +0 -0
  308. package/dist/ui/assets/editor-Cr0W5BQI.js +39 -0
  309. package/dist/ui/assets/editor-Cr0W5BQI.js.gz +0 -0
  310. package/dist/ui/assets/{emoji-B0hLmSLZ.js → emoji-Bv3m24sO.js} +1 -1
  311. package/dist/ui/assets/emoji-Bv3m24sO.js.gz +0 -0
  312. package/dist/ui/assets/{erDiagram-Q2GNP2WA-BVNeTZPQ.js → erDiagram-Q2GNP2WA-CQSXRgqr.js} +1 -1
  313. package/dist/ui/assets/erDiagram-Q2GNP2WA-CQSXRgqr.js.gz +0 -0
  314. package/dist/ui/assets/{flowDiagram-NV44I4VS-C73VFdyk.js → flowDiagram-NV44I4VS-CKcKpkph.js} +1 -1
  315. package/dist/ui/assets/flowDiagram-NV44I4VS-CKcKpkph.js.gz +0 -0
  316. package/dist/ui/assets/{ganttDiagram-LVOFAZNH-B_RosuD1.js → ganttDiagram-LVOFAZNH-DlAHzXO5.js} +1 -1
  317. package/dist/ui/assets/ganttDiagram-LVOFAZNH-DlAHzXO5.js.gz +0 -0
  318. package/dist/ui/assets/{gitGraph-F6HP7TQM-DMFIqn4h.js → gitGraph-F6HP7TQM-DeuXy4B1.js} +1 -1
  319. package/dist/ui/assets/{gitGraphDiagram-NY62KEGX-hxbgwNA1.js → gitGraphDiagram-NY62KEGX-aB-AI4Vq.js} +1 -1
  320. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-aB-AI4Vq.js.gz +0 -0
  321. package/dist/ui/assets/index-B-qHc0o5.js +63 -0
  322. package/dist/ui/assets/index-B-qHc0o5.js.gz +0 -0
  323. package/dist/ui/assets/{info-NVLQJR56-DZ3K-w48.js → info-NVLQJR56-B9PG7xsc.js} +1 -1
  324. package/dist/ui/assets/{infoDiagram-ER5ION4S-CxnBJQu6.js → infoDiagram-ER5ION4S-C5Wpoqim.js} +1 -1
  325. package/dist/ui/assets/{journeyDiagram-XKPGCS4Q-CHYNj-f8.js → journeyDiagram-XKPGCS4Q-CHLziqfS.js} +1 -1
  326. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHLziqfS.js.gz +0 -0
  327. package/dist/ui/assets/{kanban-definition-3W4ZIXB7-DQPCCsj2.js → kanban-definition-3W4ZIXB7-Dq7GzQE_.js} +1 -1
  328. package/dist/ui/assets/kanban-definition-3W4ZIXB7-Dq7GzQE_.js.gz +0 -0
  329. package/dist/ui/assets/{line-DBRjKmfa.js → line-DHKNg83I.js} +1 -1
  330. package/dist/ui/assets/{linear-DFao5Wyp.js → linear-BvUfn0I8.js} +1 -1
  331. package/dist/ui/assets/linear-BvUfn0I8.js.gz +0 -0
  332. package/dist/ui/assets/{mermaid-parser.core-DYCfacHj.js → mermaid-parser.core-C6d9tKoo.js} +2 -2
  333. package/dist/ui/assets/mermaid-parser.core-C6d9tKoo.js.gz +0 -0
  334. package/dist/ui/assets/{mermaid.core-C6xGFSdE.js → mermaid.core-CxE5KezR.js} +3 -3
  335. package/dist/ui/assets/mermaid.core-CxE5KezR.js.gz +0 -0
  336. package/dist/ui/assets/{mindmap-definition-VGOIOE7T-L3Pw-YM7.js → mindmap-definition-VGOIOE7T-DmPoQ48w.js} +1 -1
  337. package/dist/ui/assets/mindmap-definition-VGOIOE7T-DmPoQ48w.js.gz +0 -0
  338. package/dist/ui/assets/{packet-BFZMPI3H-CpL6iNoa.js → packet-BFZMPI3H-JZEkVZxU.js} +1 -1
  339. package/dist/ui/assets/{particles-CT8hcJOA.js → particles-CxMmUw86.js} +1 -1
  340. package/dist/ui/assets/particles-CxMmUw86.js.gz +0 -0
  341. package/dist/ui/assets/{pie-7BOR55EZ-hTqChbTo.js → pie-7BOR55EZ-_1II5pYQ.js} +1 -1
  342. package/dist/ui/assets/{pieDiagram-ADFJNKIX-Bf4Nou75.js → pieDiagram-ADFJNKIX-DrNkH33i.js} +1 -1
  343. package/dist/ui/assets/pieDiagram-ADFJNKIX-DrNkH33i.js.gz +0 -0
  344. package/dist/ui/assets/{quadrantDiagram-AYHSOK5B-DpjUTLB1.js → quadrantDiagram-AYHSOK5B-DOpC-HEF.js} +1 -1
  345. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DOpC-HEF.js.gz +0 -0
  346. package/dist/ui/assets/{radar-NHE76QYJ-myy7OENC.js → radar-NHE76QYJ-DDmqhzEZ.js} +1 -1
  347. package/dist/ui/assets/{reactflow-Cubtnk8i.js → reactflow-D98uPOMq.js} +1 -1
  348. package/dist/ui/assets/reactflow-D98uPOMq.js.gz +0 -0
  349. package/dist/ui/assets/{requirementDiagram-UZGBJVZJ-Bfrfh-0-.js → requirementDiagram-UZGBJVZJ-Bzx0iEPP.js} +1 -1
  350. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bzx0iEPP.js.gz +0 -0
  351. package/dist/ui/assets/{sandpack-C58bwfIS.js → sandpack-059Z4UWP.js} +1 -1
  352. package/dist/ui/assets/sandpack-059Z4UWP.js.gz +0 -0
  353. package/dist/ui/assets/sandpackDefaults-CPMNDsw7.js +1 -0
  354. package/dist/ui/assets/sandpackDefaults-CPMNDsw7.js.gz +0 -0
  355. package/dist/ui/assets/{sankeyDiagram-TZEHDZUN-ClZAZ6va.js → sankeyDiagram-TZEHDZUN-Do9pvfDv.js} +1 -1
  356. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-Do9pvfDv.js.gz +0 -0
  357. package/dist/ui/assets/{sequenceDiagram-WL72ISMW-CNgly63p.js → sequenceDiagram-WL72ISMW-CN8neUTA.js} +1 -1
  358. package/dist/ui/assets/sequenceDiagram-WL72ISMW-CN8neUTA.js.gz +0 -0
  359. package/dist/ui/assets/{src-DAeyG22O.js → src-DEbsv3pp.js} +2 -2
  360. package/dist/ui/assets/src-DEbsv3pp.js.gz +0 -0
  361. package/dist/ui/assets/{stateDiagram-FKZM4ZOC-BrEAoDpE.js → stateDiagram-FKZM4ZOC-BluWJi8n.js} +1 -1
  362. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BluWJi8n.js.gz +0 -0
  363. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-DeyqBMDR.js +1 -0
  364. package/dist/ui/assets/{streamdown-BdAVfkeF.js → streamdown-BT1twtFc.js} +5 -5
  365. package/dist/ui/assets/streamdown-BT1twtFc.js.gz +0 -0
  366. package/dist/ui/assets/{syntax-BOfTnQiy.js → syntax-CBu6nLfm.js} +1 -1
  367. package/dist/ui/assets/syntax-CBu6nLfm.js.gz +0 -0
  368. package/dist/ui/assets/{timeline-definition-IT6M3QCI-CaRH3k4l.js → timeline-definition-IT6M3QCI-WdUNkiRj.js} +1 -1
  369. package/dist/ui/assets/timeline-definition-IT6M3QCI-WdUNkiRj.js.gz +0 -0
  370. package/dist/ui/assets/{treemap-KMMF4GRG-CUaLOV_B.js → treemap-KMMF4GRG-CoriU4Jl.js} +1 -1
  371. package/dist/ui/assets/{useUserLocalStorage-C8sgXgXR.js → useUserLocalStorage-GidNiOPC.js} +1 -1
  372. package/dist/ui/assets/useUserLocalStorage-GidNiOPC.js.gz +0 -0
  373. package/dist/ui/assets/{xychartDiagram-PRI3JC2R-BlhkI9T_.js → xychartDiagram-PRI3JC2R-CgBAKNt2.js} +1 -1
  374. package/dist/ui/assets/xychartDiagram-PRI3JC2R-CgBAKNt2.js.gz +0 -0
  375. package/dist/ui/index.html +9 -8
  376. package/dist/ui/index.html.gz +0 -0
  377. package/package.json +2 -2
  378. package/dist/ui/assets/AgorEmojiPickerInner-DQjr8M3_.js +0 -1
  379. package/dist/ui/assets/App-hJtcOxHv.js +0 -5
  380. package/dist/ui/assets/App-hJtcOxHv.js.gz +0 -0
  381. package/dist/ui/assets/AppNode-BhuMpn8O.js +0 -1
  382. package/dist/ui/assets/AppNode-BhuMpn8O.js.gz +0 -0
  383. package/dist/ui/assets/ArtifactConsentModal-oMMzRn8L.js.gz +0 -0
  384. package/dist/ui/assets/ArtifactFullscreenPage-B3wT8t8f.js +0 -9
  385. package/dist/ui/assets/ArtifactFullscreenPage-B3wT8t8f.js.gz +0 -0
  386. package/dist/ui/assets/ArtifactNode-BzQcrwFS.js +0 -9
  387. package/dist/ui/assets/ArtifactNode-BzQcrwFS.js.gz +0 -0
  388. package/dist/ui/assets/AutocompleteTextarea-Dau-V_30.js +0 -19
  389. package/dist/ui/assets/AutocompleteTextarea-Dau-V_30.js.gz +0 -0
  390. package/dist/ui/assets/BoardObjectNodes-DdKWv_ZT.js +0 -34
  391. package/dist/ui/assets/BoardObjectNodes-DdKWv_ZT.js.gz +0 -0
  392. package/dist/ui/assets/CodeEditor.inner-Cuj6RuLL.js.gz +0 -0
  393. package/dist/ui/assets/ConversationView-9-3ma1u-.js +0 -1
  394. package/dist/ui/assets/ConversationView-9-3ma1u-.js.gz +0 -0
  395. package/dist/ui/assets/EmbeddedTerminal-Lx5I9EOJ.js.gz +0 -0
  396. package/dist/ui/assets/KnowledgePage-Dz8YAMYC.js +0 -24
  397. package/dist/ui/assets/KnowledgePage-Dz8YAMYC.js.gz +0 -0
  398. package/dist/ui/assets/MarketingScreenshotPage-CmDPBHOl.js.gz +0 -0
  399. package/dist/ui/assets/MobileApp-BpgSG_gz.js +0 -1
  400. package/dist/ui/assets/MobileApp-BpgSG_gz.js.gz +0 -0
  401. package/dist/ui/assets/SessionCanvas-B6_mtlxK.js +0 -13
  402. package/dist/ui/assets/SessionCanvas-B6_mtlxK.js.gz +0 -0
  403. package/dist/ui/assets/StreamdownDemoPage-okKKR2QH.js.gz +0 -0
  404. package/dist/ui/assets/TerminalModal-D9jMGZXv.js.gz +0 -0
  405. package/dist/ui/assets/ThemeSwitcher-D9HgT37l.js +0 -1
  406. package/dist/ui/assets/ThemeSwitcher-D9HgT37l.js.gz +0 -0
  407. package/dist/ui/assets/architecture-U656AL7Q-DMnxkQRZ.js +0 -1
  408. package/dist/ui/assets/architectureDiagram-VXUJARFQ-DwTJGGoj.js.gz +0 -0
  409. package/dist/ui/assets/blockDiagram-VD42YOAC-Dh1_TVW2.js.gz +0 -0
  410. package/dist/ui/assets/c4Diagram-YG6GDRKO-B1e96AcB.js.gz +0 -0
  411. package/dist/ui/assets/channel-Jv4dT4S5.js +0 -1
  412. package/dist/ui/assets/chunk-55IACEB6-lJXvUquf.js +0 -1
  413. package/dist/ui/assets/chunk-ABZYJK2D-DCTXWSzV.js.gz +0 -0
  414. package/dist/ui/assets/chunk-AGHRB4JF-CbNphBjE.js.gz +0 -0
  415. package/dist/ui/assets/chunk-ATLVNIR6-rWg3qxof.js.gz +0 -0
  416. package/dist/ui/assets/chunk-B4BG7PRW-CgtLCbpE.js.gz +0 -0
  417. package/dist/ui/assets/chunk-DI55MBZ5-Dwvx2Kva.js.gz +0 -0
  418. package/dist/ui/assets/chunk-EXTU4WIE-DHyaqTsP.js +0 -1
  419. package/dist/ui/assets/chunk-HN2XXSSU-2blQO3Gb.js.gz +0 -0
  420. package/dist/ui/assets/chunk-JA3XYJ7Z-Cr1rmOui.js.gz +0 -0
  421. package/dist/ui/assets/chunk-JZLCHNYA-BsgZ79Fa.js.gz +0 -0
  422. package/dist/ui/assets/chunk-MI3HLSF2-dwYeUy5S.js.gz +0 -0
  423. package/dist/ui/assets/chunk-N4CR4FBY-DEMgSRVe.js +0 -2
  424. package/dist/ui/assets/chunk-N4CR4FBY-DEMgSRVe.js.gz +0 -0
  425. package/dist/ui/assets/chunk-QXUST7PY-BCK2V0i-.js.gz +0 -0
  426. package/dist/ui/assets/chunk-QZHKN3VN-CALjGrEE.js +0 -1
  427. package/dist/ui/assets/chunk-S3R3BYOJ-GP3zIxrB.js.gz +0 -0
  428. package/dist/ui/assets/chunk-TZMSLE5B-dX5RaM6g.js.gz +0 -0
  429. package/dist/ui/assets/classDiagram-2ON5EDUG-C3_RVP70.js +0 -1
  430. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-C3_RVP70.js +0 -1
  431. package/dist/ui/assets/constants-GjIDNVyt.js +0 -1
  432. package/dist/ui/assets/cose-bilkent-S5V4N54A-Dx0BJVDl.js.gz +0 -0
  433. package/dist/ui/assets/dagre-6UL2VRFP-DiQSUxqN.js.gz +0 -0
  434. package/dist/ui/assets/dagre-Bekd9Vdj.js.gz +0 -0
  435. package/dist/ui/assets/diagram-PSM6KHXK-DtJnDQjc.js.gz +0 -0
  436. package/dist/ui/assets/diagram-QEK2KX5R-CobkCRdj.js.gz +0 -0
  437. package/dist/ui/assets/diagram-S2PKOQOG-DHEZYivc.js.gz +0 -0
  438. package/dist/ui/assets/editor-DQIG-JYZ.js +0 -43
  439. package/dist/ui/assets/editor-DQIG-JYZ.js.gz +0 -0
  440. package/dist/ui/assets/emoji-B0hLmSLZ.js.gz +0 -0
  441. package/dist/ui/assets/erDiagram-Q2GNP2WA-BVNeTZPQ.js.gz +0 -0
  442. package/dist/ui/assets/flowDiagram-NV44I4VS-C73VFdyk.js.gz +0 -0
  443. package/dist/ui/assets/ganttDiagram-LVOFAZNH-B_RosuD1.js.gz +0 -0
  444. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-hxbgwNA1.js.gz +0 -0
  445. package/dist/ui/assets/index-DTz1Dif6.js +0 -64
  446. package/dist/ui/assets/index-DTz1Dif6.js.gz +0 -0
  447. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHYNj-f8.js.gz +0 -0
  448. package/dist/ui/assets/kanban-definition-3W4ZIXB7-DQPCCsj2.js.gz +0 -0
  449. package/dist/ui/assets/linear-DFao5Wyp.js.gz +0 -0
  450. package/dist/ui/assets/mermaid-parser.core-DYCfacHj.js.gz +0 -0
  451. package/dist/ui/assets/mermaid.core-C6xGFSdE.js.gz +0 -0
  452. package/dist/ui/assets/mindmap-definition-VGOIOE7T-L3Pw-YM7.js.gz +0 -0
  453. package/dist/ui/assets/particles-CT8hcJOA.js.gz +0 -0
  454. package/dist/ui/assets/pieDiagram-ADFJNKIX-Bf4Nou75.js.gz +0 -0
  455. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DpjUTLB1.js.gz +0 -0
  456. package/dist/ui/assets/reactflow-Cubtnk8i.js.gz +0 -0
  457. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bfrfh-0-.js.gz +0 -0
  458. package/dist/ui/assets/sandpack-C58bwfIS.js.gz +0 -0
  459. package/dist/ui/assets/sandpackDefaults-Bkga8XAE.js +0 -1
  460. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-ClZAZ6va.js.gz +0 -0
  461. package/dist/ui/assets/sequenceDiagram-WL72ISMW-CNgly63p.js.gz +0 -0
  462. package/dist/ui/assets/src-DAeyG22O.js.gz +0 -0
  463. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BrEAoDpE.js.gz +0 -0
  464. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-BNL52_oN.js +0 -1
  465. package/dist/ui/assets/streamdown-BdAVfkeF.js.gz +0 -0
  466. package/dist/ui/assets/syntax-BOfTnQiy.js.gz +0 -0
  467. package/dist/ui/assets/timeline-definition-IT6M3QCI-CaRH3k4l.js.gz +0 -0
  468. package/dist/ui/assets/useUserLocalStorage-C8sgXgXR.js.gz +0 -0
  469. package/dist/ui/assets/xychartDiagram-PRI3JC2R-BlhkI9T_.js.gz +0 -0
@@ -1,3 +1,3473 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/config/env-resolver.ts
8
+ import { eq as eq2 } from "drizzle-orm";
9
+
10
+ // src/db/database-wrapper.ts
11
+ import { sql } from "drizzle-orm";
12
+
13
+ // src/db/tenant-context.ts
14
+ import { AsyncLocalStorage } from "async_hooks";
15
+ var tenantDatabaseScope = new AsyncLocalStorage();
16
+
17
+ // src/db/encryption.ts
18
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
19
+
20
+ // src/db/repositories/session-env-selections.ts
21
+ import { and, eq } from "drizzle-orm";
22
+
23
+ // src/db/schema.postgres.ts
24
+ var schema_postgres_exports = {};
25
+ __export(schema_postgres_exports, {
26
+ appVariables: () => appVariables,
27
+ artifactTrustGrants: () => artifactTrustGrants,
28
+ artifacts: () => artifacts,
29
+ boardComments: () => boardComments,
30
+ boardGroupGrants: () => boardGroupGrants,
31
+ boardObjects: () => boardObjects,
32
+ boardOwners: () => boardOwners,
33
+ boards: () => boards,
34
+ branchGroupGrants: () => branchGroupGrants,
35
+ branchOwners: () => branchOwners,
36
+ branches: () => branches,
37
+ branchesRelations: () => branchesRelations,
38
+ cardTypes: () => cardTypes,
39
+ cards: () => cards,
40
+ gatewayChannels: () => gatewayChannels,
41
+ gatewayOutboundMessages: () => gatewayOutboundMessages,
42
+ groupMemberships: () => groupMemberships,
43
+ groups: () => groups,
44
+ kbDocumentUnits: () => kbDocumentUnits,
45
+ kbDocumentVersions: () => kbDocumentVersions,
46
+ kbDocuments: () => kbDocuments,
47
+ kbEmbeddingSpaces: () => kbEmbeddingSpaces,
48
+ kbGraphEdges: () => kbGraphEdges,
49
+ kbGraphNodes: () => kbGraphNodes,
50
+ kbNamespaceAcl: () => kbNamespaceAcl,
51
+ kbNamespaces: () => kbNamespaces,
52
+ mcpServers: () => mcpServers,
53
+ messages: () => messages,
54
+ repos: () => repos,
55
+ schedules: () => schedules,
56
+ schedulesRelations: () => schedulesRelations,
57
+ serializedSessions: () => serializedSessions,
58
+ sessionEnvSelections: () => sessionEnvSelections,
59
+ sessionMcpServers: () => sessionMcpServers,
60
+ sessionRelationships: () => sessionRelationships,
61
+ sessionRelationshipsRelations: () => sessionRelationshipsRelations,
62
+ sessions: () => sessions,
63
+ sessionsRelations: () => sessionsRelations,
64
+ tasks: () => tasks,
65
+ threadSessionMap: () => threadSessionMap,
66
+ userApiKeys: () => userApiKeys,
67
+ userMcpOauthTokens: () => userMcpOauthTokens,
68
+ users: () => users
69
+ });
70
+
71
+ // src/types/branch.ts
72
+ var BRANCH_PERMISSION_LEVELS = ["none", "view", "session", "prompt", "all"];
73
+
74
+ // src/types/session.ts
75
+ var SessionStatus = {
76
+ IDLE: "idle",
77
+ RUNNING: "running",
78
+ STOPPING: "stopping",
79
+ // Stop requested, waiting for task to stop
80
+ AWAITING_PERMISSION: "awaiting_permission",
81
+ AWAITING_INPUT: "awaiting_input",
82
+ // Legacy / pre-#1177: AskUserQuestion was disallowed at the SDK; new sessions never enter this state, kept for historical rows
83
+ TIMED_OUT: "timed_out",
84
+ // Permission/input request timed out, executor exited — user must re-prompt
85
+ COMPLETED: "completed",
86
+ FAILED: "failed"
87
+ };
88
+ var EXECUTING_SESSION_STATUSES = /* @__PURE__ */ new Set([
89
+ SessionStatus.RUNNING,
90
+ SessionStatus.STOPPING,
91
+ SessionStatus.AWAITING_PERMISSION,
92
+ SessionStatus.AWAITING_INPUT
93
+ ]);
94
+
95
+ // src/types/task.ts
96
+ var TaskStatus = {
97
+ QUEUED: "queued",
98
+ // Task created but not yet running (waiting for executor to drain queue)
99
+ CREATED: "created",
100
+ RUNNING: "running",
101
+ STOPPING: "stopping",
102
+ // Stop requested, waiting for SDK to halt
103
+ AWAITING_PERMISSION: "awaiting_permission",
104
+ AWAITING_INPUT: "awaiting_input",
105
+ // Legacy / pre-#1177: AskUserQuestion was disallowed at the SDK; new tasks never enter this state, kept for historical rows
106
+ TIMED_OUT: "timed_out",
107
+ // Permission/input request timed out, executor exited — user must re-prompt
108
+ COMPLETED: "completed",
109
+ FAILED: "failed",
110
+ STOPPED: "stopped"
111
+ // User-requested stop (distinct from failed)
112
+ };
113
+ var TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set([
114
+ TaskStatus.COMPLETED,
115
+ TaskStatus.FAILED,
116
+ TaskStatus.STOPPED,
117
+ TaskStatus.TIMED_OUT
118
+ ]);
119
+ var EXECUTING_TASK_STATUSES = /* @__PURE__ */ new Set([
120
+ TaskStatus.RUNNING,
121
+ TaskStatus.STOPPING,
122
+ TaskStatus.AWAITING_PERMISSION,
123
+ TaskStatus.AWAITING_INPUT
124
+ ]);
125
+
126
+ // src/types/user.ts
127
+ var ROLES = {
128
+ SUPERADMIN: "superadmin",
129
+ ADMIN: "admin",
130
+ MEMBER: "member",
131
+ VIEWER: "viewer"
132
+ };
133
+ var ROLE_OPTIONS = [
134
+ {
135
+ value: ROLES.SUPERADMIN,
136
+ label: "Superadmin",
137
+ description: "Full system access + branch RBAC bypass"
138
+ },
139
+ {
140
+ value: ROLES.ADMIN,
141
+ label: "Admin",
142
+ description: "Manage resources (users, MCP servers, config)"
143
+ },
144
+ { value: ROLES.MEMBER, label: "Member", description: "Standard user" },
145
+ { value: ROLES.VIEWER, label: "Viewer", description: "Read-only access" }
146
+ ];
147
+ var ROLE_RANK = {
148
+ [ROLES.VIEWER]: 0,
149
+ [ROLES.MEMBER]: 1,
150
+ [ROLES.ADMIN]: 2,
151
+ [ROLES.SUPERADMIN]: 3,
152
+ owner: 3
153
+ };
154
+
155
+ // src/db/schema.postgres.ts
156
+ import { relations, sql as sql2 } from "drizzle-orm";
157
+ import {
158
+ bigint,
159
+ boolean,
160
+ customType,
161
+ index,
162
+ integer,
163
+ jsonb,
164
+ pgTable,
165
+ primaryKey,
166
+ text,
167
+ timestamp,
168
+ uniqueIndex,
169
+ varchar
170
+ } from "drizzle-orm/pg-core";
171
+ var bytea = customType({
172
+ dataType() {
173
+ return "bytea";
174
+ }
175
+ });
176
+ var t = {
177
+ timestamp: (name) => timestamp(name, { mode: "date", withTimezone: true }),
178
+ bool: (name) => boolean(name),
179
+ json: (name) => jsonb(name).$type()
180
+ };
181
+ var sessions = pgTable(
182
+ "sessions",
183
+ {
184
+ tenant_id: text("tenant_id").notNull().default("default"),
185
+ // Primary identity
186
+ session_id: varchar("session_id", { length: 36 }).primaryKey(),
187
+ created_at: t.timestamp("created_at").notNull(),
188
+ updated_at: t.timestamp("updated_at"),
189
+ // User attribution
190
+ created_by: varchar("created_by", { length: 36 }).notNull(),
191
+ // Unix username for SDK impersonation (immutable once set)
192
+ // Set from creator's unix_username at session creation time
193
+ // NEVER changes, even if user's unix_username changes later
194
+ // This ensures SDK session data remains accessible in the original home directory
195
+ unix_username: text("unix_username"),
196
+ // Materialized for filtering/joins (cross-DB compatible)
197
+ status: text("status", {
198
+ enum: [
199
+ "idle",
200
+ "running",
201
+ "stopping",
202
+ "awaiting_permission",
203
+ "awaiting_input",
204
+ "timed_out",
205
+ "completed",
206
+ "failed"
207
+ ]
208
+ }).notNull(),
209
+ agentic_tool: text("agentic_tool", {
210
+ enum: ["claude-code", "claude-code-cli", "codex", "gemini", "opencode", "copilot", "cursor"]
211
+ }).notNull(),
212
+ board_id: varchar("board_id", { length: 36 }),
213
+ // NULL = no board
214
+ // Genealogy (materialized for tree queries)
215
+ parent_session_id: varchar("parent_session_id", { length: 36 }),
216
+ forked_from_session_id: varchar("forked_from_session_id", { length: 36 }),
217
+ // Branch reference (REQUIRED: all sessions must have a branch)
218
+ branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, {
219
+ onDelete: "cascade"
220
+ // Cascade delete sessions when branch is deleted
221
+ }),
222
+ // Scheduler tracking (materialized for deduplication and retention cleanup)
223
+ scheduled_run_at: bigint("scheduled_run_at", { mode: "number" }),
224
+ // Unix timestamp (ms) - authoritative run ID - bigint to support dates beyond 2038
225
+ scheduled_from_branch: t.bool("scheduled_from_branch").notNull().default(false),
226
+ // FK to schedules.schedule_id, ON DELETE SET NULL. Defined here (not
227
+ // just in the migration) so drizzle-kit / db introspection sees the
228
+ // constraint and so future schema diffs don't lose it.
229
+ schedule_id: varchar("schedule_id", { length: 36 }).references(
230
+ () => schedules.schedule_id,
231
+ { onDelete: "set null" }
232
+ ),
233
+ // UI state (materialized for efficient highlighting queries)
234
+ ready_for_prompt: t.bool("ready_for_prompt").notNull().default(false),
235
+ // Archive state (cascaded from branch archive)
236
+ archived: t.bool("archived").notNull().default(false),
237
+ archived_reason: text("archived_reason", {
238
+ enum: ["branch_archived", "manual", "btw_completed"]
239
+ }),
240
+ // JSON blob for everything else (cross-DB via json() type)
241
+ data: t.json("data").$type().notNull()
242
+ },
243
+ (table) => ({
244
+ tenantIdx: index("sessions_tenant_id_idx").on(table.tenant_id),
245
+ statusIdx: index("sessions_status_idx").on(table.status),
246
+ statusReadyIdx: index("sessions_status_ready_idx").on(table.status, table.ready_for_prompt),
247
+ agenticToolIdx: index("sessions_agentic_tool_idx").on(table.agentic_tool),
248
+ boardIdx: index("sessions_board_idx").on(table.board_id),
249
+ branchIdx: index("sessions_branch_idx").on(table.branch_id),
250
+ createdIdx: index("sessions_created_idx").on(table.created_at),
251
+ parentIdx: index("sessions_parent_idx").on(table.parent_session_id),
252
+ forkedIdx: index("sessions_forked_idx").on(table.forked_from_session_id),
253
+ // Scheduler indexes — including the partial unique index below.
254
+ scheduledFromBranchIdx: index("sessions_scheduled_flag_idx").on(table.scheduled_from_branch),
255
+ // Partial unique index — covering for the scheduler's dedup lookup
256
+ // AND serves as the DB-level guard against check-then-create races
257
+ // in spawnScheduledSession.
258
+ scheduleRunUnique: uniqueIndex("sessions_schedule_run_unique").on(table.tenant_id, table.schedule_id, table.scheduled_run_at).where(sql2`${table.schedule_id} IS NOT NULL AND ${table.scheduled_run_at} IS NOT NULL`)
259
+ })
260
+ );
261
+ var sessionRelationships = pgTable(
262
+ "session_relationships",
263
+ {
264
+ tenant_id: text("tenant_id").notNull().default("default"),
265
+ relationship_id: varchar("relationship_id", { length: 36 }).primaryKey(),
266
+ source_session_id: varchar("source_session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
267
+ target_session_id: varchar("target_session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
268
+ relationship_type: text("relationship_type", { enum: ["remote_create"] }).notNull(),
269
+ created_by: varchar("created_by", { length: 36 }).notNull(),
270
+ created_at: t.timestamp("created_at").notNull(),
271
+ updated_at: t.timestamp("updated_at"),
272
+ callback_enabled: t.bool("callback_enabled").notNull().default(false),
273
+ callback_session_id: varchar("callback_session_id", { length: 36 }).references(
274
+ () => sessions.session_id,
275
+ {
276
+ onDelete: "set null"
277
+ }
278
+ ),
279
+ data: t.json("data")
280
+ },
281
+ (table) => ({
282
+ tenantIdx: index("session_relationships_tenant_id_idx").on(table.tenant_id),
283
+ sourceIdx: index("session_relationships_source_idx").on(table.source_session_id),
284
+ targetIdx: index("session_relationships_target_idx").on(table.target_session_id),
285
+ callbackIdx: index("session_relationships_callback_idx").on(table.callback_session_id),
286
+ // Composite indexes so the OR predicate in dispatchCompletionCallbacks
287
+ // (WHERE source_session_id = $1 OR target_session_id = $2) uses BitmapOr
288
+ // over these instead of a full tenant table scan via tenant_id_idx.
289
+ tenantSourceIdx: index("session_relationships_tenant_source_idx").on(
290
+ table.tenant_id,
291
+ table.source_session_id
292
+ ),
293
+ tenantTargetIdx: index("session_relationships_tenant_target_idx").on(
294
+ table.tenant_id,
295
+ table.target_session_id
296
+ ),
297
+ sourceTargetTypeUnique: uniqueIndex("session_relationships_source_target_type_unique").on(
298
+ table.tenant_id,
299
+ table.source_session_id,
300
+ table.target_session_id,
301
+ table.relationship_type
302
+ )
303
+ })
304
+ );
305
+ var tasks = pgTable(
306
+ "tasks",
307
+ {
308
+ tenant_id: text("tenant_id").notNull().default("default"),
309
+ task_id: varchar("task_id", { length: 36 }).primaryKey(),
310
+ session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
311
+ created_at: t.timestamp("created_at").notNull(),
312
+ started_at: t.timestamp("started_at"),
313
+ completed_at: t.timestamp("completed_at"),
314
+ last_executor_heartbeat_at: t.timestamp("last_executor_heartbeat_at"),
315
+ status: text("status", {
316
+ enum: [
317
+ "queued",
318
+ "created",
319
+ "running",
320
+ "stopping",
321
+ "awaiting_permission",
322
+ "awaiting_input",
323
+ "timed_out",
324
+ "completed",
325
+ "failed",
326
+ "stopped"
327
+ ]
328
+ }).notNull(),
329
+ // Queue position (lower drains first); only populated for status='queued'
330
+ queue_position: integer("queue_position"),
331
+ // User attribution
332
+ created_by: varchar("created_by", { length: 36 }).notNull(),
333
+ // MD5 of SDK session file at task completion (only populated when stateless_fs_mode is enabled)
334
+ session_md5: text("session_md5"),
335
+ data: t.json("data").$type().notNull()
336
+ },
337
+ (table) => ({
338
+ tenantIdx: index("tasks_tenant_id_idx").on(table.tenant_id),
339
+ sessionIdx: index("tasks_session_idx").on(table.session_id),
340
+ statusIdx: index("tasks_status_idx").on(table.status),
341
+ createdIdx: index("tasks_created_idx").on(table.created_at),
342
+ // Composite for "latest task for session" queries (ORDER BY created_at DESC LIMIT 1).
343
+ sessionCreatedIdx: index("tasks_session_created_idx").on(table.session_id, table.created_at),
344
+ queueIdx: index("tasks_queue_idx").on(table.session_id, table.status, table.queue_position),
345
+ // Partial unique index — defense-in-depth for `tasks.createPending` race
346
+ // serialization. Only QUEUED rows are constrained; CREATED/RUNNING/done
347
+ // rows have NULL queue_position and are unaffected.
348
+ queuedPositionUnique: uniqueIndex("tasks_queued_position_unique").on(table.tenant_id, table.session_id, table.queue_position).where(sql2`${table.status} = 'queued'`)
349
+ })
350
+ );
351
+ var serializedSessions = pgTable(
352
+ "serialized_sessions",
353
+ {
354
+ tenant_id: text("tenant_id").notNull().default("default"),
355
+ id: varchar("id", { length: 36 }).primaryKey(),
356
+ session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
357
+ branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
358
+ task_id: varchar("task_id", { length: 36 }).references(() => tasks.task_id, {
359
+ onDelete: "set null"
360
+ }),
361
+ turn_index: integer("turn_index").notNull().default(0),
362
+ created_at: t.timestamp("created_at").notNull(),
363
+ md5: text("md5").notNull(),
364
+ status: text("status").notNull(),
365
+ // 'processing' | 'done' — validated at app layer
366
+ payload: bytea("payload")
367
+ // gzipped; NULL while status='processing'
368
+ },
369
+ (table) => ({
370
+ tenantIdx: index("serialized_sessions_tenant_id_idx").on(table.tenant_id),
371
+ sessionTurnIdx: index("serialized_sessions_session_turn_idx").on(
372
+ table.session_id,
373
+ table.turn_index
374
+ ),
375
+ branchIdx: index("serialized_sessions_branch_idx").on(table.branch_id)
376
+ })
377
+ );
378
+ var messages = pgTable(
379
+ "messages",
380
+ {
381
+ tenant_id: text("tenant_id").notNull().default("default"),
382
+ // Primary identity
383
+ message_id: varchar("message_id", { length: 36 }).primaryKey(),
384
+ created_at: t.timestamp("created_at").notNull(),
385
+ // Foreign keys (materialized for indexes)
386
+ session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
387
+ task_id: varchar("task_id", { length: 36 }).references(() => tasks.task_id, {
388
+ onDelete: "set null"
389
+ }),
390
+ // Materialized for queries
391
+ type: text("type", {
392
+ enum: [
393
+ "user",
394
+ "assistant",
395
+ "system",
396
+ "file-history-snapshot",
397
+ "permission_request",
398
+ "input_request",
399
+ "daemon_restart",
400
+ "daemon_crash",
401
+ "widget_request"
402
+ ]
403
+ }).notNull(),
404
+ role: text("role", {
405
+ enum: ["user", "assistant", "system"]
406
+ }).notNull(),
407
+ index: integer("index").notNull(),
408
+ // Position in conversation (0-based)
409
+ timestamp: t.timestamp("timestamp").notNull(),
410
+ content_preview: text("content_preview"),
411
+ // First 200 chars for list views
412
+ // Parent tool use ID (for nested tool calls - e.g., Task tool spawning Read/Grep)
413
+ parent_tool_use_id: text("parent_tool_use_id"),
414
+ // NOTE: queueing moved off `messages` and onto `tasks.status='queued'` as
415
+ // of migration sqlite/0040 (postgres/0030). The legacy `status` and
416
+ // `queue_position` columns are gone — see `tasks.queue_position` instead.
417
+ // Full data (JSON blob)
418
+ data: t.json("data").$type().notNull()
419
+ },
420
+ (table) => ({
421
+ tenantIdx: index("messages_tenant_id_idx").on(table.tenant_id),
422
+ tenantTimestampIdx: index("messages_tenant_timestamp_idx").on(table.tenant_id, table.timestamp),
423
+ // Indexes for efficient lookups
424
+ sessionIdx: index("messages_session_id_idx").on(table.session_id),
425
+ taskIdx: index("messages_task_id_idx").on(table.task_id),
426
+ sessionIndexIdx: index("messages_session_index_idx").on(table.session_id, table.index),
427
+ timestampIdx: index("messages_timestamp_idx").on(table.timestamp),
428
+ sessionTimestampIdx: index("messages_session_timestamp_idx").on(
429
+ table.session_id,
430
+ table.timestamp
431
+ )
432
+ })
433
+ );
434
+ var boards = pgTable(
435
+ "boards",
436
+ {
437
+ tenant_id: text("tenant_id").notNull().default("default"),
438
+ board_id: varchar("board_id", { length: 36 }).primaryKey(),
439
+ created_at: t.timestamp("created_at").notNull(),
440
+ updated_at: t.timestamp("updated_at"),
441
+ // User attribution
442
+ created_by: varchar("created_by", { length: 36 }).notNull(),
443
+ // Materialized for lookups
444
+ name: text("name").notNull(),
445
+ slug: text("slug"),
446
+ primary_assistant_id: varchar("primary_assistant_id", { length: 36 }).references(
447
+ () => branches.branch_id,
448
+ {
449
+ onDelete: "set null"
450
+ }
451
+ ),
452
+ // JSON blob for the rest
453
+ data: t.json("data").$type().notNull(),
454
+ // Archive state (for soft deletes)
455
+ archived: t.bool("archived").notNull().default(false),
456
+ archived_at: t.timestamp("archived_at"),
457
+ archived_by: varchar("archived_by", { length: 36 })
458
+ },
459
+ (table) => ({
460
+ tenantIdx: index("boards_tenant_id_idx").on(table.tenant_id),
461
+ nameIdx: index("boards_name_idx").on(table.name),
462
+ slugIdx: index("boards_slug_idx").on(table.slug),
463
+ slugTenantUnique: uniqueIndex("boards_tenant_slug_unique").on(table.tenant_id, table.slug)
464
+ })
465
+ );
466
+ var repos = pgTable(
467
+ "repos",
468
+ {
469
+ tenant_id: text("tenant_id").notNull().default("default"),
470
+ repo_id: varchar("repo_id", { length: 36 }).primaryKey(),
471
+ created_at: t.timestamp("created_at").notNull(),
472
+ updated_at: t.timestamp("updated_at"),
473
+ // Materialized for querying
474
+ slug: text("slug").notNull(),
475
+ repo_type: text("repo_type", { enum: ["remote", "local"] }).notNull().default("remote"),
476
+ // Unix group for repo-level git access (agor_rp_<short-id>)
477
+ // Users who have access to ANY branch in this repo get added to this group.
478
+ // Applied to repo Unix-group-managed paths:
479
+ // - repo root (non-recursive) for traversal into .git/worktrees/<name>
480
+ // - .git (recursive) for shared git objects/refs and git operations
481
+ unix_group: text("unix_group"),
482
+ data: t.json("data").$type().notNull()
483
+ },
484
+ (table) => ({
485
+ tenantIdx: index("repos_tenant_id_idx").on(table.tenant_id),
486
+ slugIdx: index("repos_slug_idx").on(table.slug),
487
+ slugTenantUnique: uniqueIndex("repos_tenant_slug_unique").on(table.tenant_id, table.slug)
488
+ })
489
+ );
490
+ var branches = pgTable(
491
+ "branches",
492
+ {
493
+ tenant_id: text("tenant_id").notNull().default("default"),
494
+ // Primary identity
495
+ branch_id: varchar("branch_id", { length: 36 }).primaryKey(),
496
+ repo_id: varchar("repo_id", { length: 36 }).notNull().references(() => repos.repo_id, { onDelete: "cascade" }),
497
+ created_at: t.timestamp("created_at").notNull(),
498
+ updated_at: t.timestamp("updated_at"),
499
+ // User attribution
500
+ created_by: varchar("created_by", { length: 36 }).notNull(),
501
+ // Materialized for queries
502
+ name: text("name").notNull(),
503
+ // "feat-auth", "main"
504
+ ref: text("ref").notNull(),
505
+ // Current branch/tag/commit
506
+ ref_type: text("ref_type", { enum: ["branch", "tag"] }),
507
+ // Type of ref (branch or tag)
508
+ branch_unique_id: integer("branch_unique_id").notNull(),
509
+ // Auto-assigned sequential ID for templates
510
+ // Environment configuration (static, initialized from templates, then user-editable)
511
+ start_command: text("start_command"),
512
+ // Start command (initialized from repo's up_command template)
513
+ stop_command: text("stop_command"),
514
+ // Stop command (initialized from repo's down_command template)
515
+ nuke_command: text("nuke_command"),
516
+ // Nuke command (initialized from repo's nuke_command template)
517
+ health_check_url: text("health_check_url"),
518
+ // Health check URL (initialized from repo's health_check.url_template)
519
+ app_url: text("app_url"),
520
+ // Application URL (initialized from repo's app_url_template)
521
+ logs_command: text("logs_command"),
522
+ // Logs command (initialized from repo's logs_command template)
523
+ // Name of the environment variant currently rendered into the command fields above.
524
+ // References a key under repo.environment.variants. Null for pre-v2 branches.
525
+ environment_variant: text("environment_variant"),
526
+ // Board relationship (nullable - branches can exist without boards)
527
+ board_id: varchar("board_id", { length: 36 }).references(() => boards.board_id, {
528
+ onDelete: "set null"
529
+ // If board is deleted, branch remains but loses board association
530
+ }),
531
+ // UI state (materialized for efficient highlighting queries)
532
+ needs_attention: t.bool("needs_attention").notNull().default(true),
533
+ // Default true for new branches
534
+ // Archive state (for soft deletes)
535
+ archived: t.bool("archived").notNull().default(false),
536
+ archived_at: t.timestamp("archived_at"),
537
+ archived_by: varchar("archived_by", { length: 36 }),
538
+ filesystem_status: text("filesystem_status", {
539
+ enum: ["creating", "ready", "failed", "preserved", "cleaned", "deleted"]
540
+ }),
541
+ // RBAC: App-layer permissions (rbac.md)
542
+ permission_source: text("permission_source", { enum: ["board", "override"] }).$type().notNull().default("override"),
543
+ others_can: text("others_can", {
544
+ enum: [...BRANCH_PERMISSION_LEVELS]
545
+ }).default("view"),
546
+ // RBAC: OS-layer permissions (unix-user-modes.md)
547
+ unix_group: text("unix_group"),
548
+ // e.g., 'agor_wt_abc123'
549
+ others_fs_access: text("others_fs_access", {
550
+ enum: ["none", "read", "write"]
551
+ }).$type().default("read"),
552
+ // Branch storage model — see context/explorations/clone-redesign.md.
553
+ // 'worktree' = native `git worktree add` (shared base .git/config — legacy default).
554
+ // 'clone' = self-standing `git clone` (own .git/ — closes cross-branch leak vectors).
555
+ //
556
+ // No DB-side CHECK: enum is validated at the Drizzle/TS/Zod/service
557
+ // layer to stay symmetric with the SQLite mirror (which can't easily
558
+ // alter CHECK constraints in place).
559
+ storage_mode: text("storage_mode", { enum: ["worktree", "clone"] }).notNull().default("worktree"),
560
+ // Only meaningful when storage_mode='clone'. NULL = full clone, positive
561
+ // integer = `git clone --depth N` (shallow). The service layer rejects
562
+ // a non-null clone_depth on worktree-mode rows.
563
+ clone_depth: integer("clone_depth"),
564
+ // JSON blob for everything else
565
+ data: t.json("data").$type().notNull()
566
+ },
567
+ (table) => ({
568
+ tenantIdx: index("branches_tenant_id_idx").on(table.tenant_id),
569
+ repoIdx: index("branches_repo_idx").on(table.repo_id),
570
+ nameIdx: index("branches_name_idx").on(table.name),
571
+ refIdx: index("branches_ref_idx").on(table.ref),
572
+ boardIdx: index("branches_board_idx").on(table.board_id),
573
+ createdIdx: index("branches_created_idx").on(table.created_at),
574
+ updatedIdx: index("branches_updated_idx").on(table.updated_at),
575
+ // Composite unique constraint (repo + name)
576
+ uniqueRepoName: index("branches_repo_name_unique").on(table.repo_id, table.name)
577
+ })
578
+ );
579
+ var branchOwners = pgTable(
580
+ "branch_owners",
581
+ {
582
+ tenant_id: text("tenant_id").notNull().default("default"),
583
+ branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
584
+ user_id: varchar("user_id", { length: 36 }).notNull().references(() => users.user_id, { onDelete: "cascade" }),
585
+ created_at: t.timestamp("created_at").defaultNow()
586
+ },
587
+ (table) => ({
588
+ tenantIdx: index("branch_owners_tenant_id_idx").on(table.tenant_id),
589
+ pk: primaryKey({ columns: [table.branch_id, table.user_id] })
590
+ })
591
+ );
592
+ var boardOwners = pgTable(
593
+ "board_owners",
594
+ {
595
+ tenant_id: text("tenant_id").notNull().default("default"),
596
+ board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
597
+ user_id: varchar("user_id", { length: 36 }).notNull().references(() => users.user_id, { onDelete: "cascade" }),
598
+ created_at: t.timestamp("created_at")
599
+ },
600
+ (table) => ({
601
+ tenantIdx: index("board_owners_tenant_id_idx").on(table.tenant_id),
602
+ pk: primaryKey({ columns: [table.board_id, table.user_id] }),
603
+ userIdx: index("board_owners_user_idx").on(table.user_id)
604
+ })
605
+ );
606
+ var schedules = pgTable(
607
+ "schedules",
608
+ {
609
+ tenant_id: text("tenant_id").notNull().default("default"),
610
+ schedule_id: varchar("schedule_id", { length: 36 }).primaryKey(),
611
+ branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
612
+ name: text("name").notNull(),
613
+ description: text("description"),
614
+ cron_expression: text("cron_expression").notNull(),
615
+ timezone_mode: text("timezone_mode", { enum: ["local", "utc"] }).notNull().default("local"),
616
+ timezone: text("timezone"),
617
+ prompt: text("prompt").notNull(),
618
+ agentic_tool_config: t.json("agentic_tool_config").notNull(),
619
+ enabled: t.bool("enabled").notNull().default(true),
620
+ allow_concurrent_runs: t.bool("allow_concurrent_runs").notNull().default(false),
621
+ retention: integer("retention").notNull().default(5),
622
+ last_run_at: bigint("last_run_at", { mode: "number" }),
623
+ last_run_session_id: varchar("last_run_session_id", { length: 36 }).references(
624
+ () => sessions.session_id,
625
+ { onDelete: "set null" }
626
+ ),
627
+ next_run_at: bigint("next_run_at", { mode: "number" }),
628
+ created_at: t.timestamp("created_at").notNull(),
629
+ updated_at: t.timestamp("updated_at").notNull(),
630
+ created_by: varchar("created_by", { length: 36 }).notNull().references(() => users.user_id)
631
+ },
632
+ (table) => ({
633
+ tenantIdx: index("schedules_tenant_id_idx").on(table.tenant_id),
634
+ enabledNextRunIdx: index("schedules_enabled_next_run_idx").on(table.enabled, table.next_run_at),
635
+ branchIdx: index("schedules_branch_idx").on(table.branch_id),
636
+ createdByIdx: index("schedules_created_by_idx").on(table.created_by)
637
+ })
638
+ );
639
+ var users = pgTable(
640
+ "users",
641
+ {
642
+ tenant_id: text("tenant_id").notNull().default("default"),
643
+ // Primary identity
644
+ user_id: varchar("user_id", { length: 36 }).primaryKey(),
645
+ created_at: t.timestamp("created_at").notNull(),
646
+ updated_at: t.timestamp("updated_at"),
647
+ // Materialized for auth lookups
648
+ email: text("email").notNull(),
649
+ password: text("password").notNull(),
650
+ // bcrypt hashed
651
+ // Basic profile (materialized for display)
652
+ name: text("name"),
653
+ emoji: text("emoji"),
654
+ role: text("role", {
655
+ enum: ["superadmin", "admin", "member", "viewer"]
656
+ // 'owner' is deprecated alias for 'superadmin'
657
+ }).notNull().default("member"),
658
+ // Unix username for process impersonation (optional, app-enforced uniqueness)
659
+ unix_username: text("unix_username"),
660
+ // Onboarding state
661
+ onboarding_completed: t.bool("onboarding_completed").notNull().default(false),
662
+ // Force password change flag (admin-settable, auto-cleared on password change)
663
+ must_change_password: t.bool("must_change_password").notNull().default(false),
664
+ // Auth invalidation marker. Password changes set this timestamp so any
665
+ // previously issued browser access or refresh token is rejected.
666
+ tokens_valid_after: t.timestamp("tokens_valid_after"),
667
+ // JSON blob for profile/preferences
668
+ data: t.json("data").$type().notNull()
669
+ },
670
+ (table) => ({
671
+ tenantIdx: index("users_tenant_id_idx").on(table.tenant_id),
672
+ emailIdx: index("users_email_idx").on(table.email),
673
+ emailTenantUnique: uniqueIndex("users_tenant_email_unique").on(table.tenant_id, table.email)
674
+ })
675
+ );
676
+ var groups = pgTable(
677
+ "groups",
678
+ {
679
+ tenant_id: text("tenant_id").notNull().default("default"),
680
+ group_id: varchar("group_id", { length: 36 }).primaryKey(),
681
+ name: text("name").notNull(),
682
+ slug: text("slug").notNull(),
683
+ description: text("description"),
684
+ archived: t.bool("archived").notNull().default(false),
685
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
686
+ onDelete: "set null"
687
+ }),
688
+ created_at: t.timestamp("created_at").notNull(),
689
+ updated_at: t.timestamp("updated_at")
690
+ },
691
+ (table) => ({
692
+ tenantIdx: index("groups_tenant_id_idx").on(table.tenant_id),
693
+ slugIdx: uniqueIndex("groups_tenant_slug_unique").on(table.tenant_id, table.slug),
694
+ archivedIdx: index("groups_archived_idx").on(table.archived)
695
+ })
696
+ );
697
+ var groupMemberships = pgTable(
698
+ "group_memberships",
699
+ {
700
+ tenant_id: text("tenant_id").notNull().default("default"),
701
+ group_id: varchar("group_id", { length: 36 }).notNull().references(() => groups.group_id, { onDelete: "cascade" }),
702
+ user_id: varchar("user_id", { length: 36 }).notNull().references(() => users.user_id, { onDelete: "cascade" }),
703
+ added_by: varchar("added_by", { length: 36 }).references(() => users.user_id, {
704
+ onDelete: "set null"
705
+ }),
706
+ created_at: t.timestamp("created_at").notNull()
707
+ },
708
+ (table) => ({
709
+ tenantIdx: index("group_memberships_tenant_id_idx").on(table.tenant_id),
710
+ pk: primaryKey({ columns: [table.group_id, table.user_id] }),
711
+ userIdx: index("group_memberships_user_idx").on(table.user_id)
712
+ })
713
+ );
714
+ var branchGroupGrants = pgTable(
715
+ "branch_group_grants",
716
+ {
717
+ tenant_id: text("tenant_id").notNull().default("default"),
718
+ branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
719
+ group_id: varchar("group_id", { length: 36 }).notNull().references(() => groups.group_id, { onDelete: "cascade" }),
720
+ can: text("can", { enum: [...BRANCH_PERMISSION_LEVELS] }).notNull().default("view"),
721
+ fs_access: text("fs_access", { enum: ["none", "read", "write"] }).$type(),
722
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
723
+ onDelete: "set null"
724
+ }),
725
+ created_at: t.timestamp("created_at").notNull(),
726
+ updated_at: t.timestamp("updated_at")
727
+ },
728
+ (table) => ({
729
+ tenantIdx: index("branch_group_grants_tenant_id_idx").on(table.tenant_id),
730
+ pk: primaryKey({ columns: [table.branch_id, table.group_id] }),
731
+ groupIdx: index("branch_group_grants_group_idx").on(table.group_id)
732
+ })
733
+ );
734
+ var boardGroupGrants = pgTable(
735
+ "board_group_grants",
736
+ {
737
+ tenant_id: text("tenant_id").notNull().default("default"),
738
+ board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
739
+ group_id: varchar("group_id", { length: 36 }).notNull().references(() => groups.group_id, { onDelete: "cascade" }),
740
+ can: text("can", { enum: [...BRANCH_PERMISSION_LEVELS] }).notNull().default("view"),
741
+ fs_access: text("fs_access", { enum: ["none", "read", "write"] }).$type(),
742
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
743
+ onDelete: "set null"
744
+ }),
745
+ created_at: t.timestamp("created_at").notNull(),
746
+ updated_at: t.timestamp("updated_at")
747
+ },
748
+ (table) => ({
749
+ tenantIdx: index("board_group_grants_tenant_id_idx").on(table.tenant_id),
750
+ pk: primaryKey({ columns: [table.board_id, table.group_id] }),
751
+ groupIdx: index("board_group_grants_group_idx").on(table.group_id)
752
+ })
753
+ );
754
+ var appVariables = pgTable(
755
+ "app_variables",
756
+ {
757
+ tenant_id: text("tenant_id").notNull().default("default"),
758
+ variable_id: varchar("variable_id", { length: 36 }).primaryKey(),
759
+ namespace: text("namespace").notNull(),
760
+ key: text("key").notNull(),
761
+ value_text: text("value_text"),
762
+ value_encrypted: text("value_encrypted"),
763
+ is_encrypted: t.bool("is_encrypted").notNull().default(false),
764
+ content_type: text("content_type").notNull().default("text/plain"),
765
+ metadata: t.json("metadata"),
766
+ updated_by: varchar("updated_by", { length: 36 }).references(() => users.user_id, {
767
+ onDelete: "set null"
768
+ }),
769
+ created_at: t.timestamp("created_at").notNull(),
770
+ updated_at: t.timestamp("updated_at").notNull()
771
+ },
772
+ (table) => ({
773
+ tenantIdx: index("app_variables_tenant_id_idx").on(table.tenant_id),
774
+ namespaceKeyIdx: uniqueIndex("app_variables_tenant_namespace_key_unique").on(
775
+ table.tenant_id,
776
+ table.namespace,
777
+ table.key
778
+ ),
779
+ namespaceIdx: index("app_variables_namespace_idx").on(table.namespace)
780
+ })
781
+ );
782
+ var userApiKeys = pgTable(
783
+ "user_api_keys",
784
+ {
785
+ tenant_id: text("tenant_id").notNull().default("default"),
786
+ id: varchar("id", { length: 36 }).primaryKey(),
787
+ user_id: varchar("user_id", { length: 36 }).notNull().references(() => users.user_id, { onDelete: "cascade" }),
788
+ name: text("name").notNull(),
789
+ prefix: text("prefix").notNull(),
790
+ // first 12 chars: 'agor_sk_XXXX' for identification
791
+ key_hash: text("key_hash").notNull(),
792
+ // bcrypt hash of full key
793
+ created_at: t.timestamp("created_at").notNull(),
794
+ last_used_at: t.timestamp("last_used_at")
795
+ },
796
+ (table) => ({
797
+ tenantIdx: index("user_api_keys_tenant_id_idx").on(table.tenant_id),
798
+ userIdx: index("user_api_keys_user_idx").on(table.user_id),
799
+ prefixIdx: index("user_api_keys_prefix_idx").on(table.prefix)
800
+ })
801
+ );
802
+ var mcpServers = pgTable(
803
+ "mcp_servers",
804
+ {
805
+ tenant_id: text("tenant_id").notNull().default("default"),
806
+ // Primary identity
807
+ mcp_server_id: varchar("mcp_server_id", { length: 36 }).primaryKey(),
808
+ created_at: t.timestamp("created_at").notNull(),
809
+ updated_at: t.timestamp("updated_at"),
810
+ // Materialized for filtering
811
+ name: text("name").notNull(),
812
+ // e.g., "filesystem", "sentry"
813
+ transport: text("transport", {
814
+ enum: ["stdio", "http", "sse"]
815
+ }).notNull(),
816
+ scope: text("scope", {
817
+ enum: ["global", "session"]
818
+ }).notNull(),
819
+ enabled: t.bool("enabled").notNull().default(true),
820
+ // Scope foreign key
821
+ // For 'global' scope: which user owns this server
822
+ // For 'session' scope: use session_mcp_servers junction table (many-to-many)
823
+ owner_user_id: varchar("owner_user_id", { length: 36 }),
824
+ // Source tracking (materialized for queries)
825
+ source: text("source", {
826
+ enum: ["user", "imported", "agor"]
827
+ }).notNull(),
828
+ // JSON blob for configuration and capabilities
829
+ data: t.json("data").$type().notNull()
830
+ },
831
+ (table) => ({
832
+ tenantIdx: index("mcp_servers_tenant_id_idx").on(table.tenant_id),
833
+ nameIdx: index("mcp_servers_name_idx").on(table.name),
834
+ scopeIdx: index("mcp_servers_scope_idx").on(table.scope),
835
+ ownerIdx: index("mcp_servers_owner_idx").on(table.owner_user_id),
836
+ enabledIdx: index("mcp_servers_enabled_idx").on(table.enabled)
837
+ })
838
+ );
839
+ var cardTypes = pgTable(
840
+ "card_types",
841
+ {
842
+ tenant_id: text("tenant_id").notNull().default("default"),
843
+ card_type_id: varchar("card_type_id", { length: 36 }).primaryKey(),
844
+ name: text("name").notNull(),
845
+ emoji: text("emoji"),
846
+ color: text("color"),
847
+ json_schema: text("json_schema"),
848
+ // JSON string of JSON Schema
849
+ created_by: varchar("created_by", { length: 36 }),
850
+ created_at: t.timestamp("created_at").notNull(),
851
+ updated_at: t.timestamp("updated_at").notNull()
852
+ },
853
+ (table) => ({
854
+ tenantIdx: index("card_types_tenant_id_idx").on(table.tenant_id),
855
+ nameIdx: index("card_types_name_idx").on(table.name)
856
+ })
857
+ );
858
+ var cards = pgTable(
859
+ "cards",
860
+ {
861
+ tenant_id: text("tenant_id").notNull().default("default"),
862
+ card_id: varchar("card_id", { length: 36 }).primaryKey(),
863
+ board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
864
+ card_type_id: varchar("card_type_id", { length: 36 }).references(() => cardTypes.card_type_id, {
865
+ onDelete: "set null"
866
+ }),
867
+ title: text("title").notNull(),
868
+ url: text("url"),
869
+ description: text("description"),
870
+ note: text("note"),
871
+ data: text("data"),
872
+ // JSON blob validated against CardType.json_schema if present
873
+ color_override: text("color_override"),
874
+ emoji_override: text("emoji_override"),
875
+ created_by: varchar("created_by", { length: 36 }),
876
+ created_at: t.timestamp("created_at").notNull(),
877
+ updated_at: t.timestamp("updated_at").notNull(),
878
+ archived: t.bool("archived").notNull().default(false),
879
+ archived_at: t.timestamp("archived_at")
880
+ },
881
+ (table) => ({
882
+ tenantIdx: index("cards_tenant_id_idx").on(table.tenant_id),
883
+ boardIdx: index("cards_board_idx").on(table.board_id),
884
+ cardTypeIdx: index("cards_card_type_idx").on(table.card_type_id),
885
+ titleIdx: index("cards_title_idx").on(table.title),
886
+ archivedIdx: index("cards_archived_idx").on(table.archived),
887
+ createdIdx: index("cards_created_idx").on(table.created_at)
888
+ })
889
+ );
890
+ var artifacts = pgTable(
891
+ "artifacts",
892
+ {
893
+ tenant_id: text("tenant_id").notNull().default("default"),
894
+ artifact_id: varchar("artifact_id", { length: 36 }).primaryKey(),
895
+ branch_id: varchar("branch_id", { length: 36 }).references(() => branches.branch_id, {
896
+ onDelete: "set null"
897
+ }),
898
+ source_session_id: varchar("source_session_id", { length: 36 }).references(
899
+ () => sessions.session_id,
900
+ {
901
+ onDelete: "set null"
902
+ }
903
+ ),
904
+ board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
905
+ name: text("name").notNull(),
906
+ description: text("description"),
907
+ path: text("path"),
908
+ // provenance only — where files were read from
909
+ template: text("template").notNull().default("react"),
910
+ build_status: text("build_status").notNull().default("unknown"),
911
+ build_errors: t.json("build_errors"),
912
+ content_hash: text("content_hash"),
913
+ files: t.json("files"),
914
+ dependencies: t.json("dependencies"),
915
+ entry: text("entry"),
916
+ // denormalized cache of the Sandpack entry file
917
+ sandpack_config: t.json("sandpack_config"),
918
+ required_env_vars: t.json("required_env_vars"),
919
+ agor_grants: t.json("agor_grants"),
920
+ agor_runtime: t.json("agor_runtime"),
921
+ public: t.bool("public").notNull().default(true),
922
+ created_by: varchar("created_by", { length: 36 }),
923
+ created_at: t.timestamp("created_at").notNull(),
924
+ updated_at: t.timestamp("updated_at").notNull(),
925
+ archived: t.bool("archived").notNull().default(false),
926
+ archived_at: t.timestamp("archived_at")
927
+ },
928
+ (table) => ({
929
+ tenantIdx: index("artifacts_tenant_id_idx").on(table.tenant_id),
930
+ branchIdx: index("artifacts_branch_idx").on(table.branch_id),
931
+ sourceSessionIdx: index("artifacts_source_session_idx").on(table.source_session_id),
932
+ boardIdx: index("artifacts_board_idx").on(table.board_id),
933
+ archivedIdx: index("artifacts_archived_idx").on(table.archived),
934
+ publicIdx: index("artifacts_public_idx").on(table.public)
935
+ })
936
+ );
937
+ var artifactTrustGrants = pgTable(
938
+ "artifact_trust_grants",
939
+ {
940
+ tenant_id: text("tenant_id").notNull().default("default"),
941
+ grant_id: varchar("grant_id", { length: 36 }).primaryKey(),
942
+ user_id: varchar("user_id", { length: 36 }).notNull(),
943
+ scope_type: text("scope_type").notNull(),
944
+ scope_value: text("scope_value"),
945
+ env_vars_set: t.json("env_vars_set").notNull(),
946
+ agor_grants_set: t.json("agor_grants_set").notNull(),
947
+ granted_at: t.timestamp("granted_at").notNull(),
948
+ revoked_at: t.timestamp("revoked_at")
949
+ },
950
+ (table) => ({
951
+ tenantIdx: index("artifact_trust_grants_tenant_id_idx").on(table.tenant_id),
952
+ userIdx: index("artifact_trust_grants_user_idx").on(table.user_id),
953
+ scopeIdx: index("artifact_trust_grants_scope_idx").on(table.scope_type, table.scope_value)
954
+ })
955
+ );
956
+ var boardObjects = pgTable(
957
+ "board_objects",
958
+ {
959
+ tenant_id: text("tenant_id").notNull().default("default"),
960
+ // Primary identity
961
+ object_id: varchar("object_id", { length: 36 }).primaryKey(),
962
+ board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
963
+ created_at: t.timestamp("created_at").notNull(),
964
+ // Polymorphic entity reference (exactly one must be set)
965
+ branch_id: varchar("branch_id", { length: 36 }).references(() => branches.branch_id, {
966
+ onDelete: "cascade"
967
+ }),
968
+ card_id: varchar("card_id", { length: 36 }).references(() => cards.card_id, {
969
+ onDelete: "cascade"
970
+ }),
971
+ // Position data (JSON)
972
+ data: t.json("data").$type().notNull()
973
+ },
974
+ (table) => ({
975
+ tenantIdx: index("board_objects_tenant_id_idx").on(table.tenant_id),
976
+ boardIdx: index("board_objects_board_idx").on(table.board_id),
977
+ branchIdx: index("board_objects_branch_idx").on(table.branch_id),
978
+ cardIdx: index("board_objects_card_idx").on(table.card_id)
979
+ })
980
+ );
981
+ var sessionMcpServers = pgTable(
982
+ "session_mcp_servers",
983
+ {
984
+ tenant_id: text("tenant_id").notNull().default("default"),
985
+ session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
986
+ mcp_server_id: varchar("mcp_server_id", { length: 36 }).notNull().references(() => mcpServers.mcp_server_id, { onDelete: "cascade" }),
987
+ enabled: t.bool("enabled").notNull().default(true),
988
+ added_at: t.timestamp("added_at").notNull()
989
+ },
990
+ (table) => ({
991
+ tenantIdx: index("session_mcp_servers_tenant_id_idx").on(table.tenant_id),
992
+ // Composite primary key
993
+ pk: index("session_mcp_servers_pk").on(table.session_id, table.mcp_server_id),
994
+ // Indexes for queries
995
+ sessionIdx: index("session_mcp_servers_session_idx").on(table.session_id),
996
+ serverIdx: index("session_mcp_servers_server_idx").on(table.mcp_server_id),
997
+ enabledIdx: index("session_mcp_servers_enabled_idx").on(table.session_id, table.enabled)
998
+ })
999
+ );
1000
+ var userMcpOauthTokens = pgTable(
1001
+ "user_mcp_oauth_tokens",
1002
+ {
1003
+ tenant_id: text("tenant_id").notNull().default("default"),
1004
+ // NULL = shared-mode token (one per mcp_server_id)
1005
+ user_id: varchar("user_id", { length: 36 }).references(() => users.user_id, {
1006
+ onDelete: "cascade"
1007
+ }),
1008
+ mcp_server_id: varchar("mcp_server_id", { length: 36 }).notNull().references(() => mcpServers.mcp_server_id, { onDelete: "cascade" }),
1009
+ oauth_access_token: text("oauth_access_token").notNull(),
1010
+ oauth_token_expires_at: t.timestamp("oauth_token_expires_at"),
1011
+ // Unix timestamp in milliseconds
1012
+ oauth_refresh_token: text("oauth_refresh_token"),
1013
+ // DCR / registered client credentials this grant was issued under.
1014
+ // Must be preserved across refreshes.
1015
+ oauth_client_id: text("oauth_client_id"),
1016
+ oauth_client_secret: text("oauth_client_secret"),
1017
+ created_at: t.timestamp("created_at").notNull(),
1018
+ updated_at: t.timestamp("updated_at")
1019
+ },
1020
+ (table) => ({
1021
+ tenantIdx: index("user_mcp_oauth_tokens_tenant_id_idx").on(table.tenant_id),
1022
+ // Composite lookup indexes. Uniqueness enforced via partial unique indexes
1023
+ // created in the migration (one for per-user rows, one for the shared row).
1024
+ pk: index("user_mcp_oauth_tokens_pk").on(table.user_id, table.mcp_server_id),
1025
+ userIdx: index("user_mcp_oauth_tokens_user_idx").on(table.user_id),
1026
+ serverIdx: index("user_mcp_oauth_tokens_server_idx").on(table.mcp_server_id)
1027
+ })
1028
+ );
1029
+ var boardComments = pgTable(
1030
+ "board_comments",
1031
+ {
1032
+ tenant_id: text("tenant_id").notNull().default("default"),
1033
+ // Primary identity
1034
+ comment_id: varchar("comment_id", { length: 36 }).primaryKey(),
1035
+ created_at: t.timestamp("created_at").notNull(),
1036
+ updated_at: t.timestamp("updated_at"),
1037
+ // Scoping & authorship
1038
+ board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
1039
+ created_by: varchar("created_by", { length: 36 }).notNull(),
1040
+ // FLEXIBLE ATTACHMENTS (all optional)
1041
+ // Phase 1: board-level only (all NULL)
1042
+ // Phase 2: object attachments (session, task, message, branch)
1043
+ // Phase 3: spatial positioning
1044
+ session_id: varchar("session_id", { length: 36 }).references(() => sessions.session_id, {
1045
+ onDelete: "set null"
1046
+ }),
1047
+ task_id: varchar("task_id", { length: 36 }).references(() => tasks.task_id, {
1048
+ onDelete: "set null"
1049
+ }),
1050
+ message_id: varchar("message_id", { length: 36 }).references(() => messages.message_id, {
1051
+ onDelete: "set null"
1052
+ }),
1053
+ branch_id: varchar("branch_id", { length: 36 }).references(() => branches.branch_id, {
1054
+ onDelete: "cascade"
1055
+ }),
1056
+ // Content (materialized for display)
1057
+ content: text("content").notNull(),
1058
+ // Markdown-supported text
1059
+ content_preview: text("content_preview").notNull(),
1060
+ // First 200 chars
1061
+ // Thread support (optional)
1062
+ parent_comment_id: varchar("parent_comment_id", { length: 36 }),
1063
+ // Metadata (materialized for filtering)
1064
+ resolved: t.bool("resolved").notNull().default(false),
1065
+ edited: t.bool("edited").notNull().default(false),
1066
+ // Reactions (for BOTH thread roots and replies)
1067
+ // Stored as JSON array: [{ user_id: "abc", emoji: "👍" }, ...]
1068
+ // Display grouped by emoji: { "👍": ["alice", "bob"], "🎉": ["charlie"] }
1069
+ reactions: t.json("reactions").$type().notNull().default(sql2`'[]'`),
1070
+ // JSON blob for advanced features
1071
+ data: t.json("data").$type().notNull()
1072
+ },
1073
+ (table) => ({
1074
+ tenantIdx: index("board_comments_tenant_id_idx").on(table.tenant_id),
1075
+ boardIdx: index("board_comments_board_idx").on(table.board_id),
1076
+ sessionIdx: index("board_comments_session_idx").on(table.session_id),
1077
+ taskIdx: index("board_comments_task_idx").on(table.task_id),
1078
+ messageIdx: index("board_comments_message_idx").on(table.message_id),
1079
+ branchIdx: index("board_comments_branch_idx").on(table.branch_id),
1080
+ createdByIdx: index("board_comments_created_by_idx").on(table.created_by),
1081
+ parentIdx: index("board_comments_parent_idx").on(table.parent_comment_id),
1082
+ createdIdx: index("board_comments_created_idx").on(table.created_at),
1083
+ resolvedIdx: index("board_comments_resolved_idx").on(table.resolved)
1084
+ })
1085
+ );
1086
+ var gatewayChannels = pgTable(
1087
+ "gateway_channels",
1088
+ {
1089
+ tenant_id: text("tenant_id").notNull().default("default"),
1090
+ // Primary identity
1091
+ id: varchar("id", { length: 36 }).primaryKey(),
1092
+ created_at: t.timestamp("created_at").notNull(),
1093
+ updated_at: t.timestamp("updated_at").notNull(),
1094
+ // User attribution
1095
+ created_by: varchar("created_by", { length: 36 }).notNull(),
1096
+ // Materialized for queries
1097
+ name: text("name").notNull(),
1098
+ channel_type: text("channel_type", {
1099
+ enum: ["slack", "discord", "whatsapp", "telegram", "github", "teams"]
1100
+ }).notNull(),
1101
+ target_branch_id: varchar("target_branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
1102
+ agor_user_id: varchar("agor_user_id", { length: 36 }).notNull(),
1103
+ channel_key: text("channel_key").notNull(),
1104
+ enabled: t.bool("enabled").notNull().default(true),
1105
+ last_message_at: t.timestamp("last_message_at"),
1106
+ // JSON blob for platform credentials (encrypted at rest)
1107
+ config: t.json("config").notNull(),
1108
+ // JSON blob for agentic tool configuration (agent, model, permission mode, etc.)
1109
+ agentic_config: t.json("agentic_config")
1110
+ },
1111
+ (table) => ({
1112
+ tenantIdx: index("gateway_channels_tenant_id_idx").on(table.tenant_id),
1113
+ channelKeyIdx: index("idx_gateway_channel_key").on(table.channel_key),
1114
+ channelKeyTenantUnique: uniqueIndex("gateway_channels_tenant_channel_key_unique").on(
1115
+ table.tenant_id,
1116
+ table.channel_key
1117
+ ),
1118
+ enabledTypeIdx: index("idx_gateway_enabled_type").on(table.enabled, table.channel_type)
1119
+ })
1120
+ );
1121
+ var threadSessionMap = pgTable(
1122
+ "thread_session_map",
1123
+ {
1124
+ tenant_id: text("tenant_id").notNull().default("default"),
1125
+ // Primary identity
1126
+ id: varchar("id", { length: 36 }).primaryKey(),
1127
+ created_at: t.timestamp("created_at").notNull(),
1128
+ last_message_at: t.timestamp("last_message_at").notNull(),
1129
+ // Foreign keys
1130
+ channel_id: varchar("channel_id", { length: 36 }).notNull().references(() => gatewayChannels.id, { onDelete: "cascade" }),
1131
+ thread_id: text("thread_id").notNull(),
1132
+ session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
1133
+ branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id),
1134
+ // Materialized for queries
1135
+ status: text("status", {
1136
+ enum: ["active", "archived", "paused"]
1137
+ }).notNull().default("active"),
1138
+ // JSON blob for extra metadata
1139
+ metadata: t.json("metadata")
1140
+ },
1141
+ (table) => ({
1142
+ tenantIdx: index("thread_session_map_tenant_id_idx").on(table.tenant_id),
1143
+ uniqueChannelThread: uniqueIndex("uniq_thread_map_tenant_channel_thread").on(
1144
+ table.tenant_id,
1145
+ table.channel_id,
1146
+ table.thread_id
1147
+ ),
1148
+ sessionIdx: index("idx_thread_map_session_id").on(table.session_id),
1149
+ threadIdx: index("idx_thread_map_thread_id").on(table.thread_id),
1150
+ channelStatusIdx: index("idx_thread_map_channel_status").on(table.channel_id, table.status)
1151
+ })
1152
+ );
1153
+ var gatewayOutboundMessages = pgTable(
1154
+ "gateway_outbound_messages",
1155
+ {
1156
+ tenant_id: text("tenant_id").notNull().default("default"),
1157
+ id: varchar("id", { length: 36 }).primaryKey(),
1158
+ created_at: t.timestamp("created_at").notNull(),
1159
+ updated_at: t.timestamp("updated_at").notNull(),
1160
+ gateway_channel_id: varchar("gateway_channel_id", { length: 36 }).notNull().references(() => gatewayChannels.id, { onDelete: "cascade" }),
1161
+ channel_type: text("channel_type", {
1162
+ enum: ["slack", "discord", "whatsapp", "telegram", "github", "teams"]
1163
+ }).notNull(),
1164
+ platform_channel_id: text("platform_channel_id").notNull(),
1165
+ platform_message_id: text("platform_message_id").notNull(),
1166
+ platform_thread_id: text("platform_thread_id").notNull(),
1167
+ platform_permalink: text("platform_permalink"),
1168
+ target_branch_id: varchar("target_branch_id", { length: 36 }).notNull().references(() => branches.branch_id),
1169
+ emitted_by_user_id: varchar("emitted_by_user_id", { length: 36 }).notNull().references(() => users.user_id),
1170
+ emitted_by_session_id: varchar("emitted_by_session_id", { length: 36 }).references(
1171
+ () => sessions.session_id,
1172
+ {
1173
+ onDelete: "set null"
1174
+ }
1175
+ ),
1176
+ emitted_by_task_id: varchar("emitted_by_task_id", { length: 36 }).references(
1177
+ () => tasks.task_id,
1178
+ {
1179
+ onDelete: "set null"
1180
+ }
1181
+ ),
1182
+ emitted_by_schedule_id: varchar("emitted_by_schedule_id", { length: 36 }).references(
1183
+ () => schedules.schedule_id,
1184
+ {
1185
+ onDelete: "set null"
1186
+ }
1187
+ ),
1188
+ message_text: text("message_text").notNull(),
1189
+ message_preview: text("message_preview").notNull(),
1190
+ metadata: t.json("metadata"),
1191
+ consumed_by_session_id: varchar("consumed_by_session_id", { length: 36 }).references(
1192
+ () => sessions.session_id,
1193
+ {
1194
+ onDelete: "set null"
1195
+ }
1196
+ ),
1197
+ consumed_at: t.timestamp("consumed_at")
1198
+ },
1199
+ (table) => ({
1200
+ tenantIdx: index("gateway_outbound_messages_tenant_id_idx").on(table.tenant_id),
1201
+ uniqueChannelThread: uniqueIndex("uniq_gateway_outbound_tenant_channel_thread").on(
1202
+ table.tenant_id,
1203
+ table.gateway_channel_id,
1204
+ table.platform_thread_id
1205
+ ),
1206
+ emittedSessionIdx: index("idx_gateway_outbound_emitted_session").on(
1207
+ table.emitted_by_session_id
1208
+ ),
1209
+ emittedScheduleIdx: index("idx_gateway_outbound_emitted_schedule").on(
1210
+ table.emitted_by_schedule_id
1211
+ ),
1212
+ targetBranchCreatedIdx: index("idx_gateway_outbound_branch_created").on(
1213
+ table.target_branch_id,
1214
+ table.created_at
1215
+ ),
1216
+ consumedIdx: index("idx_gateway_outbound_consumed").on(table.consumed_at)
1217
+ })
1218
+ );
1219
+ var sessionEnvSelections = pgTable(
1220
+ "session_env_selections",
1221
+ {
1222
+ tenant_id: text("tenant_id").notNull().default("default"),
1223
+ session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
1224
+ env_var_name: text("env_var_name").notNull(),
1225
+ created_at: t.timestamp("created_at").notNull()
1226
+ },
1227
+ (table) => ({
1228
+ tenantIdx: index("session_env_selections_tenant_id_idx").on(table.tenant_id),
1229
+ pk: primaryKey({ columns: [table.session_id, table.env_var_name] }),
1230
+ sessionIdx: index("session_env_selections_session_idx").on(table.session_id)
1231
+ })
1232
+ );
1233
+ var kbNamespaces = pgTable(
1234
+ "kb_namespaces",
1235
+ {
1236
+ tenant_id: text("tenant_id").notNull().default("default"),
1237
+ namespace_id: varchar("namespace_id", { length: 36 }).primaryKey(),
1238
+ slug: text("slug").notNull(),
1239
+ display_name: text("display_name").notNull(),
1240
+ description: text("description"),
1241
+ kind: text("kind", { enum: ["system", "global", "user", "repo", "branch", "team"] }).notNull().default("global"),
1242
+ owner_user_id: varchar("owner_user_id", { length: 36 }).references(() => users.user_id, {
1243
+ onDelete: "set null"
1244
+ }),
1245
+ repo_id: varchar("repo_id", { length: 36 }).references(() => repos.repo_id, {
1246
+ onDelete: "set null"
1247
+ }),
1248
+ branch_id: varchar("branch_id", { length: 36 }).references(() => branches.branch_id, {
1249
+ onDelete: "set null"
1250
+ }),
1251
+ visibility_default: text("visibility_default", { enum: ["public", "private"] }).notNull().default("public"),
1252
+ others_can: text("others_can", { enum: ["none", "read", "write"] }).notNull().default("write"),
1253
+ metadata: t.json("metadata"),
1254
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
1255
+ onDelete: "set null"
1256
+ }),
1257
+ created_at: t.timestamp("created_at").notNull(),
1258
+ updated_at: t.timestamp("updated_at"),
1259
+ archived: t.bool("archived").notNull().default(false),
1260
+ archived_at: t.timestamp("archived_at")
1261
+ },
1262
+ (table) => ({
1263
+ tenantIdx: index("kb_namespaces_tenant_id_idx").on(table.tenant_id),
1264
+ slugIdx: uniqueIndex("kb_namespaces_tenant_slug_unique").on(table.tenant_id, table.slug).where(sql2`${table.archived} = false`),
1265
+ kindIdx: index("kb_namespaces_kind_idx").on(table.kind),
1266
+ ownerIdx: index("kb_namespaces_owner_idx").on(table.owner_user_id),
1267
+ repoIdx: index("kb_namespaces_repo_idx").on(table.repo_id),
1268
+ branchIdx: index("kb_namespaces_branch_idx").on(table.branch_id),
1269
+ archivedIdx: index("kb_namespaces_archived_idx").on(table.archived)
1270
+ })
1271
+ );
1272
+ var kbNamespaceAcl = pgTable(
1273
+ "kb_namespace_acl",
1274
+ {
1275
+ tenant_id: text("tenant_id").notNull().default("default"),
1276
+ namespace_acl_id: varchar("namespace_acl_id", { length: 36 }).primaryKey(),
1277
+ namespace_id: varchar("namespace_id", { length: 36 }).notNull().references(() => kbNamespaces.namespace_id, { onDelete: "cascade" }),
1278
+ subject_type: text("subject_type", { enum: ["user", "group"] }).notNull(),
1279
+ subject_id: varchar("subject_id", { length: 36 }).notNull(),
1280
+ permission: text("permission", { enum: ["read", "write", "own"] }).notNull(),
1281
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
1282
+ onDelete: "set null"
1283
+ }),
1284
+ created_at: t.timestamp("created_at").notNull(),
1285
+ updated_at: t.timestamp("updated_at")
1286
+ },
1287
+ (table) => ({
1288
+ tenantIdx: index("kb_namespace_acl_tenant_id_idx").on(table.tenant_id),
1289
+ namespaceIdx: index("kb_namespace_acl_namespace_idx").on(table.namespace_id),
1290
+ subjectIdx: index("kb_namespace_acl_subject_idx").on(table.subject_type, table.subject_id),
1291
+ namespaceSubjectIdx: uniqueIndex("kb_namespace_acl_tenant_namespace_subject_unique").on(
1292
+ table.tenant_id,
1293
+ table.namespace_id,
1294
+ table.subject_type,
1295
+ table.subject_id
1296
+ )
1297
+ })
1298
+ );
1299
+ var kbDocuments = pgTable(
1300
+ "kb_documents",
1301
+ {
1302
+ tenant_id: text("tenant_id").notNull().default("default"),
1303
+ document_id: varchar("document_id", { length: 36 }).primaryKey(),
1304
+ namespace_id: varchar("namespace_id", { length: 36 }).notNull().references(() => kbNamespaces.namespace_id, { onDelete: "cascade" }),
1305
+ path: text("path").notNull(),
1306
+ uri: text("uri").notNull(),
1307
+ title: text("title").notNull(),
1308
+ icon_emoji: text("icon_emoji"),
1309
+ kind: text("kind", {
1310
+ enum: ["doc", "memory", "skill", "prompt", "guide", "decision", "bundle", "external"]
1311
+ }).notNull().default("doc"),
1312
+ visibility: text("visibility", { enum: ["public", "private"] }).notNull().default("public"),
1313
+ status: text("status", { enum: ["draft", "published"] }).notNull().default("published"),
1314
+ edit_policy: text("edit_policy", { enum: ["owner", "public", "admins"] }).notNull().default("owner"),
1315
+ // Application-maintained pointer. Avoids a circular FK with versions.
1316
+ current_version_id: varchar("current_version_id", { length: 36 }),
1317
+ metadata: t.json("metadata"),
1318
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
1319
+ onDelete: "set null"
1320
+ }),
1321
+ created_at: t.timestamp("created_at").notNull(),
1322
+ updated_by: varchar("updated_by", { length: 36 }).references(() => users.user_id, {
1323
+ onDelete: "set null"
1324
+ }),
1325
+ updated_at: t.timestamp("updated_at"),
1326
+ archived: t.bool("archived").notNull().default(false),
1327
+ archived_at: t.timestamp("archived_at")
1328
+ },
1329
+ (table) => ({
1330
+ tenantIdx: index("kb_documents_tenant_id_idx").on(table.tenant_id),
1331
+ namespacePathIdx: uniqueIndex("kb_documents_tenant_namespace_path_unique").on(table.tenant_id, table.namespace_id, table.path).where(sql2`${table.archived} = false`),
1332
+ uriIdx: uniqueIndex("kb_documents_tenant_uri_unique").on(table.tenant_id, table.uri).where(sql2`${table.archived} = false`),
1333
+ namespaceIdx: index("kb_documents_namespace_idx").on(table.namespace_id),
1334
+ kindIdx: index("kb_documents_kind_idx").on(table.kind),
1335
+ visibilityIdx: index("kb_documents_visibility_idx").on(table.visibility),
1336
+ statusIdx: index("kb_documents_status_idx").on(table.status),
1337
+ createdByIdx: index("kb_documents_created_by_idx").on(table.created_by),
1338
+ updatedAtIdx: index("kb_documents_updated_at_idx").on(table.updated_at),
1339
+ archivedIdx: index("kb_documents_archived_idx").on(table.archived)
1340
+ })
1341
+ );
1342
+ var kbDocumentVersions = pgTable(
1343
+ "kb_document_versions",
1344
+ {
1345
+ tenant_id: text("tenant_id").notNull().default("default"),
1346
+ version_id: varchar("version_id", { length: 36 }).primaryKey(),
1347
+ document_id: varchar("document_id", { length: 36 }).notNull().references(() => kbDocuments.document_id, { onDelete: "cascade" }),
1348
+ version_number: integer("version_number").notNull(),
1349
+ content_text: text("content_text"),
1350
+ content_blob: bytea("content_blob"),
1351
+ mime_type: text("mime_type").notNull().default("text/markdown"),
1352
+ content_md5: text("content_md5"),
1353
+ content_sha256: text("content_sha256"),
1354
+ byte_length: integer("byte_length"),
1355
+ char_length: integer("char_length"),
1356
+ frontmatter: t.json("frontmatter"),
1357
+ metadata: t.json("metadata"),
1358
+ change_summary: text("change_summary"),
1359
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
1360
+ onDelete: "set null"
1361
+ }),
1362
+ created_at: t.timestamp("created_at").notNull()
1363
+ },
1364
+ (table) => ({
1365
+ tenantIdx: index("kb_document_versions_tenant_id_idx").on(table.tenant_id),
1366
+ documentVersionIdx: uniqueIndex("kb_document_versions_tenant_document_version_unique").on(
1367
+ table.tenant_id,
1368
+ table.document_id,
1369
+ table.version_number
1370
+ ),
1371
+ documentIdx: index("kb_document_versions_document_idx").on(table.document_id),
1372
+ createdIdx: index("kb_document_versions_created_idx").on(table.created_at),
1373
+ md5Idx: index("kb_document_versions_md5_idx").on(table.content_md5)
1374
+ })
1375
+ );
1376
+ var kbDocumentUnits = pgTable(
1377
+ "kb_document_units",
1378
+ {
1379
+ tenant_id: text("tenant_id").notNull().default("default"),
1380
+ unit_id: varchar("unit_id", { length: 36 }).primaryKey(),
1381
+ document_id: varchar("document_id", { length: 36 }).notNull().references(() => kbDocuments.document_id, { onDelete: "cascade" }),
1382
+ version_id: varchar("version_id", { length: 36 }).notNull().references(() => kbDocumentVersions.version_id, { onDelete: "cascade" }),
1383
+ kind: text("kind", { enum: ["document", "section", "file", "auto_split"] }).notNull().default("document"),
1384
+ ordinal: integer("ordinal").notNull().default(0),
1385
+ path_anchor: text("path_anchor"),
1386
+ heading_path: text("heading_path"),
1387
+ source_path: text("source_path"),
1388
+ content_text: text("content_text"),
1389
+ content_md5: text("content_md5"),
1390
+ start_offset: integer("start_offset"),
1391
+ end_offset: integer("end_offset"),
1392
+ embedding_status: text("embedding_status", {
1393
+ enum: ["not_configured", "pending", "ready", "stale", "error"]
1394
+ }).notNull().default("not_configured"),
1395
+ embedding_model: text("embedding_model"),
1396
+ embedding_dimensions: integer("embedding_dimensions"),
1397
+ embedding_hash: text("embedding_hash"),
1398
+ embedding_error: text("embedding_error"),
1399
+ metadata: t.json("metadata"),
1400
+ created_at: t.timestamp("created_at").notNull(),
1401
+ updated_at: t.timestamp("updated_at")
1402
+ },
1403
+ (table) => ({
1404
+ tenantIdx: index("kb_document_units_tenant_id_idx").on(table.tenant_id),
1405
+ documentIdx: index("kb_document_units_document_idx").on(table.document_id),
1406
+ versionIdx: index("kb_document_units_version_idx").on(table.version_id),
1407
+ versionOrdinalIdx: index("kb_document_units_version_ordinal_idx").on(
1408
+ table.version_id,
1409
+ table.ordinal
1410
+ ),
1411
+ contentHashIdx: index("kb_document_units_content_hash_idx").on(table.content_md5),
1412
+ embeddingStatusIdx: index("kb_document_units_embedding_status_idx").on(table.embedding_status)
1413
+ })
1414
+ );
1415
+ var kbEmbeddingSpaces = pgTable(
1416
+ "kb_embedding_spaces",
1417
+ {
1418
+ tenant_id: text("tenant_id").notNull().default("default"),
1419
+ embedding_space_id: varchar("embedding_space_id", { length: 36 }).primaryKey(),
1420
+ provider: text("provider").notNull(),
1421
+ model: text("model").notNull(),
1422
+ dimensions: integer("dimensions").notNull(),
1423
+ storage_type: text("storage_type").notNull().default("vector"),
1424
+ distance: text("distance").notNull().default("cosine"),
1425
+ active: t.bool("active").notNull().default(true),
1426
+ metadata: t.json("metadata"),
1427
+ created_at: t.timestamp("created_at").notNull(),
1428
+ updated_at: t.timestamp("updated_at")
1429
+ },
1430
+ (table) => ({
1431
+ tenantIdx: index("kb_embedding_spaces_tenant_id_idx").on(table.tenant_id),
1432
+ providerModelIdx: uniqueIndex("kb_embedding_spaces_tenant_provider_model_unique").on(
1433
+ table.tenant_id,
1434
+ table.provider,
1435
+ table.model,
1436
+ table.dimensions,
1437
+ table.storage_type,
1438
+ table.distance
1439
+ ),
1440
+ activeIdx: index("kb_embedding_spaces_active_idx").on(table.active)
1441
+ })
1442
+ );
1443
+ var kbGraphNodes = pgTable(
1444
+ "kb_graph_nodes",
1445
+ {
1446
+ tenant_id: text("tenant_id").notNull().default("default"),
1447
+ node_id: varchar("node_id", { length: 36 }).primaryKey(),
1448
+ node_type: text("node_type", {
1449
+ enum: [
1450
+ "namespace",
1451
+ "document",
1452
+ "document_unit",
1453
+ "branch",
1454
+ "session",
1455
+ "task",
1456
+ "message",
1457
+ "artifact",
1458
+ "repo",
1459
+ "board",
1460
+ "user",
1461
+ "tag",
1462
+ "external"
1463
+ ]
1464
+ }).notNull(),
1465
+ uri: text("uri").notNull(),
1466
+ label: text("label"),
1467
+ namespace_id: varchar("namespace_id", { length: 36 }).references(
1468
+ () => kbNamespaces.namespace_id,
1469
+ { onDelete: "cascade" }
1470
+ ),
1471
+ document_id: varchar("document_id", { length: 36 }).references(() => kbDocuments.document_id, {
1472
+ onDelete: "cascade"
1473
+ }),
1474
+ unit_id: varchar("unit_id", { length: 36 }).references(() => kbDocumentUnits.unit_id, {
1475
+ onDelete: "cascade"
1476
+ }),
1477
+ branch_id: varchar("branch_id", { length: 36 }).references(() => branches.branch_id, {
1478
+ onDelete: "cascade"
1479
+ }),
1480
+ session_id: varchar("session_id", { length: 36 }).references(() => sessions.session_id, {
1481
+ onDelete: "cascade"
1482
+ }),
1483
+ task_id: varchar("task_id", { length: 36 }).references(() => tasks.task_id, {
1484
+ onDelete: "cascade"
1485
+ }),
1486
+ message_id: varchar("message_id", { length: 36 }).references(() => messages.message_id, {
1487
+ onDelete: "cascade"
1488
+ }),
1489
+ artifact_id: varchar("artifact_id", { length: 36 }).references(() => artifacts.artifact_id, {
1490
+ onDelete: "cascade"
1491
+ }),
1492
+ repo_id: varchar("repo_id", { length: 36 }).references(() => repos.repo_id, {
1493
+ onDelete: "cascade"
1494
+ }),
1495
+ board_id: varchar("board_id", { length: 36 }).references(() => boards.board_id, {
1496
+ onDelete: "cascade"
1497
+ }),
1498
+ user_id: varchar("user_id", { length: 36 }).references(() => users.user_id, {
1499
+ onDelete: "cascade"
1500
+ }),
1501
+ external_uri: text("external_uri"),
1502
+ metadata: t.json("metadata"),
1503
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
1504
+ onDelete: "set null"
1505
+ }),
1506
+ created_at: t.timestamp("created_at").notNull(),
1507
+ updated_at: t.timestamp("updated_at"),
1508
+ archived: t.bool("archived").notNull().default(false),
1509
+ archived_at: t.timestamp("archived_at")
1510
+ },
1511
+ (table) => ({
1512
+ tenantIdx: index("kb_graph_nodes_tenant_id_idx").on(table.tenant_id),
1513
+ uriIdx: uniqueIndex("kb_graph_nodes_tenant_uri_unique").on(table.tenant_id, table.uri).where(sql2`${table.archived} = false`),
1514
+ typeIdx: index("kb_graph_nodes_type_idx").on(table.node_type),
1515
+ namespaceIdx: index("kb_graph_nodes_namespace_idx").on(table.namespace_id),
1516
+ documentIdx: index("kb_graph_nodes_document_idx").on(table.document_id),
1517
+ unitIdx: index("kb_graph_nodes_unit_idx").on(table.unit_id),
1518
+ branchIdx: index("kb_graph_nodes_branch_idx").on(table.branch_id),
1519
+ sessionIdx: index("kb_graph_nodes_session_idx").on(table.session_id),
1520
+ taskIdx: index("kb_graph_nodes_task_idx").on(table.task_id),
1521
+ messageIdx: index("kb_graph_nodes_message_idx").on(table.message_id),
1522
+ artifactIdx: index("kb_graph_nodes_artifact_idx").on(table.artifact_id),
1523
+ repoIdx: index("kb_graph_nodes_repo_idx").on(table.repo_id),
1524
+ boardIdx: index("kb_graph_nodes_board_idx").on(table.board_id),
1525
+ userIdx: index("kb_graph_nodes_user_idx").on(table.user_id),
1526
+ externalUriIdx: index("kb_graph_nodes_external_uri_idx").on(table.external_uri),
1527
+ archivedIdx: index("kb_graph_nodes_archived_idx").on(table.archived)
1528
+ })
1529
+ );
1530
+ var kbGraphEdges = pgTable(
1531
+ "kb_graph_edges",
1532
+ {
1533
+ tenant_id: text("tenant_id").notNull().default("default"),
1534
+ edge_id: varchar("edge_id", { length: 36 }).primaryKey(),
1535
+ source_node_id: varchar("source_node_id", { length: 36 }).notNull().references(() => kbGraphNodes.node_id, { onDelete: "cascade" }),
1536
+ target_node_id: varchar("target_node_id", { length: 36 }).notNull().references(() => kbGraphNodes.node_id, { onDelete: "cascade" }),
1537
+ edge_type: text("edge_type", {
1538
+ enum: [
1539
+ "contains",
1540
+ "references",
1541
+ "mentions",
1542
+ "implements",
1543
+ "depends_on",
1544
+ "supersedes",
1545
+ "derived_from",
1546
+ "tagged_with",
1547
+ "about",
1548
+ "parent_of",
1549
+ "related_to"
1550
+ ]
1551
+ }).notNull(),
1552
+ confidence: integer("confidence"),
1553
+ properties: t.json("properties"),
1554
+ created_by: varchar("created_by", { length: 36 }).references(() => users.user_id, {
1555
+ onDelete: "set null"
1556
+ }),
1557
+ created_at: t.timestamp("created_at").notNull(),
1558
+ archived: t.bool("archived").notNull().default(false),
1559
+ archived_at: t.timestamp("archived_at")
1560
+ },
1561
+ (table) => ({
1562
+ tenantIdx: index("kb_graph_edges_tenant_id_idx").on(table.tenant_id),
1563
+ sourceIdx: index("kb_graph_edges_source_idx").on(table.source_node_id),
1564
+ targetIdx: index("kb_graph_edges_target_idx").on(table.target_node_id),
1565
+ typeIdx: index("kb_graph_edges_type_idx").on(table.edge_type),
1566
+ sourceTypeIdx: index("kb_graph_edges_source_type_idx").on(
1567
+ table.source_node_id,
1568
+ table.edge_type
1569
+ ),
1570
+ targetTypeIdx: index("kb_graph_edges_target_type_idx").on(
1571
+ table.target_node_id,
1572
+ table.edge_type
1573
+ ),
1574
+ sourceTargetTypeIdx: uniqueIndex("kb_graph_edges_tenant_source_target_type_unique").on(table.tenant_id, table.source_node_id, table.target_node_id, table.edge_type).where(sql2`${table.archived} = false`),
1575
+ archivedIdx: index("kb_graph_edges_archived_idx").on(table.archived)
1576
+ })
1577
+ );
1578
+ var sessionsRelations = relations(sessions, ({ one, many }) => ({
1579
+ branch: one(branches, {
1580
+ fields: [sessions.branch_id],
1581
+ references: [branches.branch_id]
1582
+ }),
1583
+ schedule: one(schedules, {
1584
+ fields: [sessions.schedule_id],
1585
+ references: [schedules.schedule_id]
1586
+ }),
1587
+ outboundRelationships: many(sessionRelationships, { relationName: "relationshipSource" }),
1588
+ inboundRelationships: many(sessionRelationships, { relationName: "relationshipTarget" })
1589
+ }));
1590
+ var sessionRelationshipsRelations = relations(sessionRelationships, ({ one }) => ({
1591
+ sourceSession: one(sessions, {
1592
+ fields: [sessionRelationships.source_session_id],
1593
+ references: [sessions.session_id],
1594
+ relationName: "relationshipSource"
1595
+ }),
1596
+ targetSession: one(sessions, {
1597
+ fields: [sessionRelationships.target_session_id],
1598
+ references: [sessions.session_id],
1599
+ relationName: "relationshipTarget"
1600
+ }),
1601
+ callbackSession: one(sessions, {
1602
+ fields: [sessionRelationships.callback_session_id],
1603
+ references: [sessions.session_id]
1604
+ })
1605
+ }));
1606
+ var branchesRelations = relations(branches, ({ many }) => ({
1607
+ sessions: many(sessions),
1608
+ schedules: many(schedules)
1609
+ }));
1610
+ var schedulesRelations = relations(schedules, ({ one, many }) => ({
1611
+ branch: one(branches, {
1612
+ fields: [schedules.branch_id],
1613
+ references: [branches.branch_id]
1614
+ }),
1615
+ sessions: many(sessions)
1616
+ }));
1617
+
1618
+ // src/db/schema.sqlite.ts
1619
+ var schema_sqlite_exports = {};
1620
+ __export(schema_sqlite_exports, {
1621
+ appVariables: () => appVariables2,
1622
+ artifactTrustGrants: () => artifactTrustGrants2,
1623
+ artifacts: () => artifacts2,
1624
+ boardComments: () => boardComments2,
1625
+ boardGroupGrants: () => boardGroupGrants2,
1626
+ boardObjects: () => boardObjects2,
1627
+ boardOwners: () => boardOwners2,
1628
+ boards: () => boards2,
1629
+ branchGroupGrants: () => branchGroupGrants2,
1630
+ branchOwners: () => branchOwners2,
1631
+ branches: () => branches2,
1632
+ branchesRelations: () => branchesRelations2,
1633
+ cardTypes: () => cardTypes2,
1634
+ cards: () => cards2,
1635
+ gatewayChannels: () => gatewayChannels2,
1636
+ gatewayOutboundMessages: () => gatewayOutboundMessages2,
1637
+ groupMemberships: () => groupMemberships2,
1638
+ groups: () => groups2,
1639
+ kbDocumentUnits: () => kbDocumentUnits2,
1640
+ kbDocumentVersions: () => kbDocumentVersions2,
1641
+ kbDocuments: () => kbDocuments2,
1642
+ kbEmbeddingSpaces: () => kbEmbeddingSpaces2,
1643
+ kbGraphEdges: () => kbGraphEdges2,
1644
+ kbGraphNodes: () => kbGraphNodes2,
1645
+ kbNamespaceAcl: () => kbNamespaceAcl2,
1646
+ kbNamespaces: () => kbNamespaces2,
1647
+ mcpServers: () => mcpServers2,
1648
+ messages: () => messages2,
1649
+ repos: () => repos2,
1650
+ schedules: () => schedules2,
1651
+ schedulesRelations: () => schedulesRelations2,
1652
+ serializedSessions: () => serializedSessions2,
1653
+ sessionEnvSelections: () => sessionEnvSelections2,
1654
+ sessionMcpServers: () => sessionMcpServers2,
1655
+ sessionRelationships: () => sessionRelationships2,
1656
+ sessionRelationshipsRelations: () => sessionRelationshipsRelations2,
1657
+ sessions: () => sessions2,
1658
+ sessionsRelations: () => sessionsRelations2,
1659
+ tasks: () => tasks2,
1660
+ threadSessionMap: () => threadSessionMap2,
1661
+ userApiKeys: () => userApiKeys2,
1662
+ userMcpOauthTokens: () => userMcpOauthTokens2,
1663
+ users: () => users2
1664
+ });
1665
+ import { relations as relations2, sql as sql3 } from "drizzle-orm";
1666
+ import {
1667
+ blob,
1668
+ index as index2,
1669
+ integer as integer2,
1670
+ primaryKey as primaryKey2,
1671
+ sqliteTable,
1672
+ text as text2,
1673
+ uniqueIndex as uniqueIndex2
1674
+ } from "drizzle-orm/sqlite-core";
1675
+ var t2 = {
1676
+ timestamp: (name) => integer2(name, { mode: "timestamp_ms" }),
1677
+ bool: (name) => integer2(name, { mode: "boolean" }),
1678
+ json: (name) => text2(name, { mode: "json" }).$type()
1679
+ };
1680
+ var sessions2 = sqliteTable(
1681
+ "sessions",
1682
+ {
1683
+ // Primary identity
1684
+ session_id: text2("session_id", { length: 36 }).primaryKey(),
1685
+ created_at: t2.timestamp("created_at").notNull(),
1686
+ updated_at: t2.timestamp("updated_at"),
1687
+ // User attribution
1688
+ created_by: text2("created_by", { length: 36 }).notNull(),
1689
+ // Unix username for SDK impersonation (immutable once set)
1690
+ // Set from creator's unix_username at session creation time
1691
+ // NEVER changes, even if user's unix_username changes later
1692
+ // This ensures SDK session data remains accessible in the original home directory
1693
+ unix_username: text2("unix_username"),
1694
+ // Materialized for filtering/joins (cross-DB compatible)
1695
+ status: text2("status", {
1696
+ enum: [
1697
+ "idle",
1698
+ "running",
1699
+ "stopping",
1700
+ "awaiting_permission",
1701
+ "awaiting_input",
1702
+ "timed_out",
1703
+ "completed",
1704
+ "failed"
1705
+ ]
1706
+ }).notNull(),
1707
+ agentic_tool: text2("agentic_tool", {
1708
+ enum: ["claude-code", "claude-code-cli", "codex", "gemini", "opencode", "copilot", "cursor"]
1709
+ }).notNull(),
1710
+ board_id: text2("board_id", { length: 36 }),
1711
+ // NULL = no board
1712
+ // Genealogy (materialized for tree queries)
1713
+ parent_session_id: text2("parent_session_id", { length: 36 }),
1714
+ forked_from_session_id: text2("forked_from_session_id", { length: 36 }),
1715
+ // Branch reference (REQUIRED: all sessions must have a branch)
1716
+ branch_id: text2("branch_id", { length: 36 }).notNull().references(() => branches2.branch_id, {
1717
+ onDelete: "cascade"
1718
+ // Cascade delete sessions when branch is deleted
1719
+ }),
1720
+ // Scheduler tracking (materialized for deduplication and retention cleanup)
1721
+ scheduled_run_at: integer2("scheduled_run_at"),
1722
+ // Unix timestamp (ms) - authoritative run ID
1723
+ scheduled_from_branch: t2.bool("scheduled_from_branch").notNull().default(false),
1724
+ // FK to schedules.schedule_id, ON DELETE SET NULL. Defined here (not
1725
+ // just in the migration) so drizzle-kit / db introspection sees the
1726
+ // constraint and so future schema diffs don't lose it.
1727
+ schedule_id: text2("schedule_id", { length: 36 }).references(
1728
+ () => schedules2.schedule_id,
1729
+ { onDelete: "set null" }
1730
+ ),
1731
+ // UI state (materialized for efficient highlighting queries)
1732
+ ready_for_prompt: t2.bool("ready_for_prompt").notNull().default(false),
1733
+ // Archive state (cascaded from branch archive)
1734
+ archived: t2.bool("archived").notNull().default(false),
1735
+ archived_reason: text2("archived_reason", {
1736
+ enum: ["branch_archived", "manual", "btw_completed"]
1737
+ }),
1738
+ // JSON blob for everything else (cross-DB via json() type)
1739
+ data: t2.json("data").$type().notNull()
1740
+ },
1741
+ (table) => ({
1742
+ statusIdx: index2("sessions_status_idx").on(table.status),
1743
+ statusReadyIdx: index2("sessions_status_ready_idx").on(table.status, table.ready_for_prompt),
1744
+ agenticToolIdx: index2("sessions_agentic_tool_idx").on(table.agentic_tool),
1745
+ boardIdx: index2("sessions_board_idx").on(table.board_id),
1746
+ branchIdx: index2("sessions_branch_idx").on(table.branch_id),
1747
+ createdIdx: index2("sessions_created_idx").on(table.created_at),
1748
+ parentIdx: index2("sessions_parent_idx").on(table.parent_session_id),
1749
+ forkedIdx: index2("sessions_forked_idx").on(table.forked_from_session_id),
1750
+ // Scheduler indexes — including the partial unique index below.
1751
+ scheduledFromBranchIdx: index2("sessions_scheduled_flag_idx").on(table.scheduled_from_branch),
1752
+ // Partial unique index — covering for the scheduler's dedup lookup
1753
+ // AND serves as the DB-level guard against check-then-create races
1754
+ // in spawnScheduledSession (cron tick vs manual run-now, or two
1755
+ // tick async paths). Partial because schedule_id is nullable: ad-hoc
1756
+ // sessions all have schedule_id NULL and must coexist.
1757
+ scheduleRunUnique: uniqueIndex2("sessions_schedule_run_unique").on(table.schedule_id, table.scheduled_run_at).where(sql3`${table.schedule_id} IS NOT NULL AND ${table.scheduled_run_at} IS NOT NULL`)
1758
+ })
1759
+ );
1760
+ var sessionRelationships2 = sqliteTable(
1761
+ "session_relationships",
1762
+ {
1763
+ relationship_id: text2("relationship_id", { length: 36 }).primaryKey(),
1764
+ source_session_id: text2("source_session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
1765
+ target_session_id: text2("target_session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
1766
+ relationship_type: text2("relationship_type", { enum: ["remote_create"] }).notNull(),
1767
+ created_by: text2("created_by", { length: 36 }).notNull(),
1768
+ created_at: t2.timestamp("created_at").notNull(),
1769
+ updated_at: t2.timestamp("updated_at"),
1770
+ callback_enabled: t2.bool("callback_enabled").notNull().default(false),
1771
+ callback_session_id: text2("callback_session_id", { length: 36 }).references(
1772
+ () => sessions2.session_id,
1773
+ {
1774
+ onDelete: "set null"
1775
+ }
1776
+ ),
1777
+ data: t2.json("data")
1778
+ },
1779
+ (table) => ({
1780
+ sourceIdx: index2("session_relationships_source_idx").on(table.source_session_id),
1781
+ targetIdx: index2("session_relationships_target_idx").on(table.target_session_id),
1782
+ callbackIdx: index2("session_relationships_callback_idx").on(table.callback_session_id),
1783
+ // Note: no tenant_source/tenant_target composite indexes here — SQLite schema
1784
+ // has no tenant column on this table (RLS is Postgres-only). The standalone
1785
+ // source/target indexes above are sufficient for SQLite.
1786
+ sourceTargetTypeUnique: uniqueIndex2("session_relationships_source_target_type_unique").on(
1787
+ table.source_session_id,
1788
+ table.target_session_id,
1789
+ table.relationship_type
1790
+ )
1791
+ })
1792
+ );
1793
+ var tasks2 = sqliteTable(
1794
+ "tasks",
1795
+ {
1796
+ task_id: text2("task_id", { length: 36 }).primaryKey(),
1797
+ session_id: text2("session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
1798
+ created_at: t2.timestamp("created_at").notNull(),
1799
+ started_at: t2.timestamp("started_at"),
1800
+ completed_at: t2.timestamp("completed_at"),
1801
+ last_executor_heartbeat_at: t2.timestamp("last_executor_heartbeat_at"),
1802
+ status: text2("status", {
1803
+ enum: [
1804
+ "queued",
1805
+ "created",
1806
+ "running",
1807
+ "stopping",
1808
+ "awaiting_permission",
1809
+ "awaiting_input",
1810
+ "timed_out",
1811
+ "completed",
1812
+ "failed",
1813
+ "stopped"
1814
+ ]
1815
+ }).notNull(),
1816
+ // Queue position (lower drains first); only populated for status='queued'
1817
+ queue_position: integer2("queue_position"),
1818
+ // User attribution
1819
+ created_by: text2("created_by", { length: 36 }).notNull(),
1820
+ // MD5 of SDK session file at task completion (only populated when stateless_fs_mode is enabled)
1821
+ session_md5: text2("session_md5"),
1822
+ data: t2.json("data").$type().notNull()
1823
+ },
1824
+ (table) => ({
1825
+ sessionIdx: index2("tasks_session_idx").on(table.session_id),
1826
+ statusIdx: index2("tasks_status_idx").on(table.status),
1827
+ createdIdx: index2("tasks_created_idx").on(table.created_at),
1828
+ queueIdx: index2("tasks_queue_idx").on(table.session_id, table.status, table.queue_position),
1829
+ // Partial unique index — defense-in-depth for `tasks.createPending` race
1830
+ // serialization. Only QUEUED rows are constrained; CREATED/RUNNING/done
1831
+ // rows have NULL queue_position and are unaffected.
1832
+ queuedPositionUnique: uniqueIndex2("tasks_queued_position_unique").on(table.session_id, table.queue_position).where(sql3`${table.status} = 'queued'`)
1833
+ })
1834
+ );
1835
+ var serializedSessions2 = sqliteTable(
1836
+ "serialized_sessions",
1837
+ {
1838
+ id: text2("id", { length: 36 }).primaryKey(),
1839
+ session_id: text2("session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
1840
+ branch_id: text2("branch_id", { length: 36 }).notNull().references(() => branches2.branch_id, { onDelete: "cascade" }),
1841
+ task_id: text2("task_id", { length: 36 }).references(() => tasks2.task_id, {
1842
+ onDelete: "set null"
1843
+ }),
1844
+ turn_index: integer2("turn_index").notNull().default(0),
1845
+ created_at: t2.timestamp("created_at").notNull(),
1846
+ md5: text2("md5").notNull(),
1847
+ status: text2("status").notNull(),
1848
+ // 'processing' | 'done' — validated at app layer
1849
+ payload: blob("payload", { mode: "buffer" })
1850
+ // gzipped; NULL while status='processing'
1851
+ },
1852
+ (table) => ({
1853
+ sessionTurnIdx: index2("serialized_sessions_session_turn_idx").on(
1854
+ table.session_id,
1855
+ table.turn_index
1856
+ ),
1857
+ branchIdx: index2("serialized_sessions_branch_idx").on(table.branch_id)
1858
+ })
1859
+ );
1860
+ var messages2 = sqliteTable(
1861
+ "messages",
1862
+ {
1863
+ // Primary identity
1864
+ message_id: text2("message_id", { length: 36 }).primaryKey(),
1865
+ created_at: t2.timestamp("created_at").notNull(),
1866
+ // Foreign keys (materialized for indexes)
1867
+ session_id: text2("session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
1868
+ task_id: text2("task_id", { length: 36 }).references(() => tasks2.task_id, {
1869
+ onDelete: "set null"
1870
+ }),
1871
+ // Materialized for queries
1872
+ type: text2("type", {
1873
+ enum: [
1874
+ "user",
1875
+ "assistant",
1876
+ "system",
1877
+ "file-history-snapshot",
1878
+ "permission_request",
1879
+ "input_request",
1880
+ "daemon_restart",
1881
+ "daemon_crash",
1882
+ "widget_request"
1883
+ ]
1884
+ }).notNull(),
1885
+ role: text2("role", {
1886
+ enum: ["user", "assistant", "system"]
1887
+ }).notNull(),
1888
+ index: integer2("index").notNull(),
1889
+ // Position in conversation (0-based)
1890
+ timestamp: t2.timestamp("timestamp").notNull(),
1891
+ content_preview: text2("content_preview"),
1892
+ // First 200 chars for list views
1893
+ // Parent tool use ID (for nested tool calls - e.g., Task tool spawning Read/Grep)
1894
+ parent_tool_use_id: text2("parent_tool_use_id"),
1895
+ // NOTE: queueing moved off `messages` and onto `tasks.status='queued'` as
1896
+ // of migration sqlite/0040 (postgres/0030). The legacy `status` and
1897
+ // `queue_position` columns are gone — see `tasks.queue_position` instead.
1898
+ // Full data (JSON blob)
1899
+ data: t2.json("data").$type().notNull()
1900
+ },
1901
+ (table) => ({
1902
+ // Indexes for efficient lookups
1903
+ sessionIdx: index2("messages_session_id_idx").on(table.session_id),
1904
+ taskIdx: index2("messages_task_id_idx").on(table.task_id),
1905
+ sessionIndexIdx: index2("messages_session_index_idx").on(table.session_id, table.index),
1906
+ timestampIdx: index2("messages_timestamp_idx").on(table.timestamp),
1907
+ sessionTimestampIdx: index2("messages_session_timestamp_idx").on(
1908
+ table.session_id,
1909
+ table.timestamp
1910
+ )
1911
+ })
1912
+ );
1913
+ var boards2 = sqliteTable(
1914
+ "boards",
1915
+ {
1916
+ board_id: text2("board_id", { length: 36 }).primaryKey(),
1917
+ created_at: t2.timestamp("created_at").notNull(),
1918
+ updated_at: t2.timestamp("updated_at"),
1919
+ // User attribution
1920
+ created_by: text2("created_by", { length: 36 }).notNull(),
1921
+ // Materialized for lookups
1922
+ name: text2("name").notNull(),
1923
+ slug: text2("slug").unique(),
1924
+ primary_assistant_id: text2("primary_assistant_id", { length: 36 }).references(
1925
+ () => branches2.branch_id,
1926
+ {
1927
+ onDelete: "set null"
1928
+ }
1929
+ ),
1930
+ // JSON blob for the rest
1931
+ data: t2.json("data").$type().notNull(),
1932
+ // Archive state (for soft deletes)
1933
+ archived: t2.bool("archived").notNull().default(false),
1934
+ archived_at: t2.timestamp("archived_at"),
1935
+ archived_by: text2("archived_by", { length: 36 })
1936
+ },
1937
+ (table) => ({
1938
+ nameIdx: index2("boards_name_idx").on(table.name),
1939
+ slugIdx: index2("boards_slug_idx").on(table.slug)
1940
+ })
1941
+ );
1942
+ var repos2 = sqliteTable(
1943
+ "repos",
1944
+ {
1945
+ repo_id: text2("repo_id", { length: 36 }).primaryKey(),
1946
+ created_at: t2.timestamp("created_at").notNull(),
1947
+ updated_at: t2.timestamp("updated_at"),
1948
+ // Materialized for querying
1949
+ slug: text2("slug").notNull().unique(),
1950
+ repo_type: text2("repo_type", { enum: ["remote", "local"] }).notNull().default("remote"),
1951
+ // Unix group for repo-level git access (agor_rp_<short-id>)
1952
+ // Users who have access to ANY branch in this repo get added to this group.
1953
+ // Applied to repo Unix-group-managed paths:
1954
+ // - repo root (non-recursive) for traversal into .git/worktrees/<name>
1955
+ // - .git (recursive) for shared git objects/refs and git operations
1956
+ unix_group: text2("unix_group"),
1957
+ data: t2.json("data").$type().notNull()
1958
+ },
1959
+ (table) => ({
1960
+ slugIdx: index2("repos_slug_idx").on(table.slug)
1961
+ })
1962
+ );
1963
+ var branches2 = sqliteTable(
1964
+ "branches",
1965
+ {
1966
+ // Primary identity
1967
+ branch_id: text2("branch_id", { length: 36 }).primaryKey(),
1968
+ repo_id: text2("repo_id", { length: 36 }).notNull().references(() => repos2.repo_id, { onDelete: "cascade" }),
1969
+ created_at: t2.timestamp("created_at").notNull(),
1970
+ updated_at: t2.timestamp("updated_at"),
1971
+ // User attribution
1972
+ created_by: text2("created_by", { length: 36 }).notNull(),
1973
+ // Materialized for queries
1974
+ name: text2("name").notNull(),
1975
+ // "feat-auth", "main"
1976
+ ref: text2("ref").notNull(),
1977
+ // Current branch/tag/commit
1978
+ ref_type: text2("ref_type", { enum: ["branch", "tag"] }),
1979
+ // Type of ref (branch or tag)
1980
+ branch_unique_id: integer2("branch_unique_id").notNull(),
1981
+ // Auto-assigned sequential ID for templates
1982
+ // Environment configuration (static, initialized from templates, then user-editable)
1983
+ start_command: text2("start_command"),
1984
+ // Start command (initialized from repo's up_command template)
1985
+ stop_command: text2("stop_command"),
1986
+ // Stop command (initialized from repo's down_command template)
1987
+ nuke_command: text2("nuke_command"),
1988
+ // Nuke command (initialized from repo's nuke_command template)
1989
+ health_check_url: text2("health_check_url"),
1990
+ // Health check URL (initialized from repo's health_check.url_template)
1991
+ app_url: text2("app_url"),
1992
+ // Application URL (initialized from repo's app_url_template)
1993
+ logs_command: text2("logs_command"),
1994
+ // Logs command (initialized from repo's logs_command template)
1995
+ // Name of the environment variant currently rendered into the command fields above.
1996
+ // References a key under repo.environment.variants. Null for pre-v2 branches.
1997
+ environment_variant: text2("environment_variant"),
1998
+ // Board relationship (nullable - branches can exist without boards)
1999
+ board_id: text2("board_id", { length: 36 }).references(() => boards2.board_id, {
2000
+ onDelete: "set null"
2001
+ // If board is deleted, branch remains but loses board association
2002
+ }),
2003
+ // UI state (materialized for efficient highlighting queries)
2004
+ needs_attention: t2.bool("needs_attention").notNull().default(true),
2005
+ // Default true for new branches
2006
+ // Archive state (for soft deletes)
2007
+ archived: t2.bool("archived").notNull().default(false),
2008
+ archived_at: t2.timestamp("archived_at"),
2009
+ archived_by: text2("archived_by", { length: 36 }),
2010
+ filesystem_status: text2("filesystem_status", {
2011
+ enum: ["creating", "ready", "failed", "preserved", "cleaned", "deleted"]
2012
+ }),
2013
+ // RBAC: App-layer permissions (rbac.md)
2014
+ permission_source: text2("permission_source", { enum: ["board", "override"] }).$type().notNull().default("override"),
2015
+ others_can: text2("others_can", {
2016
+ enum: [...BRANCH_PERMISSION_LEVELS]
2017
+ }).default("view"),
2018
+ // RBAC: OS-layer permissions (unix-user-modes.md)
2019
+ unix_group: text2("unix_group"),
2020
+ // e.g., 'agor_wt_abc123'
2021
+ others_fs_access: text2("others_fs_access", {
2022
+ enum: ["none", "read", "write"]
2023
+ }).$type().default("read"),
2024
+ // Branch storage model — see context/explorations/clone-redesign.md.
2025
+ // 'worktree' = native `git worktree add` (shared base .git/config — legacy default).
2026
+ // 'clone' = self-standing `git clone` (own .git/ — closes cross-branch leak vectors).
2027
+ //
2028
+ // Enum is validated at the Drizzle/TS/Zod/service layer (no DB-side
2029
+ // CHECK) per context/guides/creating-database-migrations.md so adding a
2030
+ // value later doesn't force a table-recreation migration on SQLite.
2031
+ storage_mode: text2("storage_mode", { enum: ["worktree", "clone"] }).notNull().default("worktree"),
2032
+ // Only meaningful when storage_mode='clone'. NULL = full clone, positive
2033
+ // integer = `git clone --depth N` (shallow). The service layer rejects
2034
+ // a non-null clone_depth on worktree-mode rows.
2035
+ clone_depth: integer2("clone_depth"),
2036
+ // JSON blob for everything else
2037
+ data: t2.json("data").$type().notNull()
2038
+ },
2039
+ (table) => ({
2040
+ repoIdx: index2("branches_repo_idx").on(table.repo_id),
2041
+ nameIdx: index2("branches_name_idx").on(table.name),
2042
+ refIdx: index2("branches_ref_idx").on(table.ref),
2043
+ boardIdx: index2("branches_board_idx").on(table.board_id),
2044
+ createdIdx: index2("branches_created_idx").on(table.created_at),
2045
+ updatedIdx: index2("branches_updated_idx").on(table.updated_at),
2046
+ // Composite unique constraint (repo + name)
2047
+ uniqueRepoName: index2("branches_repo_name_unique").on(table.repo_id, table.name)
2048
+ })
2049
+ );
2050
+ var branchOwners2 = sqliteTable(
2051
+ "branch_owners",
2052
+ {
2053
+ branch_id: text2("branch_id", { length: 36 }).notNull().references(() => branches2.branch_id, { onDelete: "cascade" }),
2054
+ user_id: text2("user_id", { length: 36 }).notNull().references(() => users2.user_id, { onDelete: "cascade" }),
2055
+ created_at: t2.timestamp("created_at")
2056
+ },
2057
+ (table) => ({
2058
+ // Composite primary key matching migration 0016
2059
+ pk: primaryKey2({ columns: [table.branch_id, table.user_id] })
2060
+ })
2061
+ );
2062
+ var boardOwners2 = sqliteTable(
2063
+ "board_owners",
2064
+ {
2065
+ board_id: text2("board_id", { length: 36 }).notNull().references(() => boards2.board_id, { onDelete: "cascade" }),
2066
+ user_id: text2("user_id", { length: 36 }).notNull().references(() => users2.user_id, { onDelete: "cascade" }),
2067
+ created_at: t2.timestamp("created_at")
2068
+ },
2069
+ (table) => ({
2070
+ pk: primaryKey2({ columns: [table.board_id, table.user_id] }),
2071
+ userIdx: index2("board_owners_user_idx").on(table.user_id)
2072
+ })
2073
+ );
2074
+ var schedules2 = sqliteTable(
2075
+ "schedules",
2076
+ {
2077
+ schedule_id: text2("schedule_id", { length: 36 }).primaryKey(),
2078
+ branch_id: text2("branch_id", { length: 36 }).notNull().references(() => branches2.branch_id, { onDelete: "cascade" }),
2079
+ name: text2("name").notNull(),
2080
+ description: text2("description"),
2081
+ cron_expression: text2("cron_expression").notNull(),
2082
+ timezone_mode: text2("timezone_mode", { enum: ["local", "utc"] }).notNull().default("local"),
2083
+ timezone: text2("timezone"),
2084
+ // IANA, required when timezone_mode='local'
2085
+ prompt: text2("prompt").notNull(),
2086
+ // Handlebars template
2087
+ // jsonb on PG; mirrors BranchScheduleConfig minus promoted fields.
2088
+ agentic_tool_config: t2.json("agentic_tool_config").notNull(),
2089
+ enabled: t2.bool("enabled").notNull().default(true),
2090
+ allow_concurrent_runs: t2.bool("allow_concurrent_runs").notNull().default(false),
2091
+ retention: integer2("retention").notNull().default(5),
2092
+ // 0 = keep all
2093
+ last_run_at: integer2("last_run_at"),
2094
+ // Unix timestamp (ms)
2095
+ last_run_session_id: text2("last_run_session_id", { length: 36 }).references(
2096
+ () => sessions2.session_id,
2097
+ { onDelete: "set null" }
2098
+ ),
2099
+ next_run_at: integer2("next_run_at"),
2100
+ // Unix timestamp (ms), denormalized for scheduler
2101
+ created_at: t2.timestamp("created_at").notNull(),
2102
+ updated_at: t2.timestamp("updated_at").notNull(),
2103
+ created_by: text2("created_by", { length: 36 }).notNull().references(() => users2.user_id)
2104
+ },
2105
+ (table) => ({
2106
+ // Scheduler hot path: WHERE enabled = true AND next_run_at <= ?
2107
+ enabledNextRunIdx: index2("schedules_enabled_next_run_idx").on(table.enabled, table.next_run_at),
2108
+ branchIdx: index2("schedules_branch_idx").on(table.branch_id),
2109
+ createdByIdx: index2("schedules_created_by_idx").on(table.created_by)
2110
+ })
2111
+ );
2112
+ var users2 = sqliteTable(
2113
+ "users",
2114
+ {
2115
+ // Primary identity
2116
+ user_id: text2("user_id", { length: 36 }).primaryKey(),
2117
+ created_at: t2.timestamp("created_at").notNull(),
2118
+ updated_at: t2.timestamp("updated_at"),
2119
+ // Materialized for auth lookups
2120
+ email: text2("email").unique().notNull(),
2121
+ password: text2("password").notNull(),
2122
+ // bcrypt hashed
2123
+ // Basic profile (materialized for display)
2124
+ name: text2("name"),
2125
+ emoji: text2("emoji"),
2126
+ role: text2("role", {
2127
+ enum: ["superadmin", "admin", "member", "viewer"]
2128
+ // 'owner' is deprecated alias for 'superadmin'
2129
+ }).notNull().default("member"),
2130
+ // Unix username for process impersonation (optional, app-enforced uniqueness)
2131
+ unix_username: text2("unix_username"),
2132
+ // Onboarding state
2133
+ onboarding_completed: t2.bool("onboarding_completed").notNull().default(false),
2134
+ // Force password change flag (admin-settable, auto-cleared on password change)
2135
+ must_change_password: t2.bool("must_change_password").notNull().default(false),
2136
+ // Auth invalidation marker. Password changes set this timestamp so any
2137
+ // previously issued browser access or refresh token is rejected.
2138
+ tokens_valid_after: t2.timestamp("tokens_valid_after"),
2139
+ // JSON blob for profile/preferences
2140
+ data: t2.json("data").$type().notNull()
2141
+ },
2142
+ (table) => ({
2143
+ emailIdx: index2("users_email_idx").on(table.email)
2144
+ })
2145
+ );
2146
+ var groups2 = sqliteTable(
2147
+ "groups",
2148
+ {
2149
+ group_id: text2("group_id", { length: 36 }).primaryKey(),
2150
+ name: text2("name").notNull(),
2151
+ slug: text2("slug").notNull(),
2152
+ description: text2("description"),
2153
+ archived: t2.bool("archived").notNull().default(false),
2154
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2155
+ onDelete: "set null"
2156
+ }),
2157
+ created_at: t2.timestamp("created_at").notNull(),
2158
+ updated_at: t2.timestamp("updated_at")
2159
+ },
2160
+ (table) => ({
2161
+ slugIdx: uniqueIndex2("groups_slug_idx").on(table.slug),
2162
+ archivedIdx: index2("groups_archived_idx").on(table.archived)
2163
+ })
2164
+ );
2165
+ var groupMemberships2 = sqliteTable(
2166
+ "group_memberships",
2167
+ {
2168
+ group_id: text2("group_id", { length: 36 }).notNull().references(() => groups2.group_id, { onDelete: "cascade" }),
2169
+ user_id: text2("user_id", { length: 36 }).notNull().references(() => users2.user_id, { onDelete: "cascade" }),
2170
+ added_by: text2("added_by", { length: 36 }).references(() => users2.user_id, {
2171
+ onDelete: "set null"
2172
+ }),
2173
+ created_at: t2.timestamp("created_at").notNull()
2174
+ },
2175
+ (table) => ({
2176
+ pk: primaryKey2({ columns: [table.group_id, table.user_id] }),
2177
+ userIdx: index2("group_memberships_user_idx").on(table.user_id)
2178
+ })
2179
+ );
2180
+ var branchGroupGrants2 = sqliteTable(
2181
+ "branch_group_grants",
2182
+ {
2183
+ branch_id: text2("branch_id", { length: 36 }).notNull().references(() => branches2.branch_id, { onDelete: "cascade" }),
2184
+ group_id: text2("group_id", { length: 36 }).notNull().references(() => groups2.group_id, { onDelete: "cascade" }),
2185
+ can: text2("can", { enum: [...BRANCH_PERMISSION_LEVELS] }).notNull().default("view"),
2186
+ fs_access: text2("fs_access", { enum: ["none", "read", "write"] }).$type(),
2187
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2188
+ onDelete: "set null"
2189
+ }),
2190
+ created_at: t2.timestamp("created_at").notNull(),
2191
+ updated_at: t2.timestamp("updated_at")
2192
+ },
2193
+ (table) => ({
2194
+ pk: primaryKey2({ columns: [table.branch_id, table.group_id] }),
2195
+ groupIdx: index2("branch_group_grants_group_idx").on(table.group_id)
2196
+ })
2197
+ );
2198
+ var boardGroupGrants2 = sqliteTable(
2199
+ "board_group_grants",
2200
+ {
2201
+ board_id: text2("board_id", { length: 36 }).notNull().references(() => boards2.board_id, { onDelete: "cascade" }),
2202
+ group_id: text2("group_id", { length: 36 }).notNull().references(() => groups2.group_id, { onDelete: "cascade" }),
2203
+ can: text2("can", { enum: [...BRANCH_PERMISSION_LEVELS] }).notNull().default("view"),
2204
+ fs_access: text2("fs_access", { enum: ["none", "read", "write"] }).$type(),
2205
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2206
+ onDelete: "set null"
2207
+ }),
2208
+ created_at: t2.timestamp("created_at").notNull(),
2209
+ updated_at: t2.timestamp("updated_at")
2210
+ },
2211
+ (table) => ({
2212
+ pk: primaryKey2({ columns: [table.board_id, table.group_id] }),
2213
+ groupIdx: index2("board_group_grants_group_idx").on(table.group_id)
2214
+ })
2215
+ );
2216
+ var appVariables2 = sqliteTable(
2217
+ "app_variables",
2218
+ {
2219
+ variable_id: text2("variable_id", { length: 36 }).primaryKey(),
2220
+ namespace: text2("namespace").notNull(),
2221
+ key: text2("key").notNull(),
2222
+ value_text: text2("value_text"),
2223
+ value_encrypted: text2("value_encrypted"),
2224
+ is_encrypted: t2.bool("is_encrypted").notNull().default(false),
2225
+ content_type: text2("content_type").notNull().default("text/plain"),
2226
+ metadata: t2.json("metadata"),
2227
+ updated_by: text2("updated_by", { length: 36 }).references(() => users2.user_id, {
2228
+ onDelete: "set null"
2229
+ }),
2230
+ created_at: t2.timestamp("created_at").notNull(),
2231
+ updated_at: t2.timestamp("updated_at").notNull()
2232
+ },
2233
+ (table) => ({
2234
+ namespaceKeyIdx: uniqueIndex2("app_variables_namespace_key_idx").on(table.namespace, table.key),
2235
+ namespaceIdx: index2("app_variables_namespace_idx").on(table.namespace)
2236
+ })
2237
+ );
2238
+ var userApiKeys2 = sqliteTable(
2239
+ "user_api_keys",
2240
+ {
2241
+ id: text2("id", { length: 36 }).primaryKey(),
2242
+ user_id: text2("user_id", { length: 36 }).notNull().references(() => users2.user_id, { onDelete: "cascade" }),
2243
+ name: text2("name").notNull(),
2244
+ prefix: text2("prefix").notNull(),
2245
+ // first 12 chars: 'agor_sk_XXXX' for identification
2246
+ key_hash: text2("key_hash").notNull(),
2247
+ // bcrypt hash of full key
2248
+ created_at: t2.timestamp("created_at").notNull(),
2249
+ last_used_at: t2.timestamp("last_used_at")
2250
+ },
2251
+ (table) => ({
2252
+ userIdx: index2("user_api_keys_user_idx").on(table.user_id),
2253
+ prefixIdx: index2("user_api_keys_prefix_idx").on(table.prefix)
2254
+ })
2255
+ );
2256
+ var mcpServers2 = sqliteTable(
2257
+ "mcp_servers",
2258
+ {
2259
+ // Primary identity
2260
+ mcp_server_id: text2("mcp_server_id", { length: 36 }).primaryKey(),
2261
+ created_at: t2.timestamp("created_at").notNull(),
2262
+ updated_at: t2.timestamp("updated_at"),
2263
+ // Materialized for filtering
2264
+ name: text2("name").notNull(),
2265
+ // e.g., "filesystem", "sentry"
2266
+ transport: text2("transport", {
2267
+ enum: ["stdio", "http", "sse"]
2268
+ }).notNull(),
2269
+ scope: text2("scope", {
2270
+ enum: ["global", "session"]
2271
+ }).notNull(),
2272
+ enabled: t2.bool("enabled").notNull().default(true),
2273
+ // Scope foreign key
2274
+ // For 'global' scope: which user owns this server
2275
+ // For 'session' scope: use session_mcp_servers junction table (many-to-many)
2276
+ owner_user_id: text2("owner_user_id", { length: 36 }),
2277
+ // Source tracking (materialized for queries)
2278
+ source: text2("source", {
2279
+ enum: ["user", "imported", "agor"]
2280
+ }).notNull(),
2281
+ // JSON blob for configuration and capabilities
2282
+ data: t2.json("data").$type().notNull()
2283
+ },
2284
+ (table) => ({
2285
+ nameIdx: index2("mcp_servers_name_idx").on(table.name),
2286
+ scopeIdx: index2("mcp_servers_scope_idx").on(table.scope),
2287
+ ownerIdx: index2("mcp_servers_owner_idx").on(table.owner_user_id),
2288
+ enabledIdx: index2("mcp_servers_enabled_idx").on(table.enabled)
2289
+ })
2290
+ );
2291
+ var cardTypes2 = sqliteTable(
2292
+ "card_types",
2293
+ {
2294
+ card_type_id: text2("card_type_id", { length: 36 }).primaryKey(),
2295
+ name: text2("name").notNull(),
2296
+ emoji: text2("emoji"),
2297
+ color: text2("color"),
2298
+ json_schema: text2("json_schema"),
2299
+ // JSON string of JSON Schema
2300
+ created_by: text2("created_by", { length: 36 }),
2301
+ created_at: t2.timestamp("created_at").notNull(),
2302
+ updated_at: t2.timestamp("updated_at").notNull()
2303
+ },
2304
+ (table) => ({
2305
+ nameIdx: index2("card_types_name_idx").on(table.name)
2306
+ })
2307
+ );
2308
+ var cards2 = sqliteTable(
2309
+ "cards",
2310
+ {
2311
+ card_id: text2("card_id", { length: 36 }).primaryKey(),
2312
+ board_id: text2("board_id", { length: 36 }).notNull().references(() => boards2.board_id, { onDelete: "cascade" }),
2313
+ card_type_id: text2("card_type_id", { length: 36 }).references(() => cardTypes2.card_type_id, {
2314
+ onDelete: "set null"
2315
+ }),
2316
+ title: text2("title").notNull(),
2317
+ url: text2("url"),
2318
+ description: text2("description"),
2319
+ note: text2("note"),
2320
+ data: text2("data"),
2321
+ // JSON blob validated against CardType.json_schema if present
2322
+ color_override: text2("color_override"),
2323
+ emoji_override: text2("emoji_override"),
2324
+ created_by: text2("created_by", { length: 36 }),
2325
+ created_at: t2.timestamp("created_at").notNull(),
2326
+ updated_at: t2.timestamp("updated_at").notNull(),
2327
+ archived: t2.bool("archived").notNull().default(false),
2328
+ archived_at: t2.timestamp("archived_at")
2329
+ },
2330
+ (table) => ({
2331
+ boardIdx: index2("cards_board_idx").on(table.board_id),
2332
+ cardTypeIdx: index2("cards_card_type_idx").on(table.card_type_id),
2333
+ titleIdx: index2("cards_title_idx").on(table.title),
2334
+ archivedIdx: index2("cards_archived_idx").on(table.archived),
2335
+ createdIdx: index2("cards_created_idx").on(table.created_at)
2336
+ })
2337
+ );
2338
+ var artifacts2 = sqliteTable(
2339
+ "artifacts",
2340
+ {
2341
+ artifact_id: text2("artifact_id", { length: 36 }).primaryKey(),
2342
+ branch_id: text2("branch_id", { length: 36 }).references(() => branches2.branch_id, {
2343
+ onDelete: "set null"
2344
+ }),
2345
+ source_session_id: text2("source_session_id", { length: 36 }).references(
2346
+ () => sessions2.session_id,
2347
+ {
2348
+ onDelete: "set null"
2349
+ }
2350
+ ),
2351
+ board_id: text2("board_id", { length: 36 }).notNull().references(() => boards2.board_id, { onDelete: "cascade" }),
2352
+ name: text2("name").notNull(),
2353
+ description: text2("description"),
2354
+ path: text2("path"),
2355
+ // provenance only — where files were read from
2356
+ template: text2("template").notNull().default("react"),
2357
+ build_status: text2("build_status").notNull().default("unknown"),
2358
+ build_errors: t2.json("build_errors"),
2359
+ content_hash: text2("content_hash"),
2360
+ files: t2.json("files"),
2361
+ dependencies: t2.json("dependencies"),
2362
+ entry: text2("entry"),
2363
+ // denormalized cache of the Sandpack entry file
2364
+ sandpack_config: t2.json("sandpack_config"),
2365
+ required_env_vars: t2.json("required_env_vars"),
2366
+ agor_grants: t2.json("agor_grants"),
2367
+ agor_runtime: t2.json("agor_runtime"),
2368
+ public: t2.bool("public").notNull().default(true),
2369
+ created_by: text2("created_by", { length: 36 }),
2370
+ created_at: t2.timestamp("created_at").notNull(),
2371
+ updated_at: t2.timestamp("updated_at").notNull(),
2372
+ archived: t2.bool("archived").notNull().default(false),
2373
+ archived_at: t2.timestamp("archived_at")
2374
+ },
2375
+ (table) => ({
2376
+ branchIdx: index2("artifacts_branch_idx").on(table.branch_id),
2377
+ sourceSessionIdx: index2("artifacts_source_session_idx").on(table.source_session_id),
2378
+ boardIdx: index2("artifacts_board_idx").on(table.board_id),
2379
+ archivedIdx: index2("artifacts_archived_idx").on(table.archived),
2380
+ publicIdx: index2("artifacts_public_idx").on(table.public)
2381
+ })
2382
+ );
2383
+ var artifactTrustGrants2 = sqliteTable(
2384
+ "artifact_trust_grants",
2385
+ {
2386
+ grant_id: text2("grant_id", { length: 36 }).primaryKey(),
2387
+ user_id: text2("user_id", { length: 36 }).notNull(),
2388
+ // CHECK constraint omitted — service-layer enforcement only, so adding new
2389
+ // scope_types in the future doesn't require a SQLite table-recreate.
2390
+ scope_type: text2("scope_type").notNull(),
2391
+ scope_value: text2("scope_value"),
2392
+ env_vars_set: t2.json("env_vars_set").notNull(),
2393
+ agor_grants_set: t2.json("agor_grants_set").notNull(),
2394
+ granted_at: t2.timestamp("granted_at").notNull(),
2395
+ revoked_at: t2.timestamp("revoked_at")
2396
+ },
2397
+ (table) => ({
2398
+ userIdx: index2("artifact_trust_grants_user_idx").on(table.user_id),
2399
+ scopeIdx: index2("artifact_trust_grants_scope_idx").on(table.scope_type, table.scope_value)
2400
+ })
2401
+ );
2402
+ var boardObjects2 = sqliteTable(
2403
+ "board_objects",
2404
+ {
2405
+ // Primary identity
2406
+ object_id: text2("object_id", { length: 36 }).primaryKey(),
2407
+ board_id: text2("board_id", { length: 36 }).notNull().references(() => boards2.board_id, { onDelete: "cascade" }),
2408
+ created_at: t2.timestamp("created_at").notNull(),
2409
+ // Polymorphic entity reference (exactly one must be set)
2410
+ branch_id: text2("branch_id", { length: 36 }).references(() => branches2.branch_id, {
2411
+ onDelete: "cascade"
2412
+ }),
2413
+ card_id: text2("card_id", { length: 36 }).references(() => cards2.card_id, {
2414
+ onDelete: "cascade"
2415
+ }),
2416
+ // Position data (JSON)
2417
+ data: t2.json("data").$type().notNull()
2418
+ },
2419
+ (table) => ({
2420
+ boardIdx: index2("board_objects_board_idx").on(table.board_id),
2421
+ branchIdx: index2("board_objects_branch_idx").on(table.branch_id),
2422
+ cardIdx: index2("board_objects_card_idx").on(table.card_id)
2423
+ })
2424
+ );
2425
+ var sessionMcpServers2 = sqliteTable(
2426
+ "session_mcp_servers",
2427
+ {
2428
+ session_id: text2("session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
2429
+ mcp_server_id: text2("mcp_server_id", { length: 36 }).notNull().references(() => mcpServers2.mcp_server_id, { onDelete: "cascade" }),
2430
+ enabled: t2.bool("enabled").notNull().default(true),
2431
+ added_at: t2.timestamp("added_at").notNull()
2432
+ },
2433
+ (table) => ({
2434
+ // Composite primary key
2435
+ pk: index2("session_mcp_servers_pk").on(table.session_id, table.mcp_server_id),
2436
+ // Indexes for queries
2437
+ sessionIdx: index2("session_mcp_servers_session_idx").on(table.session_id),
2438
+ serverIdx: index2("session_mcp_servers_server_idx").on(table.mcp_server_id),
2439
+ enabledIdx: index2("session_mcp_servers_enabled_idx").on(table.session_id, table.enabled)
2440
+ })
2441
+ );
2442
+ var userMcpOauthTokens2 = sqliteTable(
2443
+ "user_mcp_oauth_tokens",
2444
+ {
2445
+ // NULL = shared-mode token (one per mcp_server_id)
2446
+ user_id: text2("user_id", { length: 36 }).references(() => users2.user_id, {
2447
+ onDelete: "cascade"
2448
+ }),
2449
+ mcp_server_id: text2("mcp_server_id", { length: 36 }).notNull().references(() => mcpServers2.mcp_server_id, { onDelete: "cascade" }),
2450
+ oauth_access_token: text2("oauth_access_token").notNull(),
2451
+ oauth_token_expires_at: t2.timestamp("oauth_token_expires_at"),
2452
+ // Unix timestamp in milliseconds
2453
+ oauth_refresh_token: text2("oauth_refresh_token"),
2454
+ // DCR / registered client credentials this grant was issued under.
2455
+ // Must be preserved across refreshes.
2456
+ oauth_client_id: text2("oauth_client_id"),
2457
+ oauth_client_secret: text2("oauth_client_secret"),
2458
+ created_at: t2.timestamp("created_at").notNull(),
2459
+ updated_at: t2.timestamp("updated_at")
2460
+ },
2461
+ (table) => ({
2462
+ // Composite lookup indexes. Uniqueness enforced via partial unique indexes
2463
+ // created in the migration (one for per-user rows, one for the shared row).
2464
+ pk: index2("user_mcp_oauth_tokens_pk").on(table.user_id, table.mcp_server_id),
2465
+ userIdx: index2("user_mcp_oauth_tokens_user_idx").on(table.user_id),
2466
+ serverIdx: index2("user_mcp_oauth_tokens_server_idx").on(table.mcp_server_id)
2467
+ })
2468
+ );
2469
+ var boardComments2 = sqliteTable(
2470
+ "board_comments",
2471
+ {
2472
+ // Primary identity
2473
+ comment_id: text2("comment_id", { length: 36 }).primaryKey(),
2474
+ created_at: t2.timestamp("created_at").notNull(),
2475
+ updated_at: t2.timestamp("updated_at"),
2476
+ // Scoping & authorship
2477
+ board_id: text2("board_id", { length: 36 }).notNull().references(() => boards2.board_id, { onDelete: "cascade" }),
2478
+ created_by: text2("created_by", { length: 36 }).notNull(),
2479
+ // FLEXIBLE ATTACHMENTS (all optional)
2480
+ // Phase 1: board-level only (all NULL)
2481
+ // Phase 2: object attachments (session, task, message, branch)
2482
+ // Phase 3: spatial positioning
2483
+ session_id: text2("session_id", { length: 36 }).references(() => sessions2.session_id, {
2484
+ onDelete: "set null"
2485
+ }),
2486
+ task_id: text2("task_id", { length: 36 }).references(() => tasks2.task_id, {
2487
+ onDelete: "set null"
2488
+ }),
2489
+ message_id: text2("message_id", { length: 36 }).references(() => messages2.message_id, {
2490
+ onDelete: "set null"
2491
+ }),
2492
+ branch_id: text2("branch_id", { length: 36 }).references(() => branches2.branch_id, {
2493
+ onDelete: "cascade"
2494
+ }),
2495
+ // Content (materialized for display)
2496
+ content: text2("content").notNull(),
2497
+ // Markdown-supported text
2498
+ content_preview: text2("content_preview").notNull(),
2499
+ // First 200 chars
2500
+ // Thread support (optional)
2501
+ parent_comment_id: text2("parent_comment_id", { length: 36 }),
2502
+ // Metadata (materialized for filtering)
2503
+ resolved: t2.bool("resolved").notNull().default(false),
2504
+ edited: t2.bool("edited").notNull().default(false),
2505
+ // Reactions (for BOTH thread roots and replies)
2506
+ // Stored as JSON array: [{ user_id: "abc", emoji: "👍" }, ...]
2507
+ // Display grouped by emoji: { "👍": ["alice", "bob"], "🎉": ["charlie"] }
2508
+ reactions: t2.json("reactions").$type().notNull().default(sql3`'[]'`),
2509
+ // JSON blob for advanced features
2510
+ data: t2.json("data").$type().notNull()
2511
+ },
2512
+ (table) => ({
2513
+ boardIdx: index2("board_comments_board_idx").on(table.board_id),
2514
+ sessionIdx: index2("board_comments_session_idx").on(table.session_id),
2515
+ taskIdx: index2("board_comments_task_idx").on(table.task_id),
2516
+ messageIdx: index2("board_comments_message_idx").on(table.message_id),
2517
+ branchIdx: index2("board_comments_branch_idx").on(table.branch_id),
2518
+ createdByIdx: index2("board_comments_created_by_idx").on(table.created_by),
2519
+ parentIdx: index2("board_comments_parent_idx").on(table.parent_comment_id),
2520
+ createdIdx: index2("board_comments_created_idx").on(table.created_at),
2521
+ resolvedIdx: index2("board_comments_resolved_idx").on(table.resolved)
2522
+ })
2523
+ );
2524
+ var gatewayChannels2 = sqliteTable(
2525
+ "gateway_channels",
2526
+ {
2527
+ // Primary identity
2528
+ id: text2("id", { length: 36 }).primaryKey(),
2529
+ created_at: t2.timestamp("created_at").notNull(),
2530
+ updated_at: t2.timestamp("updated_at").notNull(),
2531
+ // User attribution
2532
+ created_by: text2("created_by", { length: 36 }).notNull(),
2533
+ // Materialized for queries
2534
+ name: text2("name").notNull(),
2535
+ channel_type: text2("channel_type", {
2536
+ enum: ["slack", "discord", "whatsapp", "telegram", "github", "teams"]
2537
+ }).notNull(),
2538
+ target_branch_id: text2("target_branch_id", { length: 36 }).notNull().references(() => branches2.branch_id, { onDelete: "cascade" }),
2539
+ agor_user_id: text2("agor_user_id", { length: 36 }).notNull(),
2540
+ channel_key: text2("channel_key").notNull().unique(),
2541
+ enabled: t2.bool("enabled").notNull().default(true),
2542
+ last_message_at: t2.timestamp("last_message_at"),
2543
+ // JSON blob for platform credentials (encrypted at rest)
2544
+ config: t2.json("config").notNull(),
2545
+ // JSON blob for agentic tool configuration (agent, model, permission mode, etc.)
2546
+ agentic_config: t2.json("agentic_config")
2547
+ },
2548
+ (table) => ({
2549
+ channelKeyIdx: index2("idx_gateway_channel_key").on(table.channel_key),
2550
+ enabledTypeIdx: index2("idx_gateway_enabled_type").on(table.enabled, table.channel_type)
2551
+ })
2552
+ );
2553
+ var threadSessionMap2 = sqliteTable(
2554
+ "thread_session_map",
2555
+ {
2556
+ // Primary identity
2557
+ id: text2("id", { length: 36 }).primaryKey(),
2558
+ created_at: t2.timestamp("created_at").notNull(),
2559
+ last_message_at: t2.timestamp("last_message_at").notNull(),
2560
+ // Foreign keys
2561
+ channel_id: text2("channel_id", { length: 36 }).notNull().references(() => gatewayChannels2.id, { onDelete: "cascade" }),
2562
+ thread_id: text2("thread_id").notNull(),
2563
+ session_id: text2("session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
2564
+ branch_id: text2("branch_id", { length: 36 }).notNull().references(() => branches2.branch_id),
2565
+ // Materialized for queries
2566
+ status: text2("status", {
2567
+ enum: ["active", "archived", "paused"]
2568
+ }).notNull().default("active"),
2569
+ // JSON blob for extra metadata
2570
+ metadata: t2.json("metadata")
2571
+ },
2572
+ (table) => ({
2573
+ uniqueChannelThread: uniqueIndex2("uniq_thread_map_channel_thread").on(
2574
+ table.channel_id,
2575
+ table.thread_id
2576
+ ),
2577
+ sessionIdx: index2("idx_thread_map_session_id").on(table.session_id),
2578
+ threadIdx: index2("idx_thread_map_thread_id").on(table.thread_id),
2579
+ channelStatusIdx: index2("idx_thread_map_channel_status").on(table.channel_id, table.status)
2580
+ })
2581
+ );
2582
+ var gatewayOutboundMessages2 = sqliteTable(
2583
+ "gateway_outbound_messages",
2584
+ {
2585
+ id: text2("id", { length: 36 }).primaryKey(),
2586
+ created_at: t2.timestamp("created_at").notNull(),
2587
+ updated_at: t2.timestamp("updated_at").notNull(),
2588
+ gateway_channel_id: text2("gateway_channel_id", { length: 36 }).notNull().references(() => gatewayChannels2.id, { onDelete: "cascade" }),
2589
+ channel_type: text2("channel_type", {
2590
+ enum: ["slack", "discord", "whatsapp", "telegram", "github", "teams"]
2591
+ }).notNull(),
2592
+ platform_channel_id: text2("platform_channel_id").notNull(),
2593
+ platform_message_id: text2("platform_message_id").notNull(),
2594
+ platform_thread_id: text2("platform_thread_id").notNull(),
2595
+ platform_permalink: text2("platform_permalink"),
2596
+ target_branch_id: text2("target_branch_id", { length: 36 }).notNull().references(() => branches2.branch_id),
2597
+ emitted_by_user_id: text2("emitted_by_user_id", { length: 36 }).notNull().references(() => users2.user_id),
2598
+ emitted_by_session_id: text2("emitted_by_session_id", { length: 36 }).references(
2599
+ () => sessions2.session_id,
2600
+ {
2601
+ onDelete: "set null"
2602
+ }
2603
+ ),
2604
+ emitted_by_task_id: text2("emitted_by_task_id", { length: 36 }).references(() => tasks2.task_id, {
2605
+ onDelete: "set null"
2606
+ }),
2607
+ emitted_by_schedule_id: text2("emitted_by_schedule_id", { length: 36 }).references(
2608
+ () => schedules2.schedule_id,
2609
+ {
2610
+ onDelete: "set null"
2611
+ }
2612
+ ),
2613
+ message_text: text2("message_text").notNull(),
2614
+ message_preview: text2("message_preview").notNull(),
2615
+ metadata: t2.json("metadata"),
2616
+ consumed_by_session_id: text2("consumed_by_session_id", { length: 36 }).references(
2617
+ () => sessions2.session_id,
2618
+ {
2619
+ onDelete: "set null"
2620
+ }
2621
+ ),
2622
+ consumed_at: t2.timestamp("consumed_at")
2623
+ },
2624
+ (table) => ({
2625
+ uniqueChannelThread: uniqueIndex2("uniq_gateway_outbound_channel_thread").on(
2626
+ table.gateway_channel_id,
2627
+ table.platform_thread_id
2628
+ ),
2629
+ emittedSessionIdx: index2("idx_gateway_outbound_emitted_session").on(
2630
+ table.emitted_by_session_id
2631
+ ),
2632
+ emittedScheduleIdx: index2("idx_gateway_outbound_emitted_schedule").on(
2633
+ table.emitted_by_schedule_id
2634
+ ),
2635
+ targetBranchCreatedIdx: index2("idx_gateway_outbound_branch_created").on(
2636
+ table.target_branch_id,
2637
+ table.created_at
2638
+ ),
2639
+ consumedIdx: index2("idx_gateway_outbound_consumed").on(table.consumed_at)
2640
+ })
2641
+ );
2642
+ var sessionEnvSelections2 = sqliteTable(
2643
+ "session_env_selections",
2644
+ {
2645
+ session_id: text2("session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
2646
+ env_var_name: text2("env_var_name").notNull(),
2647
+ created_at: t2.timestamp("created_at").notNull()
2648
+ },
2649
+ (table) => ({
2650
+ pk: primaryKey2({ columns: [table.session_id, table.env_var_name] }),
2651
+ sessionIdx: index2("session_env_selections_session_idx").on(table.session_id)
2652
+ })
2653
+ );
2654
+ var kbNamespaces2 = sqliteTable(
2655
+ "kb_namespaces",
2656
+ {
2657
+ namespace_id: text2("namespace_id", { length: 36 }).primaryKey(),
2658
+ slug: text2("slug").notNull(),
2659
+ display_name: text2("display_name").notNull(),
2660
+ description: text2("description"),
2661
+ kind: text2("kind", { enum: ["system", "global", "user", "repo", "branch", "team"] }).notNull().default("global"),
2662
+ owner_user_id: text2("owner_user_id", { length: 36 }).references(() => users2.user_id, {
2663
+ onDelete: "set null"
2664
+ }),
2665
+ repo_id: text2("repo_id", { length: 36 }).references(() => repos2.repo_id, {
2666
+ onDelete: "set null"
2667
+ }),
2668
+ branch_id: text2("branch_id", { length: 36 }).references(() => branches2.branch_id, {
2669
+ onDelete: "set null"
2670
+ }),
2671
+ visibility_default: text2("visibility_default", { enum: ["public", "private"] }).notNull().default("public"),
2672
+ others_can: text2("others_can", { enum: ["none", "read", "write"] }).notNull().default("write"),
2673
+ metadata: t2.json("metadata"),
2674
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2675
+ onDelete: "set null"
2676
+ }),
2677
+ created_at: t2.timestamp("created_at").notNull(),
2678
+ updated_at: t2.timestamp("updated_at"),
2679
+ archived: t2.bool("archived").notNull().default(false),
2680
+ archived_at: t2.timestamp("archived_at")
2681
+ },
2682
+ (table) => ({
2683
+ slugIdx: uniqueIndex2("kb_namespaces_slug_idx").on(table.slug).where(sql3`${table.archived} = false`),
2684
+ kindIdx: index2("kb_namespaces_kind_idx").on(table.kind),
2685
+ ownerIdx: index2("kb_namespaces_owner_idx").on(table.owner_user_id),
2686
+ repoIdx: index2("kb_namespaces_repo_idx").on(table.repo_id),
2687
+ branchIdx: index2("kb_namespaces_branch_idx").on(table.branch_id),
2688
+ archivedIdx: index2("kb_namespaces_archived_idx").on(table.archived)
2689
+ })
2690
+ );
2691
+ var kbNamespaceAcl2 = sqliteTable(
2692
+ "kb_namespace_acl",
2693
+ {
2694
+ namespace_acl_id: text2("namespace_acl_id", { length: 36 }).primaryKey(),
2695
+ namespace_id: text2("namespace_id", { length: 36 }).notNull().references(() => kbNamespaces2.namespace_id, { onDelete: "cascade" }),
2696
+ subject_type: text2("subject_type", { enum: ["user", "group"] }).notNull(),
2697
+ subject_id: text2("subject_id", { length: 36 }).notNull(),
2698
+ permission: text2("permission", { enum: ["read", "write", "own"] }).notNull(),
2699
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2700
+ onDelete: "set null"
2701
+ }),
2702
+ created_at: t2.timestamp("created_at").notNull(),
2703
+ updated_at: t2.timestamp("updated_at")
2704
+ },
2705
+ (table) => ({
2706
+ namespaceIdx: index2("kb_namespace_acl_namespace_idx").on(table.namespace_id),
2707
+ subjectIdx: index2("kb_namespace_acl_subject_idx").on(table.subject_type, table.subject_id),
2708
+ namespaceSubjectIdx: uniqueIndex2("kb_namespace_acl_namespace_subject_idx").on(
2709
+ table.namespace_id,
2710
+ table.subject_type,
2711
+ table.subject_id
2712
+ )
2713
+ })
2714
+ );
2715
+ var kbDocuments2 = sqliteTable(
2716
+ "kb_documents",
2717
+ {
2718
+ document_id: text2("document_id", { length: 36 }).primaryKey(),
2719
+ namespace_id: text2("namespace_id", { length: 36 }).notNull().references(() => kbNamespaces2.namespace_id, { onDelete: "cascade" }),
2720
+ path: text2("path").notNull(),
2721
+ uri: text2("uri").notNull(),
2722
+ title: text2("title").notNull(),
2723
+ icon_emoji: text2("icon_emoji"),
2724
+ kind: text2("kind", {
2725
+ enum: ["doc", "memory", "skill", "prompt", "guide", "decision", "bundle", "external"]
2726
+ }).notNull().default("doc"),
2727
+ visibility: text2("visibility", { enum: ["public", "private"] }).notNull().default("public"),
2728
+ status: text2("status", { enum: ["draft", "published"] }).notNull().default("published"),
2729
+ edit_policy: text2("edit_policy", { enum: ["owner", "public", "admins"] }).notNull().default("owner"),
2730
+ // Application-maintained pointer. Avoids a circular FK with versions.
2731
+ current_version_id: text2("current_version_id", { length: 36 }),
2732
+ metadata: t2.json("metadata"),
2733
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2734
+ onDelete: "set null"
2735
+ }),
2736
+ created_at: t2.timestamp("created_at").notNull(),
2737
+ updated_by: text2("updated_by", { length: 36 }).references(() => users2.user_id, {
2738
+ onDelete: "set null"
2739
+ }),
2740
+ updated_at: t2.timestamp("updated_at"),
2741
+ archived: t2.bool("archived").notNull().default(false),
2742
+ archived_at: t2.timestamp("archived_at")
2743
+ },
2744
+ (table) => ({
2745
+ namespacePathIdx: uniqueIndex2("kb_documents_namespace_path_idx").on(table.namespace_id, table.path).where(sql3`${table.archived} = false`),
2746
+ uriIdx: uniqueIndex2("kb_documents_uri_idx").on(table.uri).where(sql3`${table.archived} = false`),
2747
+ namespaceIdx: index2("kb_documents_namespace_idx").on(table.namespace_id),
2748
+ kindIdx: index2("kb_documents_kind_idx").on(table.kind),
2749
+ visibilityIdx: index2("kb_documents_visibility_idx").on(table.visibility),
2750
+ statusIdx: index2("kb_documents_status_idx").on(table.status),
2751
+ createdByIdx: index2("kb_documents_created_by_idx").on(table.created_by),
2752
+ updatedAtIdx: index2("kb_documents_updated_at_idx").on(table.updated_at),
2753
+ archivedIdx: index2("kb_documents_archived_idx").on(table.archived)
2754
+ })
2755
+ );
2756
+ var kbDocumentVersions2 = sqliteTable(
2757
+ "kb_document_versions",
2758
+ {
2759
+ version_id: text2("version_id", { length: 36 }).primaryKey(),
2760
+ document_id: text2("document_id", { length: 36 }).notNull().references(() => kbDocuments2.document_id, { onDelete: "cascade" }),
2761
+ version_number: integer2("version_number").notNull(),
2762
+ content_text: text2("content_text"),
2763
+ content_blob: blob("content_blob"),
2764
+ mime_type: text2("mime_type").notNull().default("text/markdown"),
2765
+ content_md5: text2("content_md5"),
2766
+ content_sha256: text2("content_sha256"),
2767
+ byte_length: integer2("byte_length"),
2768
+ char_length: integer2("char_length"),
2769
+ frontmatter: t2.json("frontmatter"),
2770
+ metadata: t2.json("metadata"),
2771
+ change_summary: text2("change_summary"),
2772
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2773
+ onDelete: "set null"
2774
+ }),
2775
+ created_at: t2.timestamp("created_at").notNull()
2776
+ },
2777
+ (table) => ({
2778
+ documentVersionIdx: uniqueIndex2("kb_document_versions_document_version_idx").on(
2779
+ table.document_id,
2780
+ table.version_number
2781
+ ),
2782
+ documentIdx: index2("kb_document_versions_document_idx").on(table.document_id),
2783
+ createdIdx: index2("kb_document_versions_created_idx").on(table.created_at),
2784
+ md5Idx: index2("kb_document_versions_md5_idx").on(table.content_md5)
2785
+ })
2786
+ );
2787
+ var kbDocumentUnits2 = sqliteTable(
2788
+ "kb_document_units",
2789
+ {
2790
+ unit_id: text2("unit_id", { length: 36 }).primaryKey(),
2791
+ document_id: text2("document_id", { length: 36 }).notNull().references(() => kbDocuments2.document_id, { onDelete: "cascade" }),
2792
+ version_id: text2("version_id", { length: 36 }).notNull().references(() => kbDocumentVersions2.version_id, { onDelete: "cascade" }),
2793
+ kind: text2("kind", { enum: ["document", "section", "file", "auto_split"] }).notNull().default("document"),
2794
+ ordinal: integer2("ordinal").notNull().default(0),
2795
+ path_anchor: text2("path_anchor"),
2796
+ heading_path: text2("heading_path"),
2797
+ source_path: text2("source_path"),
2798
+ content_text: text2("content_text"),
2799
+ content_md5: text2("content_md5"),
2800
+ start_offset: integer2("start_offset"),
2801
+ end_offset: integer2("end_offset"),
2802
+ embedding_status: text2("embedding_status", {
2803
+ enum: ["not_configured", "pending", "ready", "stale", "error"]
2804
+ }).notNull().default("not_configured"),
2805
+ embedding_model: text2("embedding_model"),
2806
+ embedding_dimensions: integer2("embedding_dimensions"),
2807
+ embedding_hash: text2("embedding_hash"),
2808
+ embedding_error: text2("embedding_error"),
2809
+ metadata: t2.json("metadata"),
2810
+ created_at: t2.timestamp("created_at").notNull(),
2811
+ updated_at: t2.timestamp("updated_at")
2812
+ },
2813
+ (table) => ({
2814
+ documentIdx: index2("kb_document_units_document_idx").on(table.document_id),
2815
+ versionIdx: index2("kb_document_units_version_idx").on(table.version_id),
2816
+ versionOrdinalIdx: index2("kb_document_units_version_ordinal_idx").on(
2817
+ table.version_id,
2818
+ table.ordinal
2819
+ ),
2820
+ contentHashIdx: index2("kb_document_units_content_hash_idx").on(table.content_md5),
2821
+ embeddingStatusIdx: index2("kb_document_units_embedding_status_idx").on(table.embedding_status)
2822
+ })
2823
+ );
2824
+ var kbEmbeddingSpaces2 = sqliteTable(
2825
+ "kb_embedding_spaces",
2826
+ {
2827
+ embedding_space_id: text2("embedding_space_id", { length: 36 }).primaryKey(),
2828
+ provider: text2("provider").notNull(),
2829
+ model: text2("model").notNull(),
2830
+ dimensions: integer2("dimensions").notNull(),
2831
+ storage_type: text2("storage_type").notNull().default("vector"),
2832
+ distance: text2("distance").notNull().default("cosine"),
2833
+ active: t2.bool("active").notNull().default(true),
2834
+ metadata: t2.json("metadata"),
2835
+ created_at: t2.timestamp("created_at").notNull(),
2836
+ updated_at: t2.timestamp("updated_at")
2837
+ },
2838
+ (table) => ({
2839
+ providerModelIdx: uniqueIndex2("kb_embedding_spaces_provider_model_idx").on(
2840
+ table.provider,
2841
+ table.model,
2842
+ table.dimensions,
2843
+ table.storage_type,
2844
+ table.distance
2845
+ ),
2846
+ activeIdx: index2("kb_embedding_spaces_active_idx").on(table.active)
2847
+ })
2848
+ );
2849
+ var kbGraphNodes2 = sqliteTable(
2850
+ "kb_graph_nodes",
2851
+ {
2852
+ node_id: text2("node_id", { length: 36 }).primaryKey(),
2853
+ node_type: text2("node_type", {
2854
+ enum: [
2855
+ "namespace",
2856
+ "document",
2857
+ "document_unit",
2858
+ "branch",
2859
+ "session",
2860
+ "task",
2861
+ "message",
2862
+ "artifact",
2863
+ "repo",
2864
+ "board",
2865
+ "user",
2866
+ "tag",
2867
+ "external"
2868
+ ]
2869
+ }).notNull(),
2870
+ uri: text2("uri").notNull(),
2871
+ label: text2("label"),
2872
+ namespace_id: text2("namespace_id", { length: 36 }).references(() => kbNamespaces2.namespace_id, {
2873
+ onDelete: "cascade"
2874
+ }),
2875
+ document_id: text2("document_id", { length: 36 }).references(() => kbDocuments2.document_id, {
2876
+ onDelete: "cascade"
2877
+ }),
2878
+ unit_id: text2("unit_id", { length: 36 }).references(() => kbDocumentUnits2.unit_id, {
2879
+ onDelete: "cascade"
2880
+ }),
2881
+ branch_id: text2("branch_id", { length: 36 }).references(() => branches2.branch_id, {
2882
+ onDelete: "cascade"
2883
+ }),
2884
+ session_id: text2("session_id", { length: 36 }).references(() => sessions2.session_id, {
2885
+ onDelete: "cascade"
2886
+ }),
2887
+ task_id: text2("task_id", { length: 36 }).references(() => tasks2.task_id, {
2888
+ onDelete: "cascade"
2889
+ }),
2890
+ message_id: text2("message_id", { length: 36 }).references(() => messages2.message_id, {
2891
+ onDelete: "cascade"
2892
+ }),
2893
+ artifact_id: text2("artifact_id", { length: 36 }).references(() => artifacts2.artifact_id, {
2894
+ onDelete: "cascade"
2895
+ }),
2896
+ repo_id: text2("repo_id", { length: 36 }).references(() => repos2.repo_id, {
2897
+ onDelete: "cascade"
2898
+ }),
2899
+ board_id: text2("board_id", { length: 36 }).references(() => boards2.board_id, {
2900
+ onDelete: "cascade"
2901
+ }),
2902
+ user_id: text2("user_id", { length: 36 }).references(() => users2.user_id, {
2903
+ onDelete: "cascade"
2904
+ }),
2905
+ external_uri: text2("external_uri"),
2906
+ metadata: t2.json("metadata"),
2907
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2908
+ onDelete: "set null"
2909
+ }),
2910
+ created_at: t2.timestamp("created_at").notNull(),
2911
+ updated_at: t2.timestamp("updated_at"),
2912
+ archived: t2.bool("archived").notNull().default(false),
2913
+ archived_at: t2.timestamp("archived_at")
2914
+ },
2915
+ (table) => ({
2916
+ uriIdx: uniqueIndex2("kb_graph_nodes_uri_idx").on(table.uri).where(sql3`${table.archived} = false`),
2917
+ typeIdx: index2("kb_graph_nodes_type_idx").on(table.node_type),
2918
+ namespaceIdx: index2("kb_graph_nodes_namespace_idx").on(table.namespace_id),
2919
+ documentIdx: index2("kb_graph_nodes_document_idx").on(table.document_id),
2920
+ unitIdx: index2("kb_graph_nodes_unit_idx").on(table.unit_id),
2921
+ branchIdx: index2("kb_graph_nodes_branch_idx").on(table.branch_id),
2922
+ sessionIdx: index2("kb_graph_nodes_session_idx").on(table.session_id),
2923
+ taskIdx: index2("kb_graph_nodes_task_idx").on(table.task_id),
2924
+ messageIdx: index2("kb_graph_nodes_message_idx").on(table.message_id),
2925
+ artifactIdx: index2("kb_graph_nodes_artifact_idx").on(table.artifact_id),
2926
+ repoIdx: index2("kb_graph_nodes_repo_idx").on(table.repo_id),
2927
+ boardIdx: index2("kb_graph_nodes_board_idx").on(table.board_id),
2928
+ userIdx: index2("kb_graph_nodes_user_idx").on(table.user_id),
2929
+ externalUriIdx: index2("kb_graph_nodes_external_uri_idx").on(table.external_uri),
2930
+ archivedIdx: index2("kb_graph_nodes_archived_idx").on(table.archived)
2931
+ })
2932
+ );
2933
+ var kbGraphEdges2 = sqliteTable(
2934
+ "kb_graph_edges",
2935
+ {
2936
+ edge_id: text2("edge_id", { length: 36 }).primaryKey(),
2937
+ source_node_id: text2("source_node_id", { length: 36 }).notNull().references(() => kbGraphNodes2.node_id, { onDelete: "cascade" }),
2938
+ target_node_id: text2("target_node_id", { length: 36 }).notNull().references(() => kbGraphNodes2.node_id, { onDelete: "cascade" }),
2939
+ edge_type: text2("edge_type", {
2940
+ enum: [
2941
+ "contains",
2942
+ "references",
2943
+ "mentions",
2944
+ "implements",
2945
+ "depends_on",
2946
+ "supersedes",
2947
+ "derived_from",
2948
+ "tagged_with",
2949
+ "about",
2950
+ "parent_of",
2951
+ "related_to"
2952
+ ]
2953
+ }).notNull(),
2954
+ confidence: integer2("confidence"),
2955
+ properties: t2.json("properties"),
2956
+ created_by: text2("created_by", { length: 36 }).references(() => users2.user_id, {
2957
+ onDelete: "set null"
2958
+ }),
2959
+ created_at: t2.timestamp("created_at").notNull(),
2960
+ archived: t2.bool("archived").notNull().default(false),
2961
+ archived_at: t2.timestamp("archived_at")
2962
+ },
2963
+ (table) => ({
2964
+ sourceIdx: index2("kb_graph_edges_source_idx").on(table.source_node_id),
2965
+ targetIdx: index2("kb_graph_edges_target_idx").on(table.target_node_id),
2966
+ typeIdx: index2("kb_graph_edges_type_idx").on(table.edge_type),
2967
+ sourceTypeIdx: index2("kb_graph_edges_source_type_idx").on(
2968
+ table.source_node_id,
2969
+ table.edge_type
2970
+ ),
2971
+ targetTypeIdx: index2("kb_graph_edges_target_type_idx").on(
2972
+ table.target_node_id,
2973
+ table.edge_type
2974
+ ),
2975
+ sourceTargetTypeIdx: uniqueIndex2("kb_graph_edges_source_target_type_idx").on(table.source_node_id, table.target_node_id, table.edge_type).where(sql3`${table.archived} = false`),
2976
+ archivedIdx: index2("kb_graph_edges_archived_idx").on(table.archived)
2977
+ })
2978
+ );
2979
+ var sessionsRelations2 = relations2(sessions2, ({ one, many }) => ({
2980
+ branch: one(branches2, {
2981
+ fields: [sessions2.branch_id],
2982
+ references: [branches2.branch_id]
2983
+ }),
2984
+ schedule: one(schedules2, {
2985
+ fields: [sessions2.schedule_id],
2986
+ references: [schedules2.schedule_id]
2987
+ }),
2988
+ outboundRelationships: many(sessionRelationships2, { relationName: "relationshipSource" }),
2989
+ inboundRelationships: many(sessionRelationships2, { relationName: "relationshipTarget" })
2990
+ }));
2991
+ var sessionRelationshipsRelations2 = relations2(sessionRelationships2, ({ one }) => ({
2992
+ sourceSession: one(sessions2, {
2993
+ fields: [sessionRelationships2.source_session_id],
2994
+ references: [sessions2.session_id],
2995
+ relationName: "relationshipSource"
2996
+ }),
2997
+ targetSession: one(sessions2, {
2998
+ fields: [sessionRelationships2.target_session_id],
2999
+ references: [sessions2.session_id],
3000
+ relationName: "relationshipTarget"
3001
+ }),
3002
+ callbackSession: one(sessions2, {
3003
+ fields: [sessionRelationships2.callback_session_id],
3004
+ references: [sessions2.session_id]
3005
+ })
3006
+ }));
3007
+ var branchesRelations2 = relations2(branches2, ({ many }) => ({
3008
+ sessions: many(sessions2),
3009
+ schedules: many(schedules2)
3010
+ }));
3011
+ var schedulesRelations2 = relations2(schedules2, ({ one, many }) => ({
3012
+ branch: one(branches2, {
3013
+ fields: [schedules2.branch_id],
3014
+ references: [branches2.branch_id]
3015
+ }),
3016
+ sessions: many(sessions2)
3017
+ }));
3018
+
3019
+ // src/config/config-manager.ts
3020
+ import { readFileSync, statSync } from "fs";
3021
+ import fs from "fs/promises";
3022
+ import os from "os";
3023
+ import path from "path";
3024
+ import * as yaml from "js-yaml";
3025
+
3026
+ // src/config/analytics-defaults.ts
3027
+ function getDefaultAnalyticsConfig() {
3028
+ return {
3029
+ enabled: false,
3030
+ client: {
3031
+ app: "agor-daemon",
3032
+ version: "dev",
3033
+ debug: false
3034
+ },
3035
+ filters: {
3036
+ exclude_events: []
3037
+ },
3038
+ plugins: [
3039
+ {
3040
+ type: "stdout",
3041
+ enabled: false,
3042
+ options: {
3043
+ pretty: false
3044
+ }
3045
+ },
3046
+ {
3047
+ type: "http_batch",
3048
+ enabled: false,
3049
+ options: {
3050
+ url: null,
3051
+ flush_interval_ms: 1e3,
3052
+ max_batch_size: 50,
3053
+ timeout_ms: 3e3,
3054
+ headers: {}
3055
+ }
3056
+ },
3057
+ {
3058
+ type: "module",
3059
+ enabled: false,
3060
+ options: {
3061
+ module_path: null,
3062
+ export_name: "createAnalyticsPlugin",
3063
+ plugin_options: {}
3064
+ }
3065
+ }
3066
+ ]
3067
+ };
3068
+ }
3069
+
3070
+ // src/config/constants.ts
3071
+ var DAEMON = {
3072
+ /**
3073
+ * Default daemon port
3074
+ */
3075
+ DEFAULT_PORT: 3030,
3076
+ /**
3077
+ * Default daemon host
3078
+ */
3079
+ DEFAULT_HOST: "localhost"
3080
+ };
3081
+ var MCP_TOKEN = {
3082
+ /**
3083
+ * Default lifetime for internal MCP session tokens in milliseconds.
3084
+ * Keep short to bound the blast radius of a leaked token — there is no
3085
+ * revocation mechanism; `exp` is the only backstop.
3086
+ */
3087
+ DEFAULT_EXPIRATION_MS: 24 * 60 * 60 * 1e3
3088
+ // 24 hours
3089
+ };
3090
+
3091
+ // src/config/executor-heartbeat.ts
3092
+ var EXECUTOR_HEARTBEAT_DEFAULT_INTERVAL_MS = 1e4;
3093
+ var EXECUTOR_HEARTBEAT_MIN_STALE_AFTER_MS = 3e4;
3094
+ var EXECUTOR_HEARTBEAT_DEFAULT_CALLBACK_TIMEOUT_MS = 3e3;
3095
+ function positiveIntegerOrDefault(value, fallback) {
3096
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
3097
+ }
3098
+ function resolveExecutorHeartbeatConfig(execution) {
3099
+ const raw = execution?.executor_heartbeat;
3100
+ const intervalMs = positiveIntegerOrDefault(
3101
+ raw?.interval_ms,
3102
+ EXECUTOR_HEARTBEAT_DEFAULT_INTERVAL_MS
3103
+ );
3104
+ const staleAfterMs = positiveIntegerOrDefault(
3105
+ raw?.stale_after_ms,
3106
+ Math.max(3 * intervalMs, EXECUTOR_HEARTBEAT_MIN_STALE_AFTER_MS)
3107
+ );
3108
+ const timeoutMs = positiveIntegerOrDefault(
3109
+ raw?.callback?.timeout_ms,
3110
+ EXECUTOR_HEARTBEAT_DEFAULT_CALLBACK_TIMEOUT_MS
3111
+ );
3112
+ return {
3113
+ // Default enabled: the heartbeat is a lightweight task-row timestamp patch,
3114
+ // and callback execution remains opt-in via command_template.
3115
+ enabled: raw?.enabled ?? true,
3116
+ interval_ms: intervalMs,
3117
+ stale_after_ms: staleAfterMs,
3118
+ callback: {
3119
+ command_template: raw?.callback?.command_template ?? null,
3120
+ timeout_ms: timeoutMs
3121
+ }
3122
+ };
3123
+ }
3124
+
3125
+ // src/config/multitenancy.ts
3126
+ var DEFAULT_STATIC_TENANT_ID = "default";
3127
+ var RESERVED_AUTH_CLAIMS = /* @__PURE__ */ new Set(["aud", "exp", "iat", "iss", "jti", "nbf", "sub", "type"]);
3128
+ function detectPostgresUrl(url) {
3129
+ if (!url) return false;
3130
+ const lower = url.toLowerCase();
3131
+ return lower.startsWith("postgresql://") || lower.startsWith("postgres://") || lower.startsWith("pg://");
3132
+ }
3133
+ function resolveMultiTenancyDatabaseDialect(config = {}) {
3134
+ if (process.env.AGOR_DB_DIALECT === "postgresql" || process.env.AGOR_DB_DIALECT === "sqlite") {
3135
+ return process.env.AGOR_DB_DIALECT;
3136
+ }
3137
+ if (detectPostgresUrl(process.env.DATABASE_URL)) return "postgresql";
3138
+ if (config.database?.dialect === "postgresql" || config.database?.dialect === "sqlite") {
3139
+ return config.database.dialect;
3140
+ }
3141
+ if (detectPostgresUrl(config.database?.postgresql?.url) || config.database?.postgresql?.host) {
3142
+ return "postgresql";
3143
+ }
3144
+ return "sqlite";
3145
+ }
3146
+ function resolveMultiTenancyConfig(config) {
3147
+ const raw = config.multi_tenancy ?? {};
3148
+ const mode = raw.mode ?? "static";
3149
+ return {
3150
+ mode,
3151
+ static_tenant_id: raw.static_tenant_id?.trim() || DEFAULT_STATIC_TENANT_ID,
3152
+ ...raw.auth_claim ? { auth_claim: raw.auth_claim } : {},
3153
+ ...raw.trusted_header ? { trusted_header: raw.trusted_header } : {}
3154
+ };
3155
+ }
3156
+ function assertValidMultiTenancyConfig(config) {
3157
+ const resolved = resolveMultiTenancyConfig(config);
3158
+ if (resolved.mode !== "static" && resolved.mode !== "required_from_auth") {
3159
+ throw new Error("Config error: multi_tenancy.mode must be one of: static, required_from_auth");
3160
+ }
3161
+ if (!resolved.static_tenant_id) {
3162
+ throw new Error("Config error: multi_tenancy.static_tenant_id must not be empty");
3163
+ }
3164
+ if (resolved.auth_claim && RESERVED_AUTH_CLAIMS.has(resolved.auth_claim)) {
3165
+ throw new Error(
3166
+ `Config error: multi_tenancy.auth_claim cannot be reserved JWT claim '${resolved.auth_claim}'`
3167
+ );
3168
+ }
3169
+ if (resolved.mode === "required_from_auth") {
3170
+ if (resolveMultiTenancyDatabaseDialect(config) !== "postgresql") {
3171
+ throw new Error(
3172
+ "Config error: multi_tenancy.required_from_auth requires database.dialect: postgresql"
3173
+ );
3174
+ }
3175
+ if (!resolved.auth_claim && !resolved.trusted_header) {
3176
+ throw new Error(
3177
+ "Config error: multi_tenancy.required_from_auth requires multi_tenancy.auth_claim or multi_tenancy.trusted_header"
3178
+ );
3179
+ }
3180
+ }
3181
+ }
3182
+
3183
+ // src/config/config-manager.ts
3184
+ var NO_FILE = -1;
3185
+ var NO_FILE_KEY = { mtimeMs: NO_FILE, size: 0 };
3186
+ var cachedEntry = null;
3187
+ function cacheKeyMatches(a, b) {
3188
+ return a.mtimeMs === b.mtimeMs && a.size === b.size;
3189
+ }
3190
+ function statCacheKey(configPath) {
3191
+ try {
3192
+ const stat = statSync(configPath);
3193
+ return { mtimeMs: stat.mtimeMs, size: stat.size };
3194
+ } catch (error) {
3195
+ if (error.code === "ENOENT") {
3196
+ return NO_FILE_KEY;
3197
+ }
3198
+ return null;
3199
+ }
3200
+ }
3201
+ function readCachedConfig(configPath) {
3202
+ if (cachedEntry === null || cachedEntry.path !== configPath) {
3203
+ return null;
3204
+ }
3205
+ const currentKey = statCacheKey(configPath);
3206
+ if (currentKey === null || !cacheKeyMatches(currentKey, cachedEntry.key)) {
3207
+ return null;
3208
+ }
3209
+ return structuredClone(cachedEntry.config);
3210
+ }
3211
+ function writeCachedConfig(configPath, config, key) {
3212
+ cachedEntry = { path: configPath, config: structuredClone(config), key };
3213
+ }
3214
+ function parseAndValidateConfig(content) {
3215
+ if (content.trim() === "") {
3216
+ return {};
3217
+ }
3218
+ const parsed = yaml.load(content);
3219
+ const finalConfig = parsed || {};
3220
+ validateConfig(finalConfig);
3221
+ return finalConfig;
3222
+ }
3223
+ function getAgorHome() {
3224
+ return path.join(os.homedir(), ".agor");
3225
+ }
3226
+ function getConfigPath() {
3227
+ return path.join(getAgorHome(), "config.yaml");
3228
+ }
3229
+ function validateConfig(config) {
3230
+ const mode = config.execution?.unix_user_mode;
3231
+ if (mode === "opportunistic") {
3232
+ throw new Error(
3233
+ `Config error: 'opportunistic' unix_user_mode has been deprecated.
3234
+ Please update your config to use one of:
3235
+ - 'insulated': Filesystem isolation via Unix groups (recommended)
3236
+ - 'strict': Full process impersonation required
3237
+
3238
+ To update: agor config set execution.unix_user_mode insulated`
3239
+ );
3240
+ }
3241
+ const managedEnvExecutionMode = config.execution?.managed_envs_execution_mode;
3242
+ if (managedEnvExecutionMode !== void 0 && managedEnvExecutionMode !== "hybrid" && managedEnvExecutionMode !== "webhook-only") {
3243
+ throw new Error(
3244
+ `Config error: execution.managed_envs_execution_mode must be one of: hybrid, webhook-only`
3245
+ );
3246
+ }
3247
+ assertValidMultiTenancyConfig(config);
3248
+ validateOptionalHttpUrl(
3249
+ config.external_launch,
3250
+ "login_redirect_url",
3251
+ "external_launch.login_redirect_url"
3252
+ );
3253
+ }
3254
+ function validateOptionalHttpUrl(container, key, configPath) {
3255
+ if (!container || container[key] === void 0) return;
3256
+ const raw = container[key];
3257
+ if (typeof raw !== "string") {
3258
+ throw new Error(`Config error: ${configPath} must be an HTTP(S) URL string`);
3259
+ }
3260
+ container[key] = validateHttpUrlString(raw, configPath);
3261
+ }
3262
+ function validateHttpUrlString(url, label, options = {}) {
3263
+ const trimmed = options.stripTrailingSlash ? url.trim().replace(/\/$/, "") : url.trim();
3264
+ if (!trimmed.startsWith("http://") && !trimmed.startsWith("https://")) {
3265
+ throw new Error(`Invalid ${label}: "${url}". Must start with http:// or https://`);
3266
+ }
3267
+ let parsed;
3268
+ try {
3269
+ parsed = new URL(trimmed);
3270
+ } catch {
3271
+ throw new Error(`Invalid ${label} format: "${url}". Must be a valid HTTP(S) URL.`);
3272
+ }
3273
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
3274
+ throw new Error(`Invalid ${label}: "${url}". Must use http:// or https://`);
3275
+ }
3276
+ return trimmed;
3277
+ }
3278
+ function getDefaultConfig() {
3279
+ return {
3280
+ defaults: {
3281
+ board: "main",
3282
+ agent: "claude-code"
3283
+ },
3284
+ display: {
3285
+ tableStyle: "unicode",
3286
+ colorOutput: true
3287
+ },
3288
+ daemon: {
3289
+ port: DAEMON.DEFAULT_PORT,
3290
+ host: DAEMON.DEFAULT_HOST,
3291
+ mcpEnabled: true
3292
+ // Default: Enable built-in MCP server
3293
+ },
3294
+ ui: {
3295
+ port: 5173,
3296
+ host: "localhost"
3297
+ },
3298
+ execution: {
3299
+ session_token_expiration_ms: 864e5,
3300
+ // 24 hours
3301
+ session_token_max_uses: 1,
3302
+ // Single-use tokens
3303
+ mcp_token_expiration_ms: MCP_TOKEN.DEFAULT_EXPIRATION_MS,
3304
+ sync_unix_passwords: true,
3305
+ // Default: sync passwords to Unix
3306
+ executor_heartbeat: resolveExecutorHeartbeatConfig()
3307
+ },
3308
+ analytics: getDefaultAnalyticsConfig(),
3309
+ telemetry: {},
3310
+ multi_tenancy: {
3311
+ mode: "static",
3312
+ static_tenant_id: "default"
3313
+ }
3314
+ };
3315
+ }
3316
+ function loadConfigSync() {
3317
+ const configPath = getConfigPath();
3318
+ const cached = readCachedConfig(configPath);
3319
+ if (cached !== null) {
3320
+ return cached;
3321
+ }
3322
+ let beforeKey;
3323
+ let content;
3324
+ let afterKey;
3325
+ try {
3326
+ beforeKey = statCacheKey(configPath);
3327
+ if (beforeKey?.mtimeMs === NO_FILE) {
3328
+ const defaults = getDefaultConfig();
3329
+ writeCachedConfig(configPath, defaults, NO_FILE_KEY);
3330
+ return defaults;
3331
+ }
3332
+ content = readFileSync(configPath, "utf-8");
3333
+ afterKey = statCacheKey(configPath);
3334
+ } catch (error) {
3335
+ if (error.code === "ENOENT") {
3336
+ const defaults = getDefaultConfig();
3337
+ writeCachedConfig(configPath, defaults, NO_FILE_KEY);
3338
+ return defaults;
3339
+ }
3340
+ throw new Error(
3341
+ `Failed to load config: ${error instanceof Error ? error.message : String(error)}`
3342
+ );
3343
+ }
3344
+ let finalConfig;
3345
+ try {
3346
+ finalConfig = parseAndValidateConfig(content);
3347
+ } catch (error) {
3348
+ throw new Error(
3349
+ `Failed to load config: ${error instanceof Error ? error.message : String(error)}`
3350
+ );
3351
+ }
3352
+ if (beforeKey !== null && afterKey !== null && cacheKeyMatches(beforeKey, afterKey)) {
3353
+ writeCachedConfig(configPath, finalConfig, beforeKey);
3354
+ }
3355
+ return finalConfig;
3356
+ }
3357
+
3358
+ // src/db/schema-factory.ts
3359
+ function detectDialectFromUrl(url) {
3360
+ if (!url) return null;
3361
+ const lowerUrl = url.toLowerCase();
3362
+ if (lowerUrl.startsWith("postgresql://") || lowerUrl.startsWith("postgres://") || lowerUrl.startsWith("pg://")) {
3363
+ return "postgresql";
3364
+ }
3365
+ if (lowerUrl.startsWith("file:") || lowerUrl.startsWith("libsql://") || lowerUrl.startsWith("http://") || lowerUrl.startsWith("https://")) {
3366
+ return "sqlite";
3367
+ }
3368
+ return null;
3369
+ }
3370
+ function getDatabaseDialect() {
3371
+ const envDialect = process.env.AGOR_DB_DIALECT;
3372
+ if (envDialect === "postgresql" || envDialect === "sqlite") {
3373
+ return envDialect;
3374
+ }
3375
+ const databaseUrl = process.env.DATABASE_URL;
3376
+ if (databaseUrl) {
3377
+ const detected = detectDialectFromUrl(databaseUrl);
3378
+ if (detected) {
3379
+ return detected;
3380
+ }
3381
+ }
3382
+ try {
3383
+ const config = loadConfigSync();
3384
+ if (config.database?.dialect === "postgresql" || config.database?.dialect === "sqlite") {
3385
+ return config.database.dialect;
3386
+ }
3387
+ if (config.database?.postgresql?.url) {
3388
+ const detected = detectDialectFromUrl(config.database.postgresql.url);
3389
+ if (detected) return detected;
3390
+ }
3391
+ } catch {
3392
+ }
3393
+ return "sqlite";
3394
+ }
3395
+
3396
+ // src/db/schema.ts
3397
+ var dialect = getDatabaseDialect();
3398
+ var schema = dialect === "postgresql" ? schema_postgres_exports : schema_sqlite_exports;
3399
+ var sessions3 = schema.sessions;
3400
+ var tasks3 = schema.tasks;
3401
+ var messages3 = schema.messages;
3402
+ var boards3 = schema.boards;
3403
+ var repos3 = schema.repos;
3404
+ var branches3 = schema.branches;
3405
+ var branchOwners3 = schema.branchOwners;
3406
+ var boardOwners3 = schema.boardOwners;
3407
+ var groups3 = schema.groups;
3408
+ var groupMemberships3 = schema.groupMemberships;
3409
+ var branchGroupGrants3 = schema.branchGroupGrants;
3410
+ var boardGroupGrants3 = schema.boardGroupGrants;
3411
+ var schedules3 = schema.schedules;
3412
+ var users3 = schema.users;
3413
+ var appVariables3 = schema.appVariables;
3414
+ var mcpServers3 = schema.mcpServers;
3415
+ var cardTypes3 = schema.cardTypes;
3416
+ var cards3 = schema.cards;
3417
+ var artifacts3 = schema.artifacts;
3418
+ var artifactTrustGrants3 = schema.artifactTrustGrants;
3419
+ var boardObjects3 = schema.boardObjects;
3420
+ var sessionMcpServers3 = schema.sessionMcpServers;
3421
+ var sessionRelationships3 = schema.sessionRelationships;
3422
+ var sessionEnvSelections3 = schema.sessionEnvSelections;
3423
+ var userMcpOauthTokens3 = schema.userMcpOauthTokens;
3424
+ var boardComments3 = schema.boardComments;
3425
+ var gatewayChannels3 = schema.gatewayChannels;
3426
+ var threadSessionMap3 = schema.threadSessionMap;
3427
+ var gatewayOutboundMessages3 = schema.gatewayOutboundMessages;
3428
+ var userApiKeys3 = schema.userApiKeys;
3429
+ var serializedSessions3 = schema.serializedSessions;
3430
+ var kbNamespaces3 = schema.kbNamespaces;
3431
+ var kbNamespaceAcl3 = schema.kbNamespaceAcl;
3432
+ var kbDocuments3 = schema.kbDocuments;
3433
+ var kbDocumentVersions3 = schema.kbDocumentVersions;
3434
+ var kbDocumentUnits3 = schema.kbDocumentUnits;
3435
+ var kbEmbeddingSpaces3 = schema.kbEmbeddingSpaces;
3436
+ var kbGraphNodes3 = schema.kbGraphNodes;
3437
+ var kbGraphEdges3 = schema.kbGraphEdges;
3438
+
3439
+ // src/lib/ids.ts
3440
+ import { randomBytes as randomBytes2 } from "crypto";
3441
+ import { v7 as uuidv7 } from "uuid";
3442
+
3443
+ // src/config/env-blocklist.ts
3444
+ var BLOCKED_ENV_PATTERNS = Object.freeze([
3445
+ /^LD_/i,
3446
+ /^DYLD_/i,
3447
+ /^PYTHON(?!_AGOR_)/i
3448
+ ]);
3449
+
3450
+ // src/config/env-vars.ts
3451
+ var V05_SCOPES = ["global", "session"];
3452
+ var V05_SCOPE_SET = new Set(V05_SCOPES);
3453
+
3454
+ // src/templates/handlebars-helpers.ts
3455
+ import Handlebars from "handlebars";
3456
+
3457
+ // src/mcp/template-patterns.ts
3458
+ var USER_ENV_PLACEHOLDER_RE = /^\{\{\s*user\.env\.[A-Za-z_][A-Za-z0-9_]*\s*\}\}$/;
3459
+ function isUserEnvPlaceholder(value) {
3460
+ return USER_ENV_PLACEHOLDER_RE.test(value.trim());
3461
+ }
3462
+
3463
+ // src/mcp/template-resolver.ts
3464
+ var TEMPLATE_RESOLVABLE_MCP_AUTH_SECRET_FIELDS = [
3465
+ "token",
3466
+ "api_token",
3467
+ "api_secret",
3468
+ "oauth_client_secret"
3469
+ ];
3470
+
1
3471
  // src/tools/mcp/http-headers.ts
2
3472
  var MCP_HEADER_REDACTED_SENTINEL = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
3
3473
 
@@ -15,11 +3485,15 @@ function redactMCPAuthSecrets(auth) {
15
3485
  let changed = false;
16
3486
  const redacted = { ...auth };
17
3487
  const record = redacted;
3488
+ const templateResolvable = new Set(TEMPLATE_RESOLVABLE_MCP_AUTH_SECRET_FIELDS);
18
3489
  for (const field of MCP_AUTH_SECRET_FIELDS) {
19
- if (redacted[field] !== void 0) {
20
- record[field] = MCP_HEADER_REDACTED_SENTINEL;
21
- changed = true;
3490
+ const value = redacted[field];
3491
+ if (value === void 0) continue;
3492
+ if (templateResolvable.has(field) && typeof value === "string" && isUserEnvPlaceholder(value)) {
3493
+ continue;
22
3494
  }
3495
+ record[field] = MCP_HEADER_REDACTED_SENTINEL;
3496
+ changed = true;
23
3497
  }
24
3498
  return changed ? redacted : auth;
25
3499
  }