agor-live 0.21.2 → 0.23.1

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 (974) hide show
  1. package/dist/cli/commands/admin/add-to-branch-group.d.ts +2 -13
  2. package/dist/cli/commands/admin/add-to-branch-group.d.ts.map +1 -1
  3. package/dist/cli/commands/admin/add-to-branch-group.js +133 -33
  4. package/dist/cli/commands/admin/create-branch-group.d.ts +2 -13
  5. package/dist/cli/commands/admin/create-branch-group.d.ts.map +1 -1
  6. package/dist/cli/commands/admin/create-branch-group.js +132 -38
  7. package/dist/cli/commands/admin/create-symlink.d.ts +2 -14
  8. package/dist/cli/commands/admin/create-symlink.d.ts.map +1 -1
  9. package/dist/cli/commands/admin/create-symlink.js +138 -61
  10. package/dist/cli/commands/admin/delete-branch-group.d.ts +2 -13
  11. package/dist/cli/commands/admin/delete-branch-group.d.ts.map +1 -1
  12. package/dist/cli/commands/admin/delete-branch-group.js +132 -28
  13. package/dist/cli/commands/admin/delete-user.d.ts +2 -13
  14. package/dist/cli/commands/admin/delete-user.d.ts.map +1 -1
  15. package/dist/cli/commands/admin/delete-user.js +132 -38
  16. package/dist/cli/commands/admin/ensure-user.d.ts +2 -14
  17. package/dist/cli/commands/admin/ensure-user.d.ts.map +1 -1
  18. package/dist/cli/commands/admin/ensure-user.js +131 -46
  19. package/dist/cli/commands/admin/remove-from-branch-group.d.ts +2 -13
  20. package/dist/cli/commands/admin/remove-from-branch-group.d.ts.map +1 -1
  21. package/dist/cli/commands/admin/remove-from-branch-group.js +133 -33
  22. package/dist/cli/commands/admin/remove-symlink.d.ts +2 -14
  23. package/dist/cli/commands/admin/remove-symlink.d.ts.map +1 -1
  24. package/dist/cli/commands/admin/remove-symlink.js +136 -49
  25. package/dist/cli/commands/admin/scrub-git-remotes.d.ts +2 -2
  26. package/dist/cli/commands/admin/scrub-git-remotes.d.ts.map +1 -1
  27. package/dist/cli/commands/admin/scrub-git-remotes.js +128 -86
  28. package/dist/cli/commands/admin/sync-user-symlinks.d.ts +2 -14
  29. package/dist/cli/commands/admin/sync-user-symlinks.d.ts.map +1 -1
  30. package/dist/cli/commands/admin/sync-user-symlinks.js +132 -43
  31. package/dist/cli/commands/auth/whoami.d.ts.map +1 -1
  32. package/dist/cli/commands/auth/whoami.js +2 -1
  33. package/dist/cli/commands/branch/env/request.test.d.ts +2 -0
  34. package/dist/cli/commands/branch/env/request.test.d.ts.map +1 -0
  35. package/dist/cli/commands/branch/env/request.test.js +17723 -0
  36. package/dist/cli/commands/branch/env/restart.d.ts.map +1 -1
  37. package/dist/cli/commands/branch/env/restart.js +8 -2
  38. package/dist/cli/commands/branch/env/start.d.ts.map +1 -1
  39. package/dist/cli/commands/branch/env/start.js +8 -2
  40. package/dist/cli/commands/branch/env/stop.d.ts.map +1 -1
  41. package/dist/cli/commands/branch/env/stop.js +8 -2
  42. package/dist/cli/commands/daemon/status.d.ts.map +1 -1
  43. package/dist/cli/commands/daemon/status.js +2 -1
  44. package/dist/cli/commands/init.d.ts +6 -0
  45. package/dist/cli/commands/init.d.ts.map +1 -1
  46. package/dist/cli/commands/init.js +140 -2
  47. package/dist/cli/commands/local/add-to-branch-group.d.ts +13 -0
  48. package/dist/cli/commands/local/add-to-branch-group.d.ts.map +1 -0
  49. package/dist/cli/commands/local/add-to-branch-group.js +37 -0
  50. package/dist/cli/commands/local/create-branch-group.d.ts +12 -0
  51. package/dist/cli/commands/local/create-branch-group.d.ts.map +1 -0
  52. package/dist/cli/commands/local/create-branch-group.js +35 -0
  53. package/dist/cli/commands/local/create-symlink.d.ts +14 -0
  54. package/dist/cli/commands/local/create-symlink.d.ts.map +1 -0
  55. package/dist/cli/commands/local/create-symlink.js +45 -0
  56. package/dist/cli/commands/{daemon → local/daemon}/sync.d.ts +1 -1
  57. package/dist/cli/commands/local/daemon/sync.d.ts.map +1 -0
  58. package/dist/cli/commands/{daemon → local/daemon}/sync.js +7 -6
  59. package/dist/cli/commands/local/delete-branch-group.d.ts +12 -0
  60. package/dist/cli/commands/local/delete-branch-group.d.ts.map +1 -0
  61. package/dist/cli/commands/local/delete-branch-group.js +35 -0
  62. package/dist/cli/commands/local/delete-user.d.ts +12 -0
  63. package/dist/cli/commands/local/delete-user.d.ts.map +1 -0
  64. package/dist/cli/commands/local/delete-user.js +36 -0
  65. package/dist/cli/commands/local/ensure-user.d.ts +12 -0
  66. package/dist/cli/commands/local/ensure-user.d.ts.map +1 -0
  67. package/dist/cli/commands/local/ensure-user.js +41 -0
  68. package/dist/cli/commands/local/remove-from-branch-group.d.ts +13 -0
  69. package/dist/cli/commands/local/remove-from-branch-group.d.ts.map +1 -0
  70. package/dist/cli/commands/local/remove-from-branch-group.js +37 -0
  71. package/dist/cli/commands/local/remove-symlink.d.ts +13 -0
  72. package/dist/cli/commands/local/remove-symlink.d.ts.map +1 -0
  73. package/dist/cli/commands/local/remove-symlink.js +39 -0
  74. package/dist/cli/commands/local/scrub-git-remotes.d.ts +9 -0
  75. package/dist/cli/commands/local/scrub-git-remotes.d.ts.map +1 -0
  76. package/dist/cli/commands/local/scrub-git-remotes.js +23 -0
  77. package/dist/cli/commands/{admin → local}/sync-unix.d.ts.map +1 -1
  78. package/dist/cli/commands/{admin → local}/sync-unix.js +3 -3
  79. package/dist/cli/commands/local/sync-user-symlinks.d.ts +12 -0
  80. package/dist/cli/commands/local/sync-user-symlinks.d.ts.map +1 -0
  81. package/dist/cli/commands/local/sync-user-symlinks.js +37 -0
  82. package/dist/cli/commands/telemetry/index.d.ts +7 -0
  83. package/dist/cli/commands/telemetry/index.d.ts.map +1 -0
  84. package/dist/cli/commands/telemetry/index.js +40 -0
  85. package/dist/cli/commands/telemetry/off.d.ts +6 -0
  86. package/dist/cli/commands/telemetry/off.d.ts.map +1 -0
  87. package/dist/cli/commands/telemetry/off.js +35 -0
  88. package/dist/cli/commands/telemetry/on.d.ts +6 -0
  89. package/dist/cli/commands/telemetry/on.d.ts.map +1 -0
  90. package/dist/cli/commands/telemetry/on.js +37 -0
  91. package/dist/cli/commands/telemetry/test.d.ts +6 -0
  92. package/dist/cli/commands/telemetry/test.d.ts.map +1 -0
  93. package/dist/cli/commands/telemetry/test.js +56 -0
  94. package/dist/cli/commands/user/create-admin.d.ts.map +1 -1
  95. package/dist/cli/commands/user/create-admin.js +81 -72
  96. package/dist/cli/commands/user/list.d.ts.map +1 -1
  97. package/dist/cli/commands/user/list.js +1 -0
  98. package/dist/cli/commands/whoami.js +2 -1
  99. package/dist/cli/lib/branch-environment-action.d.ts +21 -0
  100. package/dist/cli/lib/branch-environment-action.d.ts.map +1 -0
  101. package/dist/cli/lib/branch-environment-action.js +8 -0
  102. package/dist/core/api/index.cjs +12 -3
  103. package/dist/core/api/index.d.ts +16 -2
  104. package/dist/core/api/index.d.ts.map +1 -1
  105. package/dist/core/api/index.js +12 -3
  106. package/dist/core/claude/index.cjs +634 -81
  107. package/dist/core/claude/index.js +631 -80
  108. package/dist/core/claude-cli/index.cjs +11 -0
  109. package/dist/core/claude-cli/index.js +11 -0
  110. package/dist/core/claude-cli/pricing.d.ts.map +1 -1
  111. package/dist/core/client/index.cjs +78 -10
  112. package/dist/core/client/index.js +69 -10
  113. package/dist/core/config/browser.cjs +5 -7
  114. package/dist/core/config/browser.js +5 -7
  115. package/dist/core/config/config-manager.d.ts +33 -13
  116. package/dist/core/config/config-manager.d.ts.map +1 -1
  117. package/dist/core/config/constants.d.ts +1 -1
  118. package/dist/core/config/index.cjs +4277 -4391
  119. package/dist/core/config/index.d.ts +1 -0
  120. package/dist/core/config/index.d.ts.map +1 -1
  121. package/dist/core/config/index.js +4299 -4433
  122. package/dist/core/config/key-resolver.d.ts.map +1 -1
  123. package/dist/core/config/multitenancy.d.ts +33 -0
  124. package/dist/core/config/multitenancy.d.ts.map +1 -0
  125. package/dist/core/config/security-resolver.d.ts +1 -0
  126. package/dist/core/config/security-resolver.d.ts.map +1 -1
  127. package/dist/core/config/types.d.ts +75 -4
  128. package/dist/core/config/types.d.ts.map +1 -1
  129. package/dist/core/db/client.d.ts +34 -2
  130. package/dist/core/db/client.d.ts.map +1 -1
  131. package/dist/core/db/database-wrapper.d.ts.map +1 -1
  132. package/dist/core/db/first-run-bootstrap.d.ts.map +1 -1
  133. package/dist/core/db/index.cjs +2765 -1018
  134. package/dist/core/db/index.d.ts +2 -1
  135. package/dist/core/db/index.d.ts.map +1 -1
  136. package/dist/core/db/index.js +2612 -895
  137. package/dist/core/db/migrate.d.ts.map +1 -1
  138. package/dist/core/db/repositories/artifacts.d.ts +27 -2
  139. package/dist/core/db/repositories/artifacts.d.ts.map +1 -1
  140. package/dist/core/db/repositories/base.d.ts +18 -0
  141. package/dist/core/db/repositories/base.d.ts.map +1 -1
  142. package/dist/core/db/repositories/board-comments.d.ts +17 -1
  143. package/dist/core/db/repositories/board-comments.d.ts.map +1 -1
  144. package/dist/core/db/repositories/board-objects.d.ts.map +1 -1
  145. package/dist/core/db/repositories/boards.d.ts +28 -4
  146. package/dist/core/db/repositories/boards.d.ts.map +1 -1
  147. package/dist/core/db/repositories/branch-access.d.ts +32 -0
  148. package/dist/core/db/repositories/branch-access.d.ts.map +1 -1
  149. package/dist/core/db/repositories/branches.d.ts +54 -2
  150. package/dist/core/db/repositories/branches.d.ts.map +1 -1
  151. package/dist/core/db/repositories/cards.d.ts +15 -1
  152. package/dist/core/db/repositories/cards.d.ts.map +1 -1
  153. package/dist/core/db/repositories/gateway-channels.d.ts.map +1 -1
  154. package/dist/core/db/repositories/gateway-outbound-messages.d.ts +19 -0
  155. package/dist/core/db/repositories/gateway-outbound-messages.d.ts.map +1 -0
  156. package/dist/core/db/repositories/index.d.ts +3 -0
  157. package/dist/core/db/repositories/index.d.ts.map +1 -1
  158. package/dist/core/db/repositories/messages.d.ts +9 -2
  159. package/dist/core/db/repositories/messages.d.ts.map +1 -1
  160. package/dist/core/db/repositories/repos.d.ts.map +1 -1
  161. package/dist/core/db/repositories/schedules.d.ts +12 -1
  162. package/dist/core/db/repositories/schedules.d.ts.map +1 -1
  163. package/dist/core/db/repositories/session-relationships.d.ts +30 -0
  164. package/dist/core/db/repositories/session-relationships.d.ts.map +1 -0
  165. package/dist/core/db/repositories/sessions.d.ts +49 -5
  166. package/dist/core/db/repositories/sessions.d.ts.map +1 -1
  167. package/dist/core/db/repositories/tasks.d.ts +7 -2
  168. package/dist/core/db/repositories/tasks.d.ts.map +1 -1
  169. package/dist/core/db/repositories/user-api-keys.d.ts +10 -1
  170. package/dist/core/db/repositories/user-api-keys.d.ts.map +1 -1
  171. package/dist/core/db/repositories/users.d.ts +18 -7
  172. package/dist/core/db/repositories/users.d.ts.map +1 -1
  173. package/dist/core/db/schema.d.ts +2605 -766
  174. package/dist/core/db/schema.d.ts.map +1 -1
  175. package/dist/core/db/schema.postgres.d.ts +1318 -49
  176. package/dist/core/db/schema.postgres.d.ts.map +1 -1
  177. package/dist/core/db/schema.sqlite.d.ts +667 -45
  178. package/dist/core/db/schema.sqlite.d.ts.map +1 -1
  179. package/dist/core/db/tenant-context.d.ts +26 -0
  180. package/dist/core/db/tenant-context.d.ts.map +1 -0
  181. package/dist/core/db/tenant-scope.d.ts +31 -0
  182. package/dist/core/db/tenant-scope.d.ts.map +1 -0
  183. package/dist/core/db/user-utils.d.ts +2 -2
  184. package/dist/core/db/user-utils.d.ts.map +1 -1
  185. package/dist/core/drizzle/postgres/0050_artifact_source_session.sql +3 -0
  186. package/dist/core/drizzle/postgres/0051_session_relationships.sql +26 -0
  187. package/dist/core/drizzle/postgres/0052_gateway_outbound_messages.sql +45 -0
  188. package/dist/core/drizzle/postgres/0053_user_token_invalidation.sql +1 -0
  189. package/dist/core/drizzle/postgres/0054_app_level_multitenancy.sql +219 -0
  190. package/dist/core/drizzle/postgres/0055_app_level_multitenancy_rls.sql +411 -0
  191. package/dist/core/drizzle/postgres/0056_composite_indexes.sql +15 -0
  192. package/dist/core/drizzle/postgres/0057_message_timestamp_indexes.sql +3 -0
  193. package/dist/core/drizzle/postgres/meta/_journal.json +56 -0
  194. package/dist/core/drizzle/sqlite/0059_artifact_source_session.sql +2 -0
  195. package/dist/core/drizzle/sqlite/0060_session_relationships.sql +23 -0
  196. package/dist/core/drizzle/sqlite/0061_gateway_outbound_messages.sql +38 -0
  197. package/dist/core/drizzle/sqlite/0062_user_token_invalidation.sql +1 -0
  198. package/dist/core/drizzle/sqlite/0063_composite_indexes.sql +10 -0
  199. package/dist/core/drizzle/sqlite/0064_message_timestamp_indexes.sql +2 -0
  200. package/dist/core/drizzle/sqlite/meta/_journal.json +42 -0
  201. package/dist/core/environment/render-snapshot.cjs +1 -4
  202. package/dist/core/environment/render-snapshot.js +1 -4
  203. package/dist/core/environment/webhook.cjs +1 -4
  204. package/dist/core/environment/webhook.js +1 -4
  205. package/dist/core/gateway/connector-registry.d.ts.map +1 -1
  206. package/dist/core/gateway/connector.d.ts +32 -1
  207. package/dist/core/gateway/connector.d.ts.map +1 -1
  208. package/dist/core/gateway/connectors/slack-manifest.cjs +108 -0
  209. package/dist/core/gateway/connectors/slack-manifest.d.ts +85 -0
  210. package/dist/core/gateway/connectors/slack-manifest.d.ts.map +1 -0
  211. package/dist/core/gateway/connectors/slack-manifest.js +81 -0
  212. package/dist/core/gateway/connectors/slack.d.ts +136 -7
  213. package/dist/core/gateway/connectors/slack.d.ts.map +1 -1
  214. package/dist/core/gateway/connectors/teams.d.ts +107 -0
  215. package/dist/core/gateway/connectors/teams.d.ts.map +1 -0
  216. package/dist/core/gateway/context.d.ts.map +1 -1
  217. package/dist/core/gateway/index.cjs +1044 -78
  218. package/dist/core/gateway/index.d.ts +6 -2
  219. package/dist/core/gateway/index.d.ts.map +1 -1
  220. package/dist/core/gateway/index.js +1031 -77
  221. package/dist/core/gateway/system-message.d.ts +21 -0
  222. package/dist/core/gateway/system-message.d.ts.map +1 -1
  223. package/dist/core/git/exec.cjs +24 -0
  224. package/dist/core/git/exec.d.ts +6 -4
  225. package/dist/core/git/exec.d.ts.map +1 -1
  226. package/dist/core/git/exec.js +2 -0
  227. package/dist/core/git/index.cjs +3 -1363
  228. package/dist/core/git/index.d.ts +4 -614
  229. package/dist/core/git/index.d.ts.map +1 -1
  230. package/dist/core/git/index.js +1 -1304
  231. package/dist/core/git/pure.cjs +24 -0
  232. package/dist/core/git/pure.d.ts +2 -27
  233. package/dist/core/git/pure.d.ts.map +1 -1
  234. package/dist/core/git/pure.js +2 -0
  235. package/dist/core/index.cjs +11268 -10246
  236. package/dist/core/index.d.ts +2 -0
  237. package/dist/core/index.d.ts.map +1 -1
  238. package/dist/core/index.js +11703 -10179
  239. package/dist/core/lib/feathers-validation.cjs +6 -1
  240. package/dist/core/lib/feathers-validation.d.ts +1 -0
  241. package/dist/core/lib/feathers-validation.d.ts.map +1 -1
  242. package/dist/core/lib/feathers-validation.js +6 -1
  243. package/dist/core/local-actions/git-remotes.d.ts +7 -0
  244. package/dist/core/local-actions/git-remotes.d.ts.map +1 -0
  245. package/dist/core/local-actions/index.cjs +7941 -0
  246. package/dist/core/local-actions/index.d.ts +6 -0
  247. package/dist/core/local-actions/index.d.ts.map +1 -0
  248. package/dist/core/local-actions/index.js +7943 -0
  249. package/dist/core/local-actions/symlinks.d.ts +20 -0
  250. package/dist/core/local-actions/symlinks.d.ts.map +1 -0
  251. package/dist/core/local-actions/types.d.ts +14 -0
  252. package/dist/core/local-actions/types.d.ts.map +1 -0
  253. package/dist/core/local-actions/unix-groups.d.ts +16 -0
  254. package/dist/core/local-actions/unix-groups.d.ts.map +1 -0
  255. package/dist/core/local-actions/unix-users.d.ts +12 -0
  256. package/dist/core/local-actions/unix-users.d.ts.map +1 -0
  257. package/dist/core/mcp/index.cjs +498 -34
  258. package/dist/core/mcp/index.js +497 -33
  259. package/dist/core/mcp/template-resolver.d.ts.map +1 -1
  260. package/dist/core/models/browser.cjs +148 -25
  261. package/dist/core/models/browser.js +144 -25
  262. package/dist/core/models/claude.d.ts +2 -2
  263. package/dist/core/models/claude.d.ts.map +1 -1
  264. package/dist/core/models/codex.d.ts +205 -21
  265. package/dist/core/models/codex.d.ts.map +1 -1
  266. package/dist/core/models/index.cjs +148 -25
  267. package/dist/core/models/index.js +144 -25
  268. package/dist/core/package.json +24 -0
  269. package/dist/core/seed/demo-fixtures.d.ts +87 -0
  270. package/dist/core/seed/demo-fixtures.d.ts.map +1 -0
  271. package/dist/core/seed/dev-fixtures.d.ts.map +1 -1
  272. package/dist/core/seed/index.cjs +8785 -5563
  273. package/dist/core/seed/index.d.ts +1 -0
  274. package/dist/core/seed/index.d.ts.map +1 -1
  275. package/dist/core/seed/index.js +8787 -5570
  276. package/dist/core/sessions/index.cjs +129 -24
  277. package/dist/core/sessions/index.js +129 -24
  278. package/dist/core/telemetry/index.cjs +361 -0
  279. package/dist/core/telemetry/index.d.ts +5 -0
  280. package/dist/core/telemetry/index.d.ts.map +1 -0
  281. package/dist/core/telemetry/index.js +315 -0
  282. package/dist/core/telemetry/logger.d.ts +44 -0
  283. package/dist/core/telemetry/logger.d.ts.map +1 -0
  284. package/dist/core/telemetry/model-normalization.d.ts +3 -0
  285. package/dist/core/telemetry/model-normalization.d.ts.map +1 -0
  286. package/dist/core/telemetry/types.d.ts +47 -0
  287. package/dist/core/telemetry/types.d.ts.map +1 -0
  288. package/dist/core/telemetry/version.d.ts +9 -0
  289. package/dist/core/telemetry/version.d.ts.map +1 -0
  290. package/dist/core/templates/agor-system-prompt.md +22 -53
  291. package/dist/core/templates/session-context.cjs +2 -73
  292. package/dist/core/templates/session-context.d.ts +9 -53
  293. package/dist/core/templates/session-context.d.ts.map +1 -1
  294. package/dist/core/templates/session-context.js +2 -72
  295. package/dist/core/tools/mcp/jwt-auth.cjs +2 -20
  296. package/dist/core/tools/mcp/jwt-auth.d.ts.map +1 -1
  297. package/dist/core/tools/mcp/jwt-auth.js +2 -20
  298. package/dist/core/tools/mcp/oauth-mcp-transport.cjs +2 -15
  299. package/dist/core/tools/mcp/oauth-mcp-transport.d.ts.map +1 -1
  300. package/dist/core/tools/mcp/oauth-mcp-transport.js +2 -15
  301. package/dist/core/tools/mcp/oauth-refresh.cjs +684 -106
  302. package/dist/core/tools/mcp/oauth-refresh.js +682 -107
  303. package/dist/core/types/artifact.d.ts +5 -1
  304. package/dist/core/types/artifact.d.ts.map +1 -1
  305. package/dist/core/types/board.d.ts +2 -0
  306. package/dist/core/types/board.d.ts.map +1 -1
  307. package/dist/core/types/branch.d.ts +27 -0
  308. package/dist/core/types/branch.d.ts.map +1 -1
  309. package/dist/core/types/config-services.d.ts.map +1 -1
  310. package/dist/core/types/feathers.d.ts +6 -0
  311. package/dist/core/types/feathers.d.ts.map +1 -1
  312. package/dist/core/types/gateway.d.ts +77 -2
  313. package/dist/core/types/gateway.d.ts.map +1 -1
  314. package/dist/core/types/id.d.ts +1 -0
  315. package/dist/core/types/id.d.ts.map +1 -1
  316. package/dist/core/types/index.cjs +61 -0
  317. package/dist/core/types/index.d.ts +1 -0
  318. package/dist/core/types/index.d.ts.map +1 -1
  319. package/dist/core/types/index.js +52 -0
  320. package/dist/core/types/schedule.d.ts +4 -3
  321. package/dist/core/types/schedule.d.ts.map +1 -1
  322. package/dist/core/types/session.d.ts +72 -2
  323. package/dist/core/types/session.d.ts.map +1 -1
  324. package/dist/core/types/task.d.ts +9 -0
  325. package/dist/core/types/task.d.ts.map +1 -1
  326. package/dist/core/types/tenant.d.ts +15 -0
  327. package/dist/core/types/tenant.d.ts.map +1 -0
  328. package/dist/core/types/user.d.ts +61 -0
  329. package/dist/core/types/user.d.ts.map +1 -1
  330. package/dist/core/unix/index.cjs +1367 -669
  331. package/dist/core/unix/index.js +1330 -634
  332. package/dist/core/unix/unix-integration-service.d.ts +10 -7
  333. package/dist/core/unix/unix-integration-service.d.ts.map +1 -1
  334. package/dist/core/utils/emoji-shortcodes.d.ts +13 -0
  335. package/dist/core/utils/emoji-shortcodes.d.ts.map +1 -0
  336. package/dist/core/utils/permission-mode-mapper.cjs +19 -0
  337. package/dist/core/utils/permission-mode-mapper.js +19 -0
  338. package/dist/core/yaml/index.cjs +8 -8
  339. package/dist/core/yaml/index.d.ts +1 -1
  340. package/dist/core/yaml/index.d.ts.map +1 -1
  341. package/dist/core/yaml/index.js +7 -7
  342. package/dist/daemon/adapters/drizzle.d.ts +26 -4
  343. package/dist/daemon/adapters/drizzle.d.ts.map +1 -1
  344. package/dist/daemon/adapters/drizzle.js +68 -7
  345. package/dist/daemon/auth/api-key-strategy.js +1 -1
  346. package/dist/daemon/auth/executor-runtime-scope.d.ts.map +1 -1
  347. package/dist/daemon/auth/executor-runtime-scope.js +19 -5
  348. package/dist/daemon/auth/launch-auth.d.ts +5 -4
  349. package/dist/daemon/auth/launch-auth.d.ts.map +1 -1
  350. package/dist/daemon/auth/launch-auth.js +123 -39
  351. package/dist/daemon/auth/refresh-token-service.d.ts +22 -0
  352. package/dist/daemon/auth/refresh-token-service.d.ts.map +1 -0
  353. package/dist/daemon/auth/refresh-token-service.js +133 -0
  354. package/dist/daemon/auth/runtime-tokens.d.ts +3 -1
  355. package/dist/daemon/auth/runtime-tokens.d.ts.map +1 -1
  356. package/dist/daemon/auth/runtime-tokens.js +17 -4
  357. package/dist/daemon/auth/service-jwt-strategy.d.ts +2 -1
  358. package/dist/daemon/auth/service-jwt-strategy.d.ts.map +1 -1
  359. package/dist/daemon/auth/service-jwt-strategy.js +127 -1
  360. package/dist/daemon/auth/token-invalidation.d.ts +11 -0
  361. package/dist/daemon/auth/token-invalidation.d.ts.map +1 -0
  362. package/dist/daemon/auth/token-invalidation.js +38 -0
  363. package/dist/daemon/auth/user-redaction.d.ts +12 -0
  364. package/dist/daemon/auth/user-redaction.d.ts.map +1 -0
  365. package/dist/daemon/auth/user-redaction.js +13 -0
  366. package/dist/daemon/declarations.d.ts +8 -1
  367. package/dist/daemon/declarations.d.ts.map +1 -1
  368. package/dist/daemon/hooks/gateway-route.d.ts.map +1 -1
  369. package/dist/daemon/hooks/gateway-route.js +69 -7
  370. package/dist/daemon/index.d.ts.map +1 -1
  371. package/dist/daemon/index.js +10429 -4408
  372. package/dist/daemon/knowledge/pgvector.d.ts +3 -3
  373. package/dist/daemon/knowledge/pgvector.d.ts.map +1 -1
  374. package/dist/daemon/knowledge/pgvector.js +24 -0
  375. package/dist/daemon/knowledge/units.d.ts +2 -2
  376. package/dist/daemon/knowledge/units.d.ts.map +1 -1
  377. package/dist/daemon/main.js +10429 -4408
  378. package/dist/daemon/mcp/server.d.ts +3 -3
  379. package/dist/daemon/mcp/server.d.ts.map +1 -1
  380. package/dist/daemon/mcp/server.js +1621 -87
  381. package/dist/daemon/mcp/tokens.d.ts +2 -2
  382. package/dist/daemon/mcp/tokens.d.ts.map +1 -1
  383. package/dist/daemon/mcp/tokens.js +5 -1
  384. package/dist/daemon/mcp/tool-registry.d.ts.map +1 -1
  385. package/dist/daemon/mcp/tool-registry.js +1 -0
  386. package/dist/daemon/mcp/tools/analytics.d.ts.map +1 -1
  387. package/dist/daemon/mcp/tools/analytics.js +553 -29
  388. package/dist/daemon/mcp/tools/artifacts.d.ts.map +1 -1
  389. package/dist/daemon/mcp/tools/artifacts.js +516 -25
  390. package/dist/daemon/mcp/tools/boards.d.ts.map +1 -1
  391. package/dist/daemon/mcp/tools/boards.js +522 -26
  392. package/dist/daemon/mcp/tools/branches.d.ts.map +1 -1
  393. package/dist/daemon/mcp/tools/branches.js +579 -55
  394. package/dist/daemon/mcp/tools/card-types.js +513 -23
  395. package/dist/daemon/mcp/tools/cards.js +513 -23
  396. package/dist/daemon/mcp/tools/environment.d.ts.map +1 -1
  397. package/dist/daemon/mcp/tools/environment.js +534 -28
  398. package/dist/daemon/mcp/tools/gateway-channels.d.ts +4 -0
  399. package/dist/daemon/mcp/tools/gateway-channels.d.ts.map +1 -0
  400. package/dist/daemon/mcp/tools/gateway-channels.js +16035 -0
  401. package/dist/daemon/mcp/tools/knowledge.js +513 -23
  402. package/dist/daemon/mcp/tools/mcp-servers.d.ts.map +1 -1
  403. package/dist/daemon/mcp/tools/mcp-servers.js +848 -23
  404. package/dist/daemon/mcp/tools/messages.d.ts.map +1 -1
  405. package/dist/daemon/mcp/tools/messages.js +573 -37
  406. package/dist/daemon/mcp/tools/proxies.js +523 -25
  407. package/dist/daemon/mcp/tools/repos.js +513 -23
  408. package/dist/daemon/mcp/tools/schedules.d.ts.map +1 -1
  409. package/dist/daemon/mcp/tools/schedules.js +516 -24
  410. package/dist/daemon/mcp/tools/search.js +513 -23
  411. package/dist/daemon/mcp/tools/sessions.d.ts.map +1 -1
  412. package/dist/daemon/mcp/tools/sessions.js +660 -33
  413. package/dist/daemon/mcp/tools/tasks.js +513 -23
  414. package/dist/daemon/mcp/tools/users.d.ts.map +1 -1
  415. package/dist/daemon/mcp/tools/users.js +532 -28
  416. package/dist/daemon/mcp/tools/widgets.d.ts.map +1 -1
  417. package/dist/daemon/mcp/tools/widgets.js +542 -25
  418. package/dist/daemon/register-hooks.d.ts +8 -3
  419. package/dist/daemon/register-hooks.d.ts.map +1 -1
  420. package/dist/daemon/register-hooks.js +1146 -609
  421. package/dist/daemon/register-routes.d.ts +3 -2
  422. package/dist/daemon/register-routes.d.ts.map +1 -1
  423. package/dist/daemon/register-routes.js +2926 -829
  424. package/dist/daemon/register-services.d.ts +2 -2
  425. package/dist/daemon/register-services.d.ts.map +1 -1
  426. package/dist/daemon/register-services.js +4209 -1140
  427. package/dist/daemon/services/artifacts.d.ts +43 -6
  428. package/dist/daemon/services/artifacts.d.ts.map +1 -1
  429. package/dist/daemon/services/artifacts.js +134 -9
  430. package/dist/daemon/services/assistant-knowledge.d.ts +2 -2
  431. package/dist/daemon/services/assistant-knowledge.d.ts.map +1 -1
  432. package/dist/daemon/services/board-comments.d.ts +8 -5
  433. package/dist/daemon/services/board-comments.d.ts.map +1 -1
  434. package/dist/daemon/services/board-comments.js +78 -13
  435. package/dist/daemon/services/board-objects.d.ts +8 -5
  436. package/dist/daemon/services/board-objects.d.ts.map +1 -1
  437. package/dist/daemon/services/board-objects.js +14 -4
  438. package/dist/daemon/services/boards.d.ts +34 -5
  439. package/dist/daemon/services/boards.d.ts.map +1 -1
  440. package/dist/daemon/services/boards.js +116 -8
  441. package/dist/daemon/services/branch-owners.d.ts +3 -1
  442. package/dist/daemon/services/branch-owners.d.ts.map +1 -1
  443. package/dist/daemon/services/branch-owners.js +31 -4
  444. package/dist/daemon/services/branches.d.ts +39 -6
  445. package/dist/daemon/services/branches.d.ts.map +1 -1
  446. package/dist/daemon/services/branches.js +703 -210
  447. package/dist/daemon/services/card-types.d.ts +3 -3
  448. package/dist/daemon/services/card-types.d.ts.map +1 -1
  449. package/dist/daemon/services/card-types.js +68 -7
  450. package/dist/daemon/services/cards.d.ts +19 -4
  451. package/dist/daemon/services/cards.d.ts.map +1 -1
  452. package/dist/daemon/services/cards.js +92 -8
  453. package/dist/daemon/services/check-auth.d.ts +2 -2
  454. package/dist/daemon/services/check-auth.d.ts.map +1 -1
  455. package/dist/daemon/services/claude-cli-integration.d.ts +4 -1
  456. package/dist/daemon/services/claude-cli-integration.d.ts.map +1 -1
  457. package/dist/daemon/services/claude-cli-integration.js +117 -65
  458. package/dist/daemon/services/claude-models.d.ts +3 -3
  459. package/dist/daemon/services/claude-models.d.ts.map +1 -1
  460. package/dist/daemon/services/claude-models.js +1048 -397
  461. package/dist/daemon/services/config.d.ts +12 -4
  462. package/dist/daemon/services/config.d.ts.map +1 -1
  463. package/dist/daemon/services/config.js +39 -3
  464. package/dist/daemon/services/copilot-models.d.ts +3 -3
  465. package/dist/daemon/services/copilot-models.d.ts.map +1 -1
  466. package/dist/daemon/services/cursor-models.d.ts +3 -3
  467. package/dist/daemon/services/cursor-models.d.ts.map +1 -1
  468. package/dist/daemon/services/files.d.ts +3 -3
  469. package/dist/daemon/services/files.d.ts.map +1 -1
  470. package/dist/daemon/services/files.js +24 -5
  471. package/dist/daemon/services/gateway-channels-test.d.ts +24 -0
  472. package/dist/daemon/services/gateway-channels-test.d.ts.map +1 -0
  473. package/dist/daemon/services/gateway-channels-test.js +66 -0
  474. package/dist/daemon/services/gateway-channels.d.ts +3 -3
  475. package/dist/daemon/services/gateway-channels.d.ts.map +1 -1
  476. package/dist/daemon/services/gateway-channels.js +68 -7
  477. package/dist/daemon/services/gateway.d.ts +106 -5
  478. package/dist/daemon/services/gateway.d.ts.map +1 -1
  479. package/dist/daemon/services/gateway.js +1184 -95
  480. package/dist/daemon/services/github-app-setup.d.ts +3 -3
  481. package/dist/daemon/services/github-app-setup.d.ts.map +1 -1
  482. package/dist/daemon/services/groups.d.ts +7 -5
  483. package/dist/daemon/services/groups.d.ts.map +1 -1
  484. package/dist/daemon/services/groups.js +56 -0
  485. package/dist/daemon/services/health-monitor.d.ts +34 -2
  486. package/dist/daemon/services/health-monitor.d.ts.map +1 -1
  487. package/dist/daemon/services/health-monitor.js +145 -23
  488. package/dist/daemon/services/knowledge-document-edits.d.ts +3 -3
  489. package/dist/daemon/services/knowledge-document-edits.d.ts.map +1 -1
  490. package/dist/daemon/services/knowledge-documents.d.ts +3 -3
  491. package/dist/daemon/services/knowledge-documents.d.ts.map +1 -1
  492. package/dist/daemon/services/knowledge-documents.js +92 -7
  493. package/dist/daemon/services/knowledge-embedding-indexer.d.ts +7 -2
  494. package/dist/daemon/services/knowledge-embedding-indexer.d.ts.map +1 -1
  495. package/dist/daemon/services/knowledge-embedding-indexer.js +37 -3
  496. package/dist/daemon/services/knowledge-graph.d.ts +3 -3
  497. package/dist/daemon/services/knowledge-graph.d.ts.map +1 -1
  498. package/dist/daemon/services/knowledge-indexing.d.ts +3 -3
  499. package/dist/daemon/services/knowledge-indexing.d.ts.map +1 -1
  500. package/dist/daemon/services/knowledge-namespaces.d.ts +3 -3
  501. package/dist/daemon/services/knowledge-namespaces.d.ts.map +1 -1
  502. package/dist/daemon/services/knowledge-namespaces.js +72 -8
  503. package/dist/daemon/services/knowledge-reindex.d.ts +3 -3
  504. package/dist/daemon/services/knowledge-reindex.d.ts.map +1 -1
  505. package/dist/daemon/services/knowledge-reindex.js +28 -1
  506. package/dist/daemon/services/knowledge-search.d.ts +3 -3
  507. package/dist/daemon/services/knowledge-search.d.ts.map +1 -1
  508. package/dist/daemon/services/knowledge-settings.d.ts +3 -3
  509. package/dist/daemon/services/knowledge-settings.d.ts.map +1 -1
  510. package/dist/daemon/services/knowledge-settings.js +24 -0
  511. package/dist/daemon/services/knowledge-versions.d.ts +3 -3
  512. package/dist/daemon/services/knowledge-versions.d.ts.map +1 -1
  513. package/dist/daemon/services/knowledge-versions.js +68 -7
  514. package/dist/daemon/services/leaderboard.d.ts +14 -6
  515. package/dist/daemon/services/leaderboard.d.ts.map +1 -1
  516. package/dist/daemon/services/leaderboard.js +74 -15
  517. package/dist/daemon/services/local-actions.d.ts +13 -0
  518. package/dist/daemon/services/local-actions.d.ts.map +1 -0
  519. package/dist/daemon/services/local-actions.js +120 -0
  520. package/dist/daemon/services/mcp-servers.d.ts +3 -3
  521. package/dist/daemon/services/mcp-servers.d.ts.map +1 -1
  522. package/dist/daemon/services/mcp-servers.js +68 -13
  523. package/dist/daemon/services/messages.d.ts +10 -6
  524. package/dist/daemon/services/messages.d.ts.map +1 -1
  525. package/dist/daemon/services/messages.js +87 -7
  526. package/dist/daemon/services/repos.d.ts +6 -6
  527. package/dist/daemon/services/repos.d.ts.map +1 -1
  528. package/dist/daemon/services/repos.js +131 -32
  529. package/dist/daemon/services/scheduler.d.ts +23 -27
  530. package/dist/daemon/services/scheduler.d.ts.map +1 -1
  531. package/dist/daemon/services/scheduler.js +61 -30
  532. package/dist/daemon/services/schedules.d.ts +3 -3
  533. package/dist/daemon/services/schedules.d.ts.map +1 -1
  534. package/dist/daemon/services/schedules.js +68 -7
  535. package/dist/daemon/services/session-env-selections.d.ts +3 -3
  536. package/dist/daemon/services/session-env-selections.d.ts.map +1 -1
  537. package/dist/daemon/services/session-mcp-servers.d.ts +3 -3
  538. package/dist/daemon/services/session-mcp-servers.d.ts.map +1 -1
  539. package/dist/daemon/services/session-token-service.d.ts.map +1 -1
  540. package/dist/daemon/services/session-token-service.js +3 -0
  541. package/dist/daemon/services/sessions.d.ts +20 -8
  542. package/dist/daemon/services/sessions.d.ts.map +1 -1
  543. package/dist/daemon/services/sessions.js +211 -17
  544. package/dist/daemon/services/tasks.d.ts +24 -7
  545. package/dist/daemon/services/tasks.d.ts.map +1 -1
  546. package/dist/daemon/services/tasks.js +235 -59
  547. package/dist/daemon/services/terminals.d.ts +21 -3
  548. package/dist/daemon/services/terminals.d.ts.map +1 -1
  549. package/dist/daemon/services/terminals.js +81 -25
  550. package/dist/daemon/services/thread-session-map.d.ts +3 -3
  551. package/dist/daemon/services/thread-session-map.d.ts.map +1 -1
  552. package/dist/daemon/services/thread-session-map.js +68 -7
  553. package/dist/daemon/services/user-avatar-sync.d.ts +21 -0
  554. package/dist/daemon/services/user-avatar-sync.d.ts.map +1 -0
  555. package/dist/daemon/services/user-avatar-sync.js +267 -0
  556. package/dist/daemon/services/users.d.ts +29 -9
  557. package/dist/daemon/services/users.d.ts.map +1 -1
  558. package/dist/daemon/services/users.js +383 -30
  559. package/dist/daemon/services/zone-trigger.d.ts.map +1 -1
  560. package/dist/daemon/services/zone-trigger.js +17 -4
  561. package/dist/daemon/setup/build-info.d.ts +1 -1
  562. package/dist/daemon/setup/build-info.d.ts.map +1 -1
  563. package/dist/daemon/setup/build-info.js +5 -1
  564. package/dist/daemon/setup/database.d.ts +8 -3
  565. package/dist/daemon/setup/database.d.ts.map +1 -1
  566. package/dist/daemon/setup/database.js +26 -6
  567. package/dist/daemon/setup/first-run-admin.d.ts +2 -2
  568. package/dist/daemon/setup/first-run-admin.d.ts.map +1 -1
  569. package/dist/daemon/setup/index.js +97 -17
  570. package/dist/daemon/setup/socketio.d.ts +10 -1
  571. package/dist/daemon/setup/socketio.d.ts.map +1 -1
  572. package/dist/daemon/setup/socketio.js +68 -10
  573. package/dist/daemon/startup.d.ts +13 -2
  574. package/dist/daemon/startup.d.ts.map +1 -1
  575. package/dist/daemon/startup.js +354 -88
  576. package/dist/daemon/utils/append-system-message.d.ts +2 -2
  577. package/dist/daemon/utils/append-system-message.d.ts.map +1 -1
  578. package/dist/daemon/utils/apply-session-config-defaults.d.ts.map +1 -1
  579. package/dist/daemon/utils/apply-session-config-defaults.js +12 -1
  580. package/dist/daemon/utils/authorization.d.ts +3 -1
  581. package/dist/daemon/utils/authorization.d.ts.map +1 -1
  582. package/dist/daemon/utils/authorization.js +21 -6
  583. package/dist/daemon/utils/branch-authorization.d.ts +30 -0
  584. package/dist/daemon/utils/branch-authorization.d.ts.map +1 -1
  585. package/dist/daemon/utils/branch-authorization.js +63 -5
  586. package/dist/daemon/utils/branch-inspect.d.ts +1 -0
  587. package/dist/daemon/utils/branch-inspect.d.ts.map +1 -1
  588. package/dist/daemon/utils/branch-inspect.js +11 -3
  589. package/dist/daemon/utils/executor-read-impersonation.d.ts +2 -2
  590. package/dist/daemon/utils/executor-read-impersonation.d.ts.map +1 -1
  591. package/dist/daemon/utils/git-impersonation.d.ts +10 -10
  592. package/dist/daemon/utils/git-impersonation.d.ts.map +1 -1
  593. package/dist/daemon/utils/git-remote-credential-scan.d.ts +3 -3
  594. package/dist/daemon/utils/git-remote-credential-scan.d.ts.map +1 -1
  595. package/dist/daemon/utils/git-remote-credential-scan.js +6 -2
  596. package/dist/daemon/utils/mcp-token-authorization.d.ts +18 -13
  597. package/dist/daemon/utils/mcp-token-authorization.d.ts.map +1 -1
  598. package/dist/daemon/utils/mcp-token-authorization.js +11 -5
  599. package/dist/daemon/utils/open-source-telemetry-config.d.ts +6 -0
  600. package/dist/daemon/utils/open-source-telemetry-config.d.ts.map +1 -0
  601. package/dist/daemon/utils/open-source-telemetry-config.js +21 -0
  602. package/dist/daemon/utils/open-source-telemetry-heartbeat.d.ts +7 -0
  603. package/dist/daemon/utils/open-source-telemetry-heartbeat.d.ts.map +1 -0
  604. package/dist/daemon/utils/open-source-telemetry-heartbeat.js +15 -0
  605. package/dist/daemon/utils/open-source-telemetry-usage.d.ts +9 -0
  606. package/dist/daemon/utils/open-source-telemetry-usage.d.ts.map +1 -0
  607. package/dist/daemon/utils/open-source-telemetry-usage.js +121 -0
  608. package/dist/daemon/utils/realign-repo-origin.d.ts +3 -3
  609. package/dist/daemon/utils/realign-repo-origin.d.ts.map +1 -1
  610. package/dist/daemon/utils/realign-repo-origin.js +47 -16
  611. package/dist/daemon/utils/realtime-publish.d.ts +2 -0
  612. package/dist/daemon/utils/realtime-publish.d.ts.map +1 -1
  613. package/dist/daemon/utils/realtime-publish.js +51 -10
  614. package/dist/daemon/utils/session-state-hooks.d.ts +3 -3
  615. package/dist/daemon/utils/session-state-hooks.d.ts.map +1 -1
  616. package/dist/daemon/utils/session-stop.d.ts +43 -0
  617. package/dist/daemon/utils/session-stop.d.ts.map +1 -0
  618. package/dist/daemon/utils/session-stop.js +102 -0
  619. package/dist/daemon/utils/session-task-state.d.ts +7 -2
  620. package/dist/daemon/utils/session-task-state.d.ts.map +1 -1
  621. package/dist/daemon/utils/session-task-state.js +9 -3
  622. package/dist/daemon/utils/session-tasks.d.ts +4 -4
  623. package/dist/daemon/utils/session-tasks.d.ts.map +1 -1
  624. package/dist/daemon/utils/session-tasks.js +4 -8
  625. package/dist/daemon/utils/session-turn-lock.d.ts +8 -1
  626. package/dist/daemon/utils/session-turn-lock.d.ts.map +1 -1
  627. package/dist/daemon/utils/session-turn-lock.js +25 -2
  628. package/dist/daemon/utils/spawn-executor.d.ts +23 -1
  629. package/dist/daemon/utils/spawn-executor.d.ts.map +1 -1
  630. package/dist/daemon/utils/spawn-executor.js +34 -4
  631. package/dist/daemon/utils/tenant-db-scope.d.ts +20 -0
  632. package/dist/daemon/utils/tenant-db-scope.d.ts.map +1 -0
  633. package/dist/daemon/utils/tenant-db-scope.js +114 -0
  634. package/dist/daemon/utils/unix-group-init.d.ts +3 -3
  635. package/dist/daemon/utils/unix-group-init.d.ts.map +1 -1
  636. package/dist/daemon/utils/upload.d.ts +6 -9
  637. package/dist/daemon/utils/upload.d.ts.map +1 -1
  638. package/dist/daemon/utils/upload.js +30 -37
  639. package/dist/daemon/widgets/env-vars/index.d.ts +26 -1
  640. package/dist/daemon/widgets/env-vars/index.d.ts.map +1 -1
  641. package/dist/daemon/widgets/env-vars/index.js +145 -21
  642. package/dist/daemon/widgets/index.js +137 -21
  643. package/dist/executor/commands/environment.d.ts +13 -0
  644. package/dist/executor/commands/environment.d.ts.map +1 -0
  645. package/dist/executor/commands/environment.js +291 -0
  646. package/dist/executor/commands/git.js +1 -1
  647. package/dist/executor/commands/index.d.ts.map +1 -1
  648. package/dist/executor/commands/index.js +5 -1
  649. package/dist/executor/commands/unix.d.ts +8 -1
  650. package/dist/executor/commands/unix.d.ts.map +1 -1
  651. package/dist/executor/commands/unix.js +157 -2
  652. package/dist/executor/git/index.d.ts +8 -0
  653. package/dist/executor/git/index.d.ts.map +1 -0
  654. package/dist/executor/git/index.js +7 -0
  655. package/dist/executor/handlers/sdk/base-executor.d.ts.map +1 -1
  656. package/dist/executor/handlers/sdk/base-executor.js +4 -1
  657. package/dist/executor/handlers/sdk/git-safe-directory.d.ts.map +1 -1
  658. package/dist/executor/handlers/sdk/git-safe-directory.js +1 -1
  659. package/dist/executor/payload-types.d.ts +201 -5
  660. package/dist/executor/payload-types.d.ts.map +1 -1
  661. package/dist/executor/payload-types.js +98 -0
  662. package/dist/executor/sdk-handlers/base/diff-enrichment.js +1 -1
  663. package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts.map +1 -1
  664. package/dist/executor/sdk-handlers/base/mcp-scoping.js +14 -0
  665. package/dist/executor/sdk-handlers/claude/message-processor.d.ts.map +1 -1
  666. package/dist/executor/sdk-handlers/claude/message-processor.js +0 -1
  667. package/dist/executor/sdk-handlers/claude/query-builder.d.ts +1 -0
  668. package/dist/executor/sdk-handlers/claude/query-builder.d.ts.map +1 -1
  669. package/dist/executor/sdk-handlers/claude/query-builder.js +91 -39
  670. package/dist/executor/sdk-handlers/codex/codex-tool.d.ts +6 -10
  671. package/dist/executor/sdk-handlers/codex/codex-tool.d.ts.map +1 -1
  672. package/dist/executor/sdk-handlers/codex/codex-tool.js +12 -15
  673. package/dist/executor/sdk-handlers/codex/normalizer.d.ts.map +1 -1
  674. package/dist/executor/sdk-handlers/codex/normalizer.js +11 -1
  675. package/dist/executor/sdk-handlers/codex/pricing/litellm-openai-model-prices.json +3663 -0
  676. package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.d.ts +31 -0
  677. package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.d.ts.map +1 -0
  678. package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.js +46 -0
  679. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts +12 -5
  680. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts.map +1 -1
  681. package/dist/executor/sdk-handlers/codex/prompt-service.js +133 -36
  682. package/dist/executor/sdk-handlers/codex/usage.d.ts +14 -23
  683. package/dist/executor/sdk-handlers/codex/usage.d.ts.map +1 -1
  684. package/dist/executor/sdk-handlers/codex/usage.js +18 -33
  685. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts +2 -4
  686. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts.map +1 -1
  687. package/dist/executor/sdk-handlers/copilot/prompt-service.js +4 -13
  688. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts +2 -4
  689. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts.map +1 -1
  690. package/dist/executor/sdk-handlers/gemini/prompt-service.js +4 -13
  691. package/dist/executor/services/feathers-client.js +5 -5
  692. package/dist/git/index.cjs +1101 -0
  693. package/dist/git/index.d.ts +533 -0
  694. package/dist/git/index.d.ts.map +1 -0
  695. package/dist/git/index.js +1022 -0
  696. package/dist/git/package.json +21 -0
  697. package/dist/git/pure.cjs +185 -0
  698. package/dist/git/pure.d.ts +39 -0
  699. package/dist/git/pure.d.ts.map +1 -0
  700. package/dist/git/pure.js +139 -0
  701. package/dist/ui/assets/AgorEmojiPickerInner-DQjr8M3_.js +1 -0
  702. package/dist/ui/assets/App-hJtcOxHv.js +5 -0
  703. package/dist/ui/assets/App-hJtcOxHv.js.gz +0 -0
  704. package/dist/ui/assets/AppNode-BhuMpn8O.js +1 -0
  705. package/dist/ui/assets/AppNode-BhuMpn8O.js.gz +0 -0
  706. package/dist/ui/assets/ArtifactConsentModal-oMMzRn8L.js +1 -0
  707. package/dist/ui/assets/ArtifactConsentModal-oMMzRn8L.js.gz +0 -0
  708. package/dist/ui/assets/ArtifactFullscreenPage-B3wT8t8f.js +9 -0
  709. package/dist/ui/assets/ArtifactFullscreenPage-B3wT8t8f.js.gz +0 -0
  710. package/dist/ui/assets/ArtifactNode-BzQcrwFS.js +9 -0
  711. package/dist/ui/assets/ArtifactNode-BzQcrwFS.js.gz +0 -0
  712. package/dist/ui/assets/AutocompleteTextarea-Dau-V_30.js +19 -0
  713. package/dist/ui/assets/AutocompleteTextarea-Dau-V_30.js.gz +0 -0
  714. package/dist/ui/assets/BoardObjectNodes-DdKWv_ZT.js +34 -0
  715. package/dist/ui/assets/BoardObjectNodes-DdKWv_ZT.js.gz +0 -0
  716. package/dist/ui/assets/CodeEditor.inner-Cuj6RuLL.js +7 -0
  717. package/dist/ui/assets/CodeEditor.inner-Cuj6RuLL.js.gz +0 -0
  718. package/dist/ui/assets/ConversationView-9-3ma1u-.js +1 -0
  719. package/dist/ui/assets/ConversationView-9-3ma1u-.js.gz +0 -0
  720. package/dist/ui/assets/EmbeddedTerminal-Lx5I9EOJ.js +2 -0
  721. package/dist/ui/assets/EmbeddedTerminal-Lx5I9EOJ.js.gz +0 -0
  722. package/dist/ui/assets/KnowledgePage-Dz8YAMYC.js +24 -0
  723. package/dist/ui/assets/KnowledgePage-Dz8YAMYC.js.gz +0 -0
  724. package/dist/ui/assets/MarketingScreenshotPage-9Qd7eZsm.css +1 -0
  725. package/dist/ui/assets/MarketingScreenshotPage-CmDPBHOl.js +143 -0
  726. package/dist/ui/assets/MarketingScreenshotPage-CmDPBHOl.js.gz +0 -0
  727. package/dist/ui/assets/MobileApp-BpgSG_gz.js +1 -0
  728. package/dist/ui/assets/MobileApp-BpgSG_gz.js.gz +0 -0
  729. package/dist/ui/assets/SessionCanvas-B6_mtlxK.js +13 -0
  730. package/dist/ui/assets/SessionCanvas-B6_mtlxK.js.gz +0 -0
  731. package/dist/ui/assets/SessionCanvas-Bh7Yg5dZ.css +1 -0
  732. package/dist/ui/assets/SessionCanvas-Bh7Yg5dZ.css.gz +0 -0
  733. package/dist/ui/assets/{StreamdownDemoPage-B9wbgp2s.js → StreamdownDemoPage-okKKR2QH.js} +2 -2
  734. package/dist/ui/assets/StreamdownDemoPage-okKKR2QH.js.gz +0 -0
  735. package/dist/ui/assets/TerminalModal-D9jMGZXv.js +2 -0
  736. package/dist/ui/assets/TerminalModal-D9jMGZXv.js.gz +0 -0
  737. package/dist/ui/assets/ThemeSwitcher-D9HgT37l.js +1 -0
  738. package/dist/ui/assets/ThemeSwitcher-D9HgT37l.js.gz +0 -0
  739. package/dist/ui/assets/ThemedSyntaxHighlighter.inner-C1FdIHn0.js +1 -0
  740. package/dist/ui/assets/antd-DT5ackd0.js +401 -0
  741. package/dist/ui/assets/antd-DT5ackd0.js.gz +0 -0
  742. package/dist/ui/assets/architecture-U656AL7Q-DMnxkQRZ.js +1 -0
  743. package/dist/ui/assets/architectureDiagram-VXUJARFQ-DwTJGGoj.js +36 -0
  744. package/dist/ui/assets/architectureDiagram-VXUJARFQ-DwTJGGoj.js.gz +0 -0
  745. package/dist/ui/assets/{blockDiagram-VD42YOAC-CzGHAHao.js → blockDiagram-VD42YOAC-Dh1_TVW2.js} +4 -4
  746. package/dist/ui/assets/blockDiagram-VD42YOAC-Dh1_TVW2.js.gz +0 -0
  747. package/dist/ui/assets/{c4Diagram-YG6GDRKO-DscJyaWN.js → c4Diagram-YG6GDRKO-B1e96AcB.js} +2 -2
  748. package/dist/ui/assets/c4Diagram-YG6GDRKO-B1e96AcB.js.gz +0 -0
  749. package/dist/ui/assets/channel-Jv4dT4S5.js +1 -0
  750. package/dist/ui/assets/{chunk-4BX2VUAB-DoWpTvP8.js → chunk-4BX2VUAB-BODpCjJx.js} +1 -1
  751. package/dist/ui/assets/chunk-55IACEB6-lJXvUquf.js +1 -0
  752. package/dist/ui/assets/{chunk-ABZYJK2D-RzDCrjE6.js → chunk-ABZYJK2D-DCTXWSzV.js} +3 -3
  753. package/dist/ui/assets/chunk-ABZYJK2D-DCTXWSzV.js.gz +0 -0
  754. package/dist/ui/assets/{chunk-AGHRB4JF-jidCS5Of.js → chunk-AGHRB4JF-CbNphBjE.js} +1 -1
  755. package/dist/ui/assets/chunk-AGHRB4JF-CbNphBjE.js.gz +0 -0
  756. package/dist/ui/assets/{chunk-ATLVNIR6-BEIIfJtC.js → chunk-ATLVNIR6-rWg3qxof.js} +1 -1
  757. package/dist/ui/assets/chunk-ATLVNIR6-rWg3qxof.js.gz +0 -0
  758. package/dist/ui/assets/{chunk-B4BG7PRW-B8b6dQQ2.js → chunk-B4BG7PRW-CgtLCbpE.js} +3 -3
  759. package/dist/ui/assets/chunk-B4BG7PRW-CgtLCbpE.js.gz +0 -0
  760. package/dist/ui/assets/{chunk-CVBHYZKI-D-mQAfrk.js → chunk-CVBHYZKI-DTL6Zgr0.js} +1 -1
  761. package/dist/ui/assets/{chunk-DI55MBZ5-BfATX3V8.js → chunk-DI55MBZ5-Dwvx2Kva.js} +1 -1
  762. package/dist/ui/assets/chunk-DI55MBZ5-Dwvx2Kva.js.gz +0 -0
  763. package/dist/ui/assets/chunk-EXTU4WIE-DHyaqTsP.js +1 -0
  764. package/dist/ui/assets/{chunk-FMBD7UC4-fqXscNvc.js → chunk-FMBD7UC4-BogA_9CV.js} +1 -1
  765. package/dist/ui/assets/{chunk-HN2XXSSU-BCHvD80g.js → chunk-HN2XXSSU-2blQO3Gb.js} +1 -1
  766. package/dist/ui/assets/chunk-HN2XXSSU-2blQO3Gb.js.gz +0 -0
  767. package/dist/ui/assets/chunk-JA3XYJ7Z-Cr1rmOui.js +11 -0
  768. package/dist/ui/assets/chunk-JA3XYJ7Z-Cr1rmOui.js.gz +0 -0
  769. package/dist/ui/assets/{chunk-JZLCHNYA-cKMooY3y.js → chunk-JZLCHNYA-BsgZ79Fa.js} +5 -5
  770. package/dist/ui/assets/chunk-JZLCHNYA-BsgZ79Fa.js.gz +0 -0
  771. package/dist/ui/assets/{chunk-MI3HLSF2-BlzO5wOE.js → chunk-MI3HLSF2-dwYeUy5S.js} +1 -1
  772. package/dist/ui/assets/chunk-MI3HLSF2-dwYeUy5S.js.gz +0 -0
  773. package/dist/ui/assets/chunk-N4CR4FBY-DEMgSRVe.js +2 -0
  774. package/dist/ui/assets/chunk-N4CR4FBY-DEMgSRVe.js.gz +0 -0
  775. package/dist/ui/assets/{chunk-QN33PNHL-DIHGQ_pd.js → chunk-QN33PNHL-DxdIDCAa.js} +1 -1
  776. package/dist/ui/assets/{chunk-QXUST7PY-C9l0muI0.js → chunk-QXUST7PY-BCK2V0i-.js} +2 -2
  777. package/dist/ui/assets/chunk-QXUST7PY-BCK2V0i-.js.gz +0 -0
  778. package/dist/ui/assets/chunk-QZHKN3VN-CALjGrEE.js +1 -0
  779. package/dist/ui/assets/chunk-S3R3BYOJ-GP3zIxrB.js +2 -0
  780. package/dist/ui/assets/chunk-S3R3BYOJ-GP3zIxrB.js.gz +0 -0
  781. package/dist/ui/assets/{chunk-TZMSLE5B-DZwI0C_2.js → chunk-TZMSLE5B-dX5RaM6g.js} +1 -1
  782. package/dist/ui/assets/chunk-TZMSLE5B-dX5RaM6g.js.gz +0 -0
  783. package/dist/ui/assets/classDiagram-2ON5EDUG-C3_RVP70.js +1 -0
  784. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-C3_RVP70.js +1 -0
  785. package/dist/ui/assets/constants-GjIDNVyt.js +1 -0
  786. package/dist/ui/assets/{cose-bilkent-S5V4N54A-Ipik-oSD.js → cose-bilkent-S5V4N54A-Dx0BJVDl.js} +1 -1
  787. package/dist/ui/assets/cose-bilkent-S5V4N54A-Dx0BJVDl.js.gz +0 -0
  788. package/dist/ui/assets/cursor-QEb7m-rN.png +0 -0
  789. package/dist/ui/assets/{dagre-6UL2VRFP-BDpyWQnh.js → dagre-6UL2VRFP-DiQSUxqN.js} +1 -1
  790. package/dist/ui/assets/dagre-6UL2VRFP-DiQSUxqN.js.gz +0 -0
  791. package/dist/ui/assets/{dagre-CgA4KhUX.js → dagre-Bekd9Vdj.js} +1 -1
  792. package/dist/ui/assets/dagre-Bekd9Vdj.js.gz +0 -0
  793. package/dist/ui/assets/diagram-PSM6KHXK-DtJnDQjc.js +24 -0
  794. package/dist/ui/assets/diagram-PSM6KHXK-DtJnDQjc.js.gz +0 -0
  795. package/dist/ui/assets/{diagram-QEK2KX5R-BWPW28XI.js → diagram-QEK2KX5R-CobkCRdj.js} +1 -1
  796. package/dist/ui/assets/diagram-QEK2KX5R-CobkCRdj.js.gz +0 -0
  797. package/dist/ui/assets/{diagram-S2PKOQOG-BIHhcGoV.js → diagram-S2PKOQOG-DHEZYivc.js} +1 -1
  798. package/dist/ui/assets/diagram-S2PKOQOG-DHEZYivc.js.gz +0 -0
  799. package/dist/ui/assets/editor-DQIG-JYZ.js +43 -0
  800. package/dist/ui/assets/editor-DQIG-JYZ.js.gz +0 -0
  801. package/dist/ui/assets/emoji-B0hLmSLZ.js +3 -0
  802. package/dist/ui/assets/emoji-B0hLmSLZ.js.gz +0 -0
  803. package/dist/ui/assets/{erDiagram-Q2GNP2WA-ubTaAFcK.js → erDiagram-Q2GNP2WA-BVNeTZPQ.js} +2 -2
  804. package/dist/ui/assets/erDiagram-Q2GNP2WA-BVNeTZPQ.js.gz +0 -0
  805. package/dist/ui/assets/flowDiagram-NV44I4VS-C73VFdyk.js +162 -0
  806. package/dist/ui/assets/flowDiagram-NV44I4VS-C73VFdyk.js.gz +0 -0
  807. package/dist/ui/assets/ganttDiagram-LVOFAZNH-B_RosuD1.js +267 -0
  808. package/dist/ui/assets/ganttDiagram-LVOFAZNH-B_RosuD1.js.gz +0 -0
  809. package/dist/ui/assets/{gitGraph-F6HP7TQM-DghoobE6.js → gitGraph-F6HP7TQM-DMFIqn4h.js} +1 -1
  810. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-hxbgwNA1.js +65 -0
  811. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-hxbgwNA1.js.gz +0 -0
  812. package/dist/ui/assets/index-DTz1Dif6.js +64 -0
  813. package/dist/ui/assets/index-DTz1Dif6.js.gz +0 -0
  814. package/dist/ui/assets/index-qkT7Qqm2.css +1 -0
  815. package/dist/ui/assets/index-qkT7Qqm2.css.gz +0 -0
  816. package/dist/ui/assets/{info-NVLQJR56-0ZldEXPQ.js → info-NVLQJR56-DZ3K-w48.js} +1 -1
  817. package/dist/ui/assets/{infoDiagram-ER5ION4S-DMmPX-il.js → infoDiagram-ER5ION4S-CxnBJQu6.js} +1 -1
  818. package/dist/ui/assets/{journeyDiagram-XKPGCS4Q-CrVickA2.js → journeyDiagram-XKPGCS4Q-CHYNj-f8.js} +3 -3
  819. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHYNj-f8.js.gz +0 -0
  820. package/dist/ui/assets/{kanban-definition-3W4ZIXB7-C_BsdHYL.js → kanban-definition-3W4ZIXB7-DQPCCsj2.js} +1 -1
  821. package/dist/ui/assets/kanban-definition-3W4ZIXB7-DQPCCsj2.js.gz +0 -0
  822. package/dist/ui/assets/{line-CfBP7Yic.js → line-DBRjKmfa.js} +1 -1
  823. package/dist/ui/assets/{linear-BsjageUB.js → linear-DFao5Wyp.js} +1 -1
  824. package/dist/ui/assets/linear-DFao5Wyp.js.gz +0 -0
  825. package/dist/ui/assets/{mermaid-parser.core-DZdP-NFq.js → mermaid-parser.core-DYCfacHj.js} +2 -2
  826. package/dist/ui/assets/mermaid-parser.core-DYCfacHj.js.gz +0 -0
  827. package/dist/ui/assets/mermaid.core-C6xGFSdE.js +11 -0
  828. package/dist/ui/assets/mermaid.core-C6xGFSdE.js.gz +0 -0
  829. package/dist/ui/assets/{mindmap-definition-VGOIOE7T-BbmaUjMY.js → mindmap-definition-VGOIOE7T-L3Pw-YM7.js} +1 -1
  830. package/dist/ui/assets/mindmap-definition-VGOIOE7T-L3Pw-YM7.js.gz +0 -0
  831. package/dist/ui/assets/{packet-BFZMPI3H-D_ZhkXuT.js → packet-BFZMPI3H-CpL6iNoa.js} +1 -1
  832. package/dist/ui/assets/{particles-Dv28pjOd.js → particles-CT8hcJOA.js} +1 -1
  833. package/dist/ui/assets/particles-CT8hcJOA.js.gz +0 -0
  834. package/dist/ui/assets/{pie-7BOR55EZ-Dn0Q3qNx.js → pie-7BOR55EZ-hTqChbTo.js} +1 -1
  835. package/dist/ui/assets/{pieDiagram-ADFJNKIX-BbyjfYu8.js → pieDiagram-ADFJNKIX-Bf4Nou75.js} +1 -1
  836. package/dist/ui/assets/pieDiagram-ADFJNKIX-Bf4Nou75.js.gz +0 -0
  837. package/dist/ui/assets/{quadrantDiagram-AYHSOK5B-Bc3GqMKz.js → quadrantDiagram-AYHSOK5B-DpjUTLB1.js} +3 -3
  838. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DpjUTLB1.js.gz +0 -0
  839. package/dist/ui/assets/{radar-NHE76QYJ-BHwoAy1q.js → radar-NHE76QYJ-myy7OENC.js} +1 -1
  840. package/dist/ui/assets/reactflow-Cubtnk8i.js +2 -0
  841. package/dist/ui/assets/reactflow-Cubtnk8i.js.gz +0 -0
  842. package/dist/ui/assets/{requirementDiagram-UZGBJVZJ-BQaKKL09.js → requirementDiagram-UZGBJVZJ-Bfrfh-0-.js} +1 -1
  843. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bfrfh-0-.js.gz +0 -0
  844. package/dist/ui/assets/{sandpack-BQW_FQ7G.js → sandpack-C58bwfIS.js} +38 -38
  845. package/dist/ui/assets/sandpack-C58bwfIS.js.gz +0 -0
  846. package/dist/ui/assets/sandpackDefaults-Bkga8XAE.js +1 -0
  847. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-ClZAZ6va.js +10 -0
  848. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-ClZAZ6va.js.gz +0 -0
  849. package/dist/ui/assets/{sequenceDiagram-WL72ISMW-Dw32824o.js → sequenceDiagram-WL72ISMW-CNgly63p.js} +6 -6
  850. package/dist/ui/assets/sequenceDiagram-WL72ISMW-CNgly63p.js.gz +0 -0
  851. package/dist/ui/assets/src-DAeyG22O.js +34 -0
  852. package/dist/ui/assets/src-DAeyG22O.js.gz +0 -0
  853. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BrEAoDpE.js +1 -0
  854. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BrEAoDpE.js.gz +0 -0
  855. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-BNL52_oN.js +1 -0
  856. package/dist/ui/assets/streamdown-BdAVfkeF.js +521 -0
  857. package/dist/ui/assets/streamdown-BdAVfkeF.js.gz +0 -0
  858. package/dist/ui/assets/syntax-BOfTnQiy.js +9 -0
  859. package/dist/ui/assets/syntax-BOfTnQiy.js.gz +0 -0
  860. package/dist/ui/assets/{timeline-definition-IT6M3QCI-Jh_WZzXv.js → timeline-definition-IT6M3QCI-CaRH3k4l.js} +16 -16
  861. package/dist/ui/assets/timeline-definition-IT6M3QCI-CaRH3k4l.js.gz +0 -0
  862. package/dist/ui/assets/{treemap-KMMF4GRG-CPYIgjxE.js → treemap-KMMF4GRG-CUaLOV_B.js} +1 -1
  863. package/dist/ui/assets/{knowledgeRoutes-CivaUqha.js → useUserLocalStorage-C8sgXgXR.js} +1 -1
  864. package/dist/ui/assets/useUserLocalStorage-C8sgXgXR.js.gz +0 -0
  865. package/dist/ui/assets/{xychartDiagram-PRI3JC2R-CERc7Rdb.js → xychartDiagram-PRI3JC2R-BlhkI9T_.js} +1 -1
  866. package/dist/ui/assets/xychartDiagram-PRI3JC2R-BlhkI9T_.js.gz +0 -0
  867. package/dist/ui/index.html +13 -12
  868. package/dist/ui/index.html.gz +0 -0
  869. package/package.json +12 -10
  870. package/scripts/postinstall.js +27 -19
  871. package/dist/cli/commands/daemon/sync.d.ts.map +0 -1
  872. package/dist/ui/assets/App-9s2WHM6S.js +0 -22
  873. package/dist/ui/assets/App-9s2WHM6S.js.gz +0 -0
  874. package/dist/ui/assets/App-BAdBsEnV.css +0 -1
  875. package/dist/ui/assets/App-BAdBsEnV.css.gz +0 -0
  876. package/dist/ui/assets/ArtifactConsentModal-ParNk5kW.js +0 -1
  877. package/dist/ui/assets/ArtifactConsentModal-ParNk5kW.js.gz +0 -0
  878. package/dist/ui/assets/ArtifactFullscreenPage-VQxLMCiN.js +0 -9
  879. package/dist/ui/assets/ArtifactFullscreenPage-VQxLMCiN.js.gz +0 -0
  880. package/dist/ui/assets/AutocompleteTextarea-3RchrIgk.js +0 -18
  881. package/dist/ui/assets/AutocompleteTextarea-3RchrIgk.js.gz +0 -0
  882. package/dist/ui/assets/CodeEditor.inner-D51Z_CLQ.js +0 -8
  883. package/dist/ui/assets/CodeEditor.inner-D51Z_CLQ.js.gz +0 -0
  884. package/dist/ui/assets/ConversationView-Dyddw2b1.js +0 -34
  885. package/dist/ui/assets/ConversationView-Dyddw2b1.js.gz +0 -0
  886. package/dist/ui/assets/KnowledgePage-CdftslnF.js +0 -24
  887. package/dist/ui/assets/KnowledgePage-CdftslnF.js.gz +0 -0
  888. package/dist/ui/assets/MobileApp-BdBMpnJ1.js +0 -1
  889. package/dist/ui/assets/MobileApp-BdBMpnJ1.js.gz +0 -0
  890. package/dist/ui/assets/StreamdownDemoPage-B9wbgp2s.js.gz +0 -0
  891. package/dist/ui/assets/ThemeSwitcher-ubn6IOz9.js +0 -1
  892. package/dist/ui/assets/ThemeSwitcher-ubn6IOz9.js.gz +0 -0
  893. package/dist/ui/assets/antd-C-HfEC4E.js +0 -400
  894. package/dist/ui/assets/antd-C-HfEC4E.js.gz +0 -0
  895. package/dist/ui/assets/architecture-U656AL7Q-dkBewUpN.js +0 -1
  896. package/dist/ui/assets/architectureDiagram-VXUJARFQ-ChmZt3zk.js +0 -36
  897. package/dist/ui/assets/architectureDiagram-VXUJARFQ-ChmZt3zk.js.gz +0 -0
  898. package/dist/ui/assets/blockDiagram-VD42YOAC-CzGHAHao.js.gz +0 -0
  899. package/dist/ui/assets/c4Diagram-YG6GDRKO-DscJyaWN.js.gz +0 -0
  900. package/dist/ui/assets/channel-DvRQqEqC.js +0 -1
  901. package/dist/ui/assets/chunk-55IACEB6-DojF2pZN.js +0 -1
  902. package/dist/ui/assets/chunk-ABZYJK2D-RzDCrjE6.js.gz +0 -0
  903. package/dist/ui/assets/chunk-AGHRB4JF-jidCS5Of.js.gz +0 -0
  904. package/dist/ui/assets/chunk-ATLVNIR6-BEIIfJtC.js.gz +0 -0
  905. package/dist/ui/assets/chunk-B4BG7PRW-B8b6dQQ2.js.gz +0 -0
  906. package/dist/ui/assets/chunk-DI55MBZ5-BfATX3V8.js.gz +0 -0
  907. package/dist/ui/assets/chunk-EXTU4WIE-BKt6lPJM.js +0 -1
  908. package/dist/ui/assets/chunk-HN2XXSSU-BCHvD80g.js.gz +0 -0
  909. package/dist/ui/assets/chunk-JA3XYJ7Z-Cp6dqHnY.js +0 -11
  910. package/dist/ui/assets/chunk-JA3XYJ7Z-Cp6dqHnY.js.gz +0 -0
  911. package/dist/ui/assets/chunk-JZLCHNYA-cKMooY3y.js.gz +0 -0
  912. package/dist/ui/assets/chunk-MI3HLSF2-BlzO5wOE.js.gz +0 -0
  913. package/dist/ui/assets/chunk-N4CR4FBY-pASDorUx.js +0 -2
  914. package/dist/ui/assets/chunk-N4CR4FBY-pASDorUx.js.gz +0 -0
  915. package/dist/ui/assets/chunk-QXUST7PY-C9l0muI0.js.gz +0 -0
  916. package/dist/ui/assets/chunk-QZHKN3VN-CZskCFCf.js +0 -1
  917. package/dist/ui/assets/chunk-S3R3BYOJ-VJiLzt2o.js +0 -2
  918. package/dist/ui/assets/chunk-S3R3BYOJ-VJiLzt2o.js.gz +0 -0
  919. package/dist/ui/assets/chunk-TZMSLE5B-DZwI0C_2.js.gz +0 -0
  920. package/dist/ui/assets/classDiagram-2ON5EDUG-BFASUbmZ.js +0 -1
  921. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-BFASUbmZ.js +0 -1
  922. package/dist/ui/assets/cose-bilkent-S5V4N54A-Ipik-oSD.js.gz +0 -0
  923. package/dist/ui/assets/dagre-6UL2VRFP-BDpyWQnh.js.gz +0 -0
  924. package/dist/ui/assets/dagre-CgA4KhUX.js.gz +0 -0
  925. package/dist/ui/assets/diagram-PSM6KHXK-B4GRzxLJ.js +0 -24
  926. package/dist/ui/assets/diagram-PSM6KHXK-B4GRzxLJ.js.gz +0 -0
  927. package/dist/ui/assets/diagram-QEK2KX5R-BWPW28XI.js.gz +0 -0
  928. package/dist/ui/assets/diagram-S2PKOQOG-BIHhcGoV.js.gz +0 -0
  929. package/dist/ui/assets/editor-C-HJ7Yw0.js +0 -39
  930. package/dist/ui/assets/editor-C-HJ7Yw0.js.gz +0 -0
  931. package/dist/ui/assets/emoji-D8F6B62m.js +0 -3
  932. package/dist/ui/assets/emoji-D8F6B62m.js.gz +0 -0
  933. package/dist/ui/assets/erDiagram-Q2GNP2WA-ubTaAFcK.js.gz +0 -0
  934. package/dist/ui/assets/flowDiagram-NV44I4VS-BHLCTYjI.js +0 -162
  935. package/dist/ui/assets/flowDiagram-NV44I4VS-BHLCTYjI.js.gz +0 -0
  936. package/dist/ui/assets/ganttDiagram-LVOFAZNH-ClC3pay1.js +0 -267
  937. package/dist/ui/assets/ganttDiagram-LVOFAZNH-ClC3pay1.js.gz +0 -0
  938. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-Clqpiswu.js +0 -65
  939. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-Clqpiswu.js.gz +0 -0
  940. package/dist/ui/assets/index-D9OElx9A.css +0 -1
  941. package/dist/ui/assets/index-D9OElx9A.css.gz +0 -0
  942. package/dist/ui/assets/index-DxPuzG7E.js +0 -350
  943. package/dist/ui/assets/index-DxPuzG7E.js.gz +0 -0
  944. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CrVickA2.js.gz +0 -0
  945. package/dist/ui/assets/kanban-definition-3W4ZIXB7-C_BsdHYL.js.gz +0 -0
  946. package/dist/ui/assets/katex-CamJ39w1.js +0 -257
  947. package/dist/ui/assets/katex-CamJ39w1.js.gz +0 -0
  948. package/dist/ui/assets/knowledgeRoutes-CivaUqha.js.gz +0 -0
  949. package/dist/ui/assets/linear-BsjageUB.js.gz +0 -0
  950. package/dist/ui/assets/mermaid-parser.core-DZdP-NFq.js.gz +0 -0
  951. package/dist/ui/assets/mermaid.core-TNrI0pHG.js +0 -11
  952. package/dist/ui/assets/mermaid.core-TNrI0pHG.js.gz +0 -0
  953. package/dist/ui/assets/message-BtWWJ9Af.js +0 -36
  954. package/dist/ui/assets/message-BtWWJ9Af.js.gz +0 -0
  955. package/dist/ui/assets/mindmap-definition-VGOIOE7T-BbmaUjMY.js.gz +0 -0
  956. package/dist/ui/assets/particles-Dv28pjOd.js.gz +0 -0
  957. package/dist/ui/assets/pieDiagram-ADFJNKIX-BbyjfYu8.js.gz +0 -0
  958. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-Bc3GqMKz.js.gz +0 -0
  959. package/dist/ui/assets/reactflow-BVYPxNhc.js +0 -2
  960. package/dist/ui/assets/reactflow-BVYPxNhc.js.gz +0 -0
  961. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-BQaKKL09.js.gz +0 -0
  962. package/dist/ui/assets/sandpack-BQW_FQ7G.js.gz +0 -0
  963. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-DiJvDvhb.js +0 -10
  964. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-DiJvDvhb.js.gz +0 -0
  965. package/dist/ui/assets/sequenceDiagram-WL72ISMW-Dw32824o.js.gz +0 -0
  966. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BCOpNdHV.js +0 -1
  967. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BCOpNdHV.js.gz +0 -0
  968. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-Cuqwvgfg.js +0 -1
  969. package/dist/ui/assets/syntax-VJrU5BEu.js +0 -10
  970. package/dist/ui/assets/syntax-VJrU5BEu.js.gz +0 -0
  971. package/dist/ui/assets/theme-DZtFA8b4.js +0 -1
  972. package/dist/ui/assets/timeline-definition-IT6M3QCI-Jh_WZzXv.js.gz +0 -0
  973. package/dist/ui/assets/xychartDiagram-PRI3JC2R-CERc7Rdb.js.gz +0 -0
  974. /package/dist/cli/commands/{admin → local}/sync-unix.d.ts +0 -0
@@ -1,5 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
2
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
3
5
  var __esm = (fn, res) => function __init() {
4
6
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
7
  };
@@ -7,6 +9,15 @@ var __export = (target, all) => {
7
9
  for (var name in all)
8
10
  __defProp(target, name, { get: all[name], enumerable: true });
9
11
  };
12
+ var __copyProps = (to, from, except, desc6) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc6 = __getOwnPropDesc(from, key)) || desc6.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
10
21
 
11
22
  // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.15_tsx@4.22.4_typescript@6.0.3_yaml@2.9.0/node_modules/tsup/assets/esm_shims.js
12
23
  import path from "path";
@@ -136,6 +147,71 @@ var init_executor_heartbeat = __esm({
136
147
  }
137
148
  });
138
149
 
150
+ // src/config/multitenancy.ts
151
+ function detectPostgresUrl(url) {
152
+ if (!url) return false;
153
+ const lower = url.toLowerCase();
154
+ return lower.startsWith("postgresql://") || lower.startsWith("postgres://") || lower.startsWith("pg://");
155
+ }
156
+ function resolveMultiTenancyDatabaseDialect(config = {}) {
157
+ if (process.env.AGOR_DB_DIALECT === "postgresql" || process.env.AGOR_DB_DIALECT === "sqlite") {
158
+ return process.env.AGOR_DB_DIALECT;
159
+ }
160
+ if (detectPostgresUrl(process.env.DATABASE_URL)) return "postgresql";
161
+ if (config.database?.dialect === "postgresql" || config.database?.dialect === "sqlite") {
162
+ return config.database.dialect;
163
+ }
164
+ if (detectPostgresUrl(config.database?.postgresql?.url) || config.database?.postgresql?.host) {
165
+ return "postgresql";
166
+ }
167
+ return "sqlite";
168
+ }
169
+ function resolveMultiTenancyConfig(config) {
170
+ const raw = config.multi_tenancy ?? {};
171
+ const mode = raw.mode ?? "static";
172
+ return {
173
+ mode,
174
+ static_tenant_id: raw.static_tenant_id?.trim() || DEFAULT_STATIC_TENANT_ID,
175
+ ...raw.auth_claim ? { auth_claim: raw.auth_claim } : {},
176
+ ...raw.trusted_header ? { trusted_header: raw.trusted_header } : {}
177
+ };
178
+ }
179
+ function assertValidMultiTenancyConfig(config) {
180
+ const resolved = resolveMultiTenancyConfig(config);
181
+ if (resolved.mode !== "static" && resolved.mode !== "required_from_auth") {
182
+ throw new Error("Config error: multi_tenancy.mode must be one of: static, required_from_auth");
183
+ }
184
+ if (!resolved.static_tenant_id) {
185
+ throw new Error("Config error: multi_tenancy.static_tenant_id must not be empty");
186
+ }
187
+ if (resolved.auth_claim && RESERVED_AUTH_CLAIMS.has(resolved.auth_claim)) {
188
+ throw new Error(
189
+ `Config error: multi_tenancy.auth_claim cannot be reserved JWT claim '${resolved.auth_claim}'`
190
+ );
191
+ }
192
+ if (resolved.mode === "required_from_auth") {
193
+ if (resolveMultiTenancyDatabaseDialect(config) !== "postgresql") {
194
+ throw new Error(
195
+ "Config error: multi_tenancy.required_from_auth requires database.dialect: postgresql"
196
+ );
197
+ }
198
+ if (!resolved.auth_claim && !resolved.trusted_header) {
199
+ throw new Error(
200
+ "Config error: multi_tenancy.required_from_auth requires multi_tenancy.auth_claim or multi_tenancy.trusted_header"
201
+ );
202
+ }
203
+ }
204
+ }
205
+ var DEFAULT_STATIC_TENANT_ID, RESERVED_AUTH_CLAIMS;
206
+ var init_multitenancy = __esm({
207
+ "src/config/multitenancy.ts"() {
208
+ "use strict";
209
+ init_esm_shims();
210
+ DEFAULT_STATIC_TENANT_ID = "default";
211
+ RESERVED_AUTH_CLAIMS = /* @__PURE__ */ new Set(["aud", "exp", "iat", "iss", "jti", "nbf", "sub", "type"]);
212
+ }
213
+ });
214
+
139
215
  // src/config/types.ts
140
216
  var BRANCH_STORAGE_MODES, DEFAULT_BRANCH_STORAGE_MODE;
141
217
  var init_types = __esm({
@@ -180,6 +256,7 @@ __export(config_manager_exports, {
180
256
  requireDaemonUser: () => requireDaemonUser,
181
257
  requirePublicBaseUrl: () => requirePublicBaseUrl,
182
258
  resolveBranchStorageConfig: () => resolveBranchStorageConfig,
259
+ resolveExecutionSecurityMode: () => resolveExecutionSecurityMode,
183
260
  saveConfig: () => saveConfig,
184
261
  setConfigValue: () => setConfigValue,
185
262
  unsetConfigValue: () => unsetConfigValue
@@ -188,14 +265,14 @@ import { readFileSync, statSync } from "fs";
188
265
  import fs2 from "fs/promises";
189
266
  import os from "os";
190
267
  import path2 from "path";
191
- import yaml2 from "js-yaml";
268
+ import * as yaml2 from "js-yaml";
192
269
  function cacheKeyMatches(a, b) {
193
270
  return a.mtimeMs === b.mtimeMs && a.size === b.size;
194
271
  }
195
272
  function statCacheKey(configPath) {
196
273
  try {
197
- const stat2 = statSync(configPath);
198
- return { mtimeMs: stat2.mtimeMs, size: stat2.size };
274
+ const stat = statSync(configPath);
275
+ return { mtimeMs: stat.mtimeMs, size: stat.size };
199
276
  } catch (error) {
200
277
  if (error.code === "ENOENT") {
201
278
  return NO_FILE_KEY;
@@ -223,6 +300,9 @@ function __resetConfigCacheForTests() {
223
300
  invalidateConfigCache();
224
301
  }
225
302
  function parseAndValidateConfig(content) {
303
+ if (content.trim() === "") {
304
+ return {};
305
+ }
226
306
  const parsed = yaml2.load(content);
227
307
  const finalConfig = parsed || {};
228
308
  validateConfig(finalConfig);
@@ -260,6 +340,7 @@ To update: agor config set execution.unix_user_mode insulated`
260
340
  `Config error: execution.managed_envs_execution_mode must be one of: hybrid, webhook-only`
261
341
  );
262
342
  }
343
+ assertValidMultiTenancyConfig(config);
263
344
  validateOptionalHttpUrl(
264
345
  config.external_launch,
265
346
  "login_redirect_url",
@@ -377,7 +458,12 @@ function getDefaultConfig() {
377
458
  // Default: sync passwords to Unix
378
459
  executor_heartbeat: resolveExecutorHeartbeatConfig()
379
460
  },
380
- analytics: getDefaultAnalyticsConfig()
461
+ analytics: getDefaultAnalyticsConfig(),
462
+ telemetry: {},
463
+ multi_tenancy: {
464
+ mode: "static",
465
+ static_tenant_id: "default"
466
+ }
381
467
  };
382
468
  }
383
469
  function expandHomePath(input) {
@@ -409,7 +495,8 @@ async function getConfigValue(key) {
409
495
  ui: { ...defaults.ui, ...config.ui },
410
496
  execution: { ...defaults.execution, ...config.execution },
411
497
  paths: { ...defaults.paths, ...config.paths },
412
- analytics: { ...defaults.analytics, ...config.analytics }
498
+ analytics: { ...defaults.analytics, ...config.analytics },
499
+ telemetry: { ...defaults.telemetry, ...config.telemetry }
413
500
  };
414
501
  const parts = key.split(".");
415
502
  let value = merged;
@@ -480,6 +567,9 @@ async function getBaseUrl() {
480
567
  if (config.daemon?.base_url) {
481
568
  return validateBaseUrl(config.daemon.base_url);
482
569
  }
570
+ if (config.ui?.base_url) {
571
+ return validateBaseUrl(config.ui.base_url);
572
+ }
483
573
  const defaults = getDefaultConfig();
484
574
  const envPort = process.env.PORT ? Number.parseInt(process.env.PORT, 10) : void 0;
485
575
  const port = envPort || config.daemon?.port || defaults.daemon?.port || DAEMON.DEFAULT_PORT;
@@ -494,8 +584,11 @@ async function requirePublicBaseUrl() {
494
584
  if (config.daemon?.base_url) {
495
585
  return validateBaseUrl(config.daemon.base_url);
496
586
  }
587
+ if (config.ui?.base_url) {
588
+ return validateBaseUrl(config.ui.base_url);
589
+ }
497
590
  throw new PublicBaseUrlNotConfiguredError(
498
- "No public base URL configured. Set the AGOR_BASE_URL environment variable or `daemon.base_url` in ~/.agor/config.yaml to the daemon's browser-reachable URL (e.g. https://agor.example.com). This is required so OAuth providers can redirect users back to a URL their browser can reach \u2014 the localhost fallback only works for browsers on the daemon machine."
591
+ "No public base URL configured. Set the AGOR_BASE_URL environment variable or `daemon.base_url` (preferred) / `ui.base_url` (legacy) in ~/.agor/config.yaml to the daemon's browser-reachable URL (e.g. https://agor.example.com). This is required so OAuth providers can redirect users back to a URL their browser can reach \u2014 the localhost fallback only works for browsers on the daemon machine."
499
592
  );
500
593
  }
501
594
  function loadConfigSync() {
@@ -565,10 +658,10 @@ function requireDaemonUser(config) {
565
658
  if (config.daemon?.unix_user) {
566
659
  return config.daemon.unix_user;
567
660
  }
568
- const unixIsolationEnabled = config.execution?.branch_rbac === true || config.execution?.unix_user_mode && config.execution.unix_user_mode !== "simple";
661
+ const unixIsolationEnabled = resolveExecutionSecurityMode(config).requiresDaemonUnixUser;
569
662
  if (unixIsolationEnabled) {
570
663
  throw new Error(
571
- "Unix isolation is enabled (branch_rbac or unix_user_mode) but daemon.unix_user is not configured.\nPlease set daemon.unix_user in ~/.agor/config.yaml to the user running the daemon.\nExample:\n daemon:\n unix_user: agor"
664
+ "Unix isolation is enabled (execution.unix_user_mode is insulated or strict) but daemon.unix_user is not configured.\nPlease set daemon.unix_user in ~/.agor/config.yaml to the user running the daemon.\nExample:\n daemon:\n unix_user: agor"
572
665
  );
573
666
  }
574
667
  const user = process.env.USER || os.userInfo().username;
@@ -579,19 +672,29 @@ function requireDaemonUser(config) {
579
672
  }
580
673
  return user;
581
674
  }
675
+ function resolveExecutionSecurityMode(config = loadConfigSync()) {
676
+ const unixUserMode = config.execution?.unix_user_mode ?? "simple";
677
+ const unixIsolationEnabled = unixUserMode !== "simple";
678
+ return {
679
+ appRbacEnabled: config.execution?.branch_rbac === true,
680
+ unixUserMode,
681
+ unixImpersonationEnabled: unixIsolationEnabled,
682
+ unixFsIsolationEnabled: unixIsolationEnabled,
683
+ unixGroupRefreshNeeded: unixIsolationEnabled,
684
+ requiresDaemonUnixUser: unixIsolationEnabled,
685
+ shouldInitUnixGroups: unixIsolationEnabled
686
+ };
687
+ }
582
688
  function isBranchRbacEnabled() {
583
689
  try {
584
- const config = loadConfigSync();
585
- return config.execution?.branch_rbac === true;
690
+ return resolveExecutionSecurityMode().appRbacEnabled;
586
691
  } catch {
587
692
  return false;
588
693
  }
589
694
  }
590
695
  function isUnixImpersonationEnabled() {
591
696
  try {
592
- const config = loadConfigSync();
593
- const mode = config.execution?.unix_user_mode;
594
- return mode !== void 0 && mode !== "simple";
697
+ return resolveExecutionSecurityMode().unixImpersonationEnabled;
595
698
  } catch {
596
699
  return false;
597
700
  }
@@ -617,7 +720,7 @@ function ensureBranchStorageModeAllowed(mode) {
617
720
  }
618
721
  }
619
722
  function isUnixGroupRefreshNeeded() {
620
- return isBranchRbacEnabled() || isUnixImpersonationEnabled();
723
+ return resolveExecutionSecurityMode().unixGroupRefreshNeeded;
621
724
  }
622
725
  function getDataHome() {
623
726
  if (process.env.AGOR_DATA_HOME) {
@@ -668,6 +771,7 @@ var init_config_manager = __esm({
668
771
  init_analytics_defaults();
669
772
  init_constants();
670
773
  init_executor_heartbeat();
774
+ init_multitenancy();
671
775
  init_types();
672
776
  NO_FILE = -1;
673
777
  NO_FILE_KEY = { mtimeMs: NO_FILE, size: 0 };
@@ -690,6 +794,21 @@ var init_config_manager = __esm({
690
794
  }
691
795
  });
692
796
 
797
+ // src/db/tenant-context.ts
798
+ import { AsyncLocalStorage } from "async_hooks";
799
+ function getCurrentTenantId() {
800
+ const store = tenantDatabaseScope.getStore();
801
+ return store?.kind === "tenant" ? store.tenantId : void 0;
802
+ }
803
+ var tenantDatabaseScope;
804
+ var init_tenant_context = __esm({
805
+ "src/db/tenant-context.ts"() {
806
+ "use strict";
807
+ init_esm_shims();
808
+ tenantDatabaseScope = new AsyncLocalStorage();
809
+ }
810
+ });
811
+
693
812
  // src/db/database-wrapper.ts
694
813
  var database_wrapper_exports = {};
695
814
  __export(database_wrapper_exports, {
@@ -756,7 +875,7 @@ function dateTruncUtc(db, column, bucket) {
756
875
  }
757
876
  } else {
758
877
  return sql`to_char(
759
- date_trunc(${bucket}, ${column} AT TIME ZONE 'UTC'),
878
+ date_trunc(${sql.raw(`'${bucket}'`)}, ${column} AT TIME ZONE 'UTC'),
760
879
  'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'
761
880
  )`;
762
881
  }
@@ -778,12 +897,12 @@ function advisoryLockKeyForUuid(uuid) {
778
897
  const FNV_OFFSET = 0xcbf29ce484222325n;
779
898
  const FNV_PRIME = 0x100000001b3n;
780
899
  const MASK_64 = 0xffffffffffffffffn;
781
- let hash2 = FNV_OFFSET;
900
+ let hash = FNV_OFFSET;
782
901
  for (let i = 0; i < uuid.length; i++) {
783
- hash2 ^= BigInt(uuid.charCodeAt(i));
784
- hash2 = hash2 * FNV_PRIME & MASK_64;
902
+ hash ^= BigInt(uuid.charCodeAt(i));
903
+ hash = hash * FNV_PRIME & MASK_64;
785
904
  }
786
- return hash2 > 0x7fffffffffffffffn ? hash2 - 0x10000000000000000n : hash2;
905
+ return hash > 0x7fffffffffffffffn ? hash - 0x10000000000000000n : hash;
787
906
  }
788
907
  async function executeRaw(db, query) {
789
908
  if (isSQLiteDatabase(db)) {
@@ -811,21 +930,36 @@ async function getOne(db, table, where) {
811
930
  }
812
931
  async function insertOne(db, table, values) {
813
932
  if (isSQLiteDatabase(db)) {
814
- const result = await db.insert(table).values(values).returning();
933
+ const result = await db.insert(table).values(withTenantInsertValues(values, table)).returning();
815
934
  return result;
816
935
  } else {
817
- const result = await db.insert(table).values(values).returning();
936
+ const result = await db.insert(table).values(withTenantInsertValues(values, table)).returning();
818
937
  return result[0];
819
938
  }
820
939
  }
821
- function wrapQuery(query, db) {
940
+ function tableHasTenantColumn(table) {
941
+ return Boolean(table && "tenant_id" in table);
942
+ }
943
+ function withTenantInsertValues(values, table) {
944
+ const tenantId = getCurrentTenantId();
945
+ if (!tenantId || !tableHasTenantColumn(table)) return values;
946
+ const stamp = (row) => {
947
+ if (!row || typeof row !== "object" || Array.isArray(row)) return row;
948
+ if ("tenant_id" in row) return row;
949
+ return { tenant_id: tenantId, ...row };
950
+ };
951
+ return Array.isArray(values) ? values.map(stamp) : stamp(values);
952
+ }
953
+ function wrapQuery(query, db, table) {
822
954
  return {
823
955
  ...query,
824
956
  one: async () => {
825
957
  if (isSQLiteDatabase(db)) {
826
958
  return await query.get();
827
959
  } else {
828
- const results = await query.limit(1);
960
+ const results = await query.limit(
961
+ 1
962
+ );
829
963
  return results[0] || null;
830
964
  }
831
965
  },
@@ -847,30 +981,55 @@ function wrapQuery(query, db) {
847
981
  return { rowsAffected: result.length || 0 };
848
982
  }
849
983
  },
850
- // biome-ignore lint/suspicious/noExplicitAny: Drizzle query builder types vary by dialect
851
984
  returning: () => wrapReturning(query.returning(), db),
852
985
  // Preserve chainable methods
853
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
854
- where: (...args) => wrapQuery(query.where(...args), db),
855
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
856
- limit: (...args) => wrapQuery(query.limit(...args), db),
857
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
858
- offset: (...args) => wrapQuery(query.offset(...args), db),
859
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
860
- orderBy: (...args) => wrapQuery(query.orderBy(...args), db),
861
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
862
- groupBy: (...args) => wrapQuery(query.groupBy(...args), db),
863
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
864
- set: (...args) => wrapQuery(query.set(...args), db),
865
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
866
- values: (...args) => wrapQuery(query.values(...args), db),
867
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
868
- innerJoin: (...args) => wrapQuery(query.innerJoin(...args), db),
869
- // biome-ignore lint/suspicious/noExplicitAny: These methods accept varying argument types from Drizzle
870
- leftJoin: (...args) => wrapQuery(query.leftJoin(...args), db),
871
- onConflictDoNothing: (...args) => (
872
- // biome-ignore lint/suspicious/noExplicitAny: Drizzle exposes onConflictDoNothing on both dialects after .values()
873
- wrapQuery(query.onConflictDoNothing(...args), db)
986
+ where: (...args) => wrapQuery(
987
+ query.where(...args),
988
+ db,
989
+ table
990
+ ),
991
+ limit: (...args) => wrapQuery(
992
+ query.limit(...args),
993
+ db,
994
+ table
995
+ ),
996
+ offset: (...args) => wrapQuery(
997
+ query.offset(...args),
998
+ db,
999
+ table
1000
+ ),
1001
+ orderBy: (...args) => wrapQuery(
1002
+ query.orderBy(...args),
1003
+ db,
1004
+ table
1005
+ ),
1006
+ groupBy: (...args) => wrapQuery(
1007
+ query.groupBy(...args),
1008
+ db,
1009
+ table
1010
+ ),
1011
+ set: (...args) => wrapQuery(query.set(...args), db, table),
1012
+ values: (...args) => wrapQuery(
1013
+ query.values(
1014
+ ...args.map((arg) => withTenantInsertValues(arg, table))
1015
+ ),
1016
+ db,
1017
+ table
1018
+ ),
1019
+ innerJoin: (...args) => wrapQuery(
1020
+ query.innerJoin(...args),
1021
+ db,
1022
+ table
1023
+ ),
1024
+ leftJoin: (...args) => wrapQuery(
1025
+ query.leftJoin(...args),
1026
+ db,
1027
+ table
1028
+ ),
1029
+ onConflictDoNothing: (...args) => wrapQuery(
1030
+ query.onConflictDoNothing(...args),
1031
+ db,
1032
+ table
874
1033
  )
875
1034
  };
876
1035
  }
@@ -903,7 +1062,7 @@ function select(db, columns) {
903
1062
  }
904
1063
  function insert(db, table) {
905
1064
  const query = db.insert(table);
906
- return wrapQuery(query, db);
1065
+ return wrapQuery(query, db, table);
907
1066
  }
908
1067
  function update(db, table) {
909
1068
  const query = db.update(table);
@@ -941,6 +1100,7 @@ var init_database_wrapper = __esm({
941
1100
  "src/db/database-wrapper.ts"() {
942
1101
  "use strict";
943
1102
  init_esm_shims();
1103
+ init_tenant_context();
944
1104
  }
945
1105
  });
946
1106
 
@@ -1145,15 +1305,35 @@ var init_schedule = __esm({
1145
1305
  });
1146
1306
 
1147
1307
  // src/types/session.ts
1308
+ var SessionStatus, EXECUTING_SESSION_STATUSES;
1148
1309
  var init_session = __esm({
1149
1310
  "src/types/session.ts"() {
1150
1311
  "use strict";
1151
1312
  init_esm_shims();
1313
+ SessionStatus = {
1314
+ IDLE: "idle",
1315
+ RUNNING: "running",
1316
+ STOPPING: "stopping",
1317
+ // Stop requested, waiting for task to stop
1318
+ AWAITING_PERMISSION: "awaiting_permission",
1319
+ AWAITING_INPUT: "awaiting_input",
1320
+ // Legacy / pre-#1177: AskUserQuestion was disallowed at the SDK; new sessions never enter this state, kept for historical rows
1321
+ TIMED_OUT: "timed_out",
1322
+ // Permission/input request timed out, executor exited — user must re-prompt
1323
+ COMPLETED: "completed",
1324
+ FAILED: "failed"
1325
+ };
1326
+ EXECUTING_SESSION_STATUSES = /* @__PURE__ */ new Set([
1327
+ SessionStatus.RUNNING,
1328
+ SessionStatus.STOPPING,
1329
+ SessionStatus.AWAITING_PERMISSION,
1330
+ SessionStatus.AWAITING_INPUT
1331
+ ]);
1152
1332
  }
1153
1333
  });
1154
1334
 
1155
1335
  // src/types/task.ts
1156
- var TaskStatus, TERMINAL_TASK_STATUSES;
1336
+ var TaskStatus, TERMINAL_TASK_STATUSES, EXECUTING_TASK_STATUSES;
1157
1337
  var init_task = __esm({
1158
1338
  "src/types/task.ts"() {
1159
1339
  "use strict";
@@ -1181,6 +1361,12 @@ var init_task = __esm({
1181
1361
  TaskStatus.STOPPED,
1182
1362
  TaskStatus.TIMED_OUT
1183
1363
  ]);
1364
+ EXECUTING_TASK_STATUSES = /* @__PURE__ */ new Set([
1365
+ TaskStatus.RUNNING,
1366
+ TaskStatus.STOPPING,
1367
+ TaskStatus.AWAITING_PERMISSION,
1368
+ TaskStatus.AWAITING_INPUT
1369
+ ]);
1184
1370
  }
1185
1371
  });
1186
1372
 
@@ -1192,6 +1378,14 @@ var init_template = __esm({
1192
1378
  }
1193
1379
  });
1194
1380
 
1381
+ // src/types/tenant.ts
1382
+ var init_tenant = __esm({
1383
+ "src/types/tenant.ts"() {
1384
+ "use strict";
1385
+ init_esm_shims();
1386
+ }
1387
+ });
1388
+
1195
1389
  // src/types/ui.ts
1196
1390
  var init_ui = __esm({
1197
1391
  "src/types/ui.ts"() {
@@ -1297,6 +1491,7 @@ var init_types2 = __esm({
1297
1491
  init_session();
1298
1492
  init_task();
1299
1493
  init_template();
1494
+ init_tenant();
1300
1495
  init_ui();
1301
1496
  init_user();
1302
1497
  init_utils();
@@ -1322,6 +1517,7 @@ __export(schema_postgres_exports, {
1322
1517
  cardTypes: () => cardTypes,
1323
1518
  cards: () => cards,
1324
1519
  gatewayChannels: () => gatewayChannels,
1520
+ gatewayOutboundMessages: () => gatewayOutboundMessages,
1325
1521
  groupMemberships: () => groupMemberships,
1326
1522
  groups: () => groups,
1327
1523
  kbDocumentUnits: () => kbDocumentUnits,
@@ -1340,6 +1536,8 @@ __export(schema_postgres_exports, {
1340
1536
  serializedSessions: () => serializedSessions,
1341
1537
  sessionEnvSelections: () => sessionEnvSelections,
1342
1538
  sessionMcpServers: () => sessionMcpServers,
1539
+ sessionRelationships: () => sessionRelationships,
1540
+ sessionRelationshipsRelations: () => sessionRelationshipsRelations,
1343
1541
  sessions: () => sessions,
1344
1542
  sessionsRelations: () => sessionsRelations,
1345
1543
  tasks: () => tasks,
@@ -1363,7 +1561,7 @@ import {
1363
1561
  uniqueIndex,
1364
1562
  varchar
1365
1563
  } from "drizzle-orm/pg-core";
1366
- var bytea, t, sessions, tasks, serializedSessions, messages, boards, repos, branches, branchOwners, boardOwners, schedules, users, groups, groupMemberships, branchGroupGrants, boardGroupGrants, appVariables, userApiKeys, mcpServers, cardTypes, cards, artifacts, artifactTrustGrants, boardObjects, sessionMcpServers, userMcpOauthTokens, boardComments, gatewayChannels, threadSessionMap, sessionEnvSelections, kbNamespaces, kbNamespaceAcl, kbDocuments, kbDocumentVersions, kbDocumentUnits, kbEmbeddingSpaces, kbGraphNodes, kbGraphEdges, sessionsRelations, branchesRelations, schedulesRelations;
1564
+ var bytea, t, sessions, sessionRelationships, tasks, serializedSessions, messages, boards, repos, branches, branchOwners, boardOwners, schedules, users, groups, groupMemberships, branchGroupGrants, boardGroupGrants, appVariables, userApiKeys, mcpServers, cardTypes, cards, artifacts, artifactTrustGrants, boardObjects, sessionMcpServers, userMcpOauthTokens, boardComments, gatewayChannels, threadSessionMap, gatewayOutboundMessages, sessionEnvSelections, kbNamespaces, kbNamespaceAcl, kbDocuments, kbDocumentVersions, kbDocumentUnits, kbEmbeddingSpaces, kbGraphNodes, kbGraphEdges, sessionsRelations, sessionRelationshipsRelations, branchesRelations, schedulesRelations;
1367
1565
  var init_schema_postgres = __esm({
1368
1566
  "src/db/schema.postgres.ts"() {
1369
1567
  "use strict";
@@ -1382,6 +1580,7 @@ var init_schema_postgres = __esm({
1382
1580
  sessions = pgTable(
1383
1581
  "sessions",
1384
1582
  {
1583
+ tenant_id: text("tenant_id").notNull().default("default"),
1385
1584
  // Primary identity
1386
1585
  session_id: varchar("session_id", { length: 36 }).primaryKey(),
1387
1586
  created_at: t.timestamp("created_at").notNull(),
@@ -1441,7 +1640,9 @@ var init_schema_postgres = __esm({
1441
1640
  data: t.json("data").$type().notNull()
1442
1641
  },
1443
1642
  (table) => ({
1643
+ tenantIdx: index("sessions_tenant_id_idx").on(table.tenant_id),
1444
1644
  statusIdx: index("sessions_status_idx").on(table.status),
1645
+ statusReadyIdx: index("sessions_status_ready_idx").on(table.status, table.ready_for_prompt),
1445
1646
  agenticToolIdx: index("sessions_agentic_tool_idx").on(table.agentic_tool),
1446
1647
  boardIdx: index("sessions_board_idx").on(table.board_id),
1447
1648
  branchIdx: index("sessions_branch_idx").on(table.branch_id),
@@ -1453,12 +1654,57 @@ var init_schema_postgres = __esm({
1453
1654
  // Partial unique index — covering for the scheduler's dedup lookup
1454
1655
  // AND serves as the DB-level guard against check-then-create races
1455
1656
  // in spawnScheduledSession.
1456
- scheduleRunUnique: uniqueIndex("sessions_schedule_run_unique").on(table.schedule_id, table.scheduled_run_at).where(sql2`${table.schedule_id} IS NOT NULL AND ${table.scheduled_run_at} IS NOT NULL`)
1657
+ 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`)
1658
+ })
1659
+ );
1660
+ sessionRelationships = pgTable(
1661
+ "session_relationships",
1662
+ {
1663
+ tenant_id: text("tenant_id").notNull().default("default"),
1664
+ relationship_id: varchar("relationship_id", { length: 36 }).primaryKey(),
1665
+ source_session_id: varchar("source_session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
1666
+ target_session_id: varchar("target_session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
1667
+ relationship_type: text("relationship_type", { enum: ["remote_create"] }).notNull(),
1668
+ created_by: varchar("created_by", { length: 36 }).notNull(),
1669
+ created_at: t.timestamp("created_at").notNull(),
1670
+ updated_at: t.timestamp("updated_at"),
1671
+ callback_enabled: t.bool("callback_enabled").notNull().default(false),
1672
+ callback_session_id: varchar("callback_session_id", { length: 36 }).references(
1673
+ () => sessions.session_id,
1674
+ {
1675
+ onDelete: "set null"
1676
+ }
1677
+ ),
1678
+ data: t.json("data")
1679
+ },
1680
+ (table) => ({
1681
+ tenantIdx: index("session_relationships_tenant_id_idx").on(table.tenant_id),
1682
+ sourceIdx: index("session_relationships_source_idx").on(table.source_session_id),
1683
+ targetIdx: index("session_relationships_target_idx").on(table.target_session_id),
1684
+ callbackIdx: index("session_relationships_callback_idx").on(table.callback_session_id),
1685
+ // Composite indexes so the OR predicate in dispatchCompletionCallbacks
1686
+ // (WHERE source_session_id = $1 OR target_session_id = $2) uses BitmapOr
1687
+ // over these instead of a full tenant table scan via tenant_id_idx.
1688
+ tenantSourceIdx: index("session_relationships_tenant_source_idx").on(
1689
+ table.tenant_id,
1690
+ table.source_session_id
1691
+ ),
1692
+ tenantTargetIdx: index("session_relationships_tenant_target_idx").on(
1693
+ table.tenant_id,
1694
+ table.target_session_id
1695
+ ),
1696
+ sourceTargetTypeUnique: uniqueIndex("session_relationships_source_target_type_unique").on(
1697
+ table.tenant_id,
1698
+ table.source_session_id,
1699
+ table.target_session_id,
1700
+ table.relationship_type
1701
+ )
1457
1702
  })
1458
1703
  );
1459
1704
  tasks = pgTable(
1460
1705
  "tasks",
1461
1706
  {
1707
+ tenant_id: text("tenant_id").notNull().default("default"),
1462
1708
  task_id: varchar("task_id", { length: 36 }).primaryKey(),
1463
1709
  session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
1464
1710
  created_at: t.timestamp("created_at").notNull(),
@@ -1488,19 +1734,23 @@ var init_schema_postgres = __esm({
1488
1734
  data: t.json("data").$type().notNull()
1489
1735
  },
1490
1736
  (table) => ({
1737
+ tenantIdx: index("tasks_tenant_id_idx").on(table.tenant_id),
1491
1738
  sessionIdx: index("tasks_session_idx").on(table.session_id),
1492
1739
  statusIdx: index("tasks_status_idx").on(table.status),
1493
1740
  createdIdx: index("tasks_created_idx").on(table.created_at),
1741
+ // Composite for "latest task for session" queries (ORDER BY created_at DESC LIMIT 1).
1742
+ sessionCreatedIdx: index("tasks_session_created_idx").on(table.session_id, table.created_at),
1494
1743
  queueIdx: index("tasks_queue_idx").on(table.session_id, table.status, table.queue_position),
1495
1744
  // Partial unique index — defense-in-depth for `tasks.createPending` race
1496
1745
  // serialization. Only QUEUED rows are constrained; CREATED/RUNNING/done
1497
1746
  // rows have NULL queue_position and are unaffected.
1498
- queuedPositionUnique: uniqueIndex("tasks_queued_position_unique").on(table.session_id, table.queue_position).where(sql2`${table.status} = 'queued'`)
1747
+ queuedPositionUnique: uniqueIndex("tasks_queued_position_unique").on(table.tenant_id, table.session_id, table.queue_position).where(sql2`${table.status} = 'queued'`)
1499
1748
  })
1500
1749
  );
1501
1750
  serializedSessions = pgTable(
1502
1751
  "serialized_sessions",
1503
1752
  {
1753
+ tenant_id: text("tenant_id").notNull().default("default"),
1504
1754
  id: varchar("id", { length: 36 }).primaryKey(),
1505
1755
  session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
1506
1756
  branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
@@ -1516,6 +1766,7 @@ var init_schema_postgres = __esm({
1516
1766
  // gzipped; NULL while status='processing'
1517
1767
  },
1518
1768
  (table) => ({
1769
+ tenantIdx: index("serialized_sessions_tenant_id_idx").on(table.tenant_id),
1519
1770
  sessionTurnIdx: index("serialized_sessions_session_turn_idx").on(
1520
1771
  table.session_id,
1521
1772
  table.turn_index
@@ -1526,6 +1777,7 @@ var init_schema_postgres = __esm({
1526
1777
  messages = pgTable(
1527
1778
  "messages",
1528
1779
  {
1780
+ tenant_id: text("tenant_id").notNull().default("default"),
1529
1781
  // Primary identity
1530
1782
  message_id: varchar("message_id", { length: 36 }).primaryKey(),
1531
1783
  created_at: t.timestamp("created_at").notNull(),
@@ -1565,15 +1817,23 @@ var init_schema_postgres = __esm({
1565
1817
  data: t.json("data").$type().notNull()
1566
1818
  },
1567
1819
  (table) => ({
1820
+ tenantIdx: index("messages_tenant_id_idx").on(table.tenant_id),
1821
+ tenantTimestampIdx: index("messages_tenant_timestamp_idx").on(table.tenant_id, table.timestamp),
1568
1822
  // Indexes for efficient lookups
1569
1823
  sessionIdx: index("messages_session_id_idx").on(table.session_id),
1570
1824
  taskIdx: index("messages_task_id_idx").on(table.task_id),
1571
- sessionIndexIdx: index("messages_session_index_idx").on(table.session_id, table.index)
1825
+ sessionIndexIdx: index("messages_session_index_idx").on(table.session_id, table.index),
1826
+ timestampIdx: index("messages_timestamp_idx").on(table.timestamp),
1827
+ sessionTimestampIdx: index("messages_session_timestamp_idx").on(
1828
+ table.session_id,
1829
+ table.timestamp
1830
+ )
1572
1831
  })
1573
1832
  );
1574
1833
  boards = pgTable(
1575
1834
  "boards",
1576
1835
  {
1836
+ tenant_id: text("tenant_id").notNull().default("default"),
1577
1837
  board_id: varchar("board_id", { length: 36 }).primaryKey(),
1578
1838
  created_at: t.timestamp("created_at").notNull(),
1579
1839
  updated_at: t.timestamp("updated_at"),
@@ -1581,7 +1841,7 @@ var init_schema_postgres = __esm({
1581
1841
  created_by: varchar("created_by", { length: 36 }).notNull(),
1582
1842
  // Materialized for lookups
1583
1843
  name: text("name").notNull(),
1584
- slug: text("slug").unique(),
1844
+ slug: text("slug"),
1585
1845
  primary_assistant_id: varchar("primary_assistant_id", { length: 36 }).references(
1586
1846
  () => branches.branch_id,
1587
1847
  {
@@ -1596,18 +1856,21 @@ var init_schema_postgres = __esm({
1596
1856
  archived_by: varchar("archived_by", { length: 36 })
1597
1857
  },
1598
1858
  (table) => ({
1859
+ tenantIdx: index("boards_tenant_id_idx").on(table.tenant_id),
1599
1860
  nameIdx: index("boards_name_idx").on(table.name),
1600
- slugIdx: index("boards_slug_idx").on(table.slug)
1861
+ slugIdx: index("boards_slug_idx").on(table.slug),
1862
+ slugTenantUnique: uniqueIndex("boards_tenant_slug_unique").on(table.tenant_id, table.slug)
1601
1863
  })
1602
1864
  );
1603
1865
  repos = pgTable(
1604
1866
  "repos",
1605
1867
  {
1868
+ tenant_id: text("tenant_id").notNull().default("default"),
1606
1869
  repo_id: varchar("repo_id", { length: 36 }).primaryKey(),
1607
1870
  created_at: t.timestamp("created_at").notNull(),
1608
1871
  updated_at: t.timestamp("updated_at"),
1609
1872
  // Materialized for querying
1610
- slug: text("slug").notNull().unique(),
1873
+ slug: text("slug").notNull(),
1611
1874
  repo_type: text("repo_type", { enum: ["remote", "local"] }).notNull().default("remote"),
1612
1875
  // Unix group for repo-level git access (agor_rp_<short-id>)
1613
1876
  // Users who have access to ANY branch in this repo get added to this group.
@@ -1618,12 +1881,15 @@ var init_schema_postgres = __esm({
1618
1881
  data: t.json("data").$type().notNull()
1619
1882
  },
1620
1883
  (table) => ({
1621
- slugIdx: index("repos_slug_idx").on(table.slug)
1884
+ tenantIdx: index("repos_tenant_id_idx").on(table.tenant_id),
1885
+ slugIdx: index("repos_slug_idx").on(table.slug),
1886
+ slugTenantUnique: uniqueIndex("repos_tenant_slug_unique").on(table.tenant_id, table.slug)
1622
1887
  })
1623
1888
  );
1624
1889
  branches = pgTable(
1625
1890
  "branches",
1626
1891
  {
1892
+ tenant_id: text("tenant_id").notNull().default("default"),
1627
1893
  // Primary identity
1628
1894
  branch_id: varchar("branch_id", { length: 36 }).primaryKey(),
1629
1895
  repo_id: varchar("repo_id", { length: 36 }).notNull().references(() => repos.repo_id, { onDelete: "cascade" }),
@@ -1698,6 +1964,7 @@ var init_schema_postgres = __esm({
1698
1964
  data: t.json("data").$type().notNull()
1699
1965
  },
1700
1966
  (table) => ({
1967
+ tenantIdx: index("branches_tenant_id_idx").on(table.tenant_id),
1701
1968
  repoIdx: index("branches_repo_idx").on(table.repo_id),
1702
1969
  nameIdx: index("branches_name_idx").on(table.name),
1703
1970
  refIdx: index("branches_ref_idx").on(table.ref),
@@ -1711,22 +1978,26 @@ var init_schema_postgres = __esm({
1711
1978
  branchOwners = pgTable(
1712
1979
  "branch_owners",
1713
1980
  {
1981
+ tenant_id: text("tenant_id").notNull().default("default"),
1714
1982
  branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
1715
1983
  user_id: varchar("user_id", { length: 36 }).notNull().references(() => users.user_id, { onDelete: "cascade" }),
1716
1984
  created_at: t.timestamp("created_at").defaultNow()
1717
1985
  },
1718
1986
  (table) => ({
1987
+ tenantIdx: index("branch_owners_tenant_id_idx").on(table.tenant_id),
1719
1988
  pk: primaryKey({ columns: [table.branch_id, table.user_id] })
1720
1989
  })
1721
1990
  );
1722
1991
  boardOwners = pgTable(
1723
1992
  "board_owners",
1724
1993
  {
1994
+ tenant_id: text("tenant_id").notNull().default("default"),
1725
1995
  board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
1726
1996
  user_id: varchar("user_id", { length: 36 }).notNull().references(() => users.user_id, { onDelete: "cascade" }),
1727
1997
  created_at: t.timestamp("created_at")
1728
1998
  },
1729
1999
  (table) => ({
2000
+ tenantIdx: index("board_owners_tenant_id_idx").on(table.tenant_id),
1730
2001
  pk: primaryKey({ columns: [table.board_id, table.user_id] }),
1731
2002
  userIdx: index("board_owners_user_idx").on(table.user_id)
1732
2003
  })
@@ -1734,6 +2005,7 @@ var init_schema_postgres = __esm({
1734
2005
  schedules = pgTable(
1735
2006
  "schedules",
1736
2007
  {
2008
+ tenant_id: text("tenant_id").notNull().default("default"),
1737
2009
  schedule_id: varchar("schedule_id", { length: 36 }).primaryKey(),
1738
2010
  branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
1739
2011
  name: text("name").notNull(),
@@ -1757,6 +2029,7 @@ var init_schema_postgres = __esm({
1757
2029
  created_by: varchar("created_by", { length: 36 }).notNull().references(() => users.user_id)
1758
2030
  },
1759
2031
  (table) => ({
2032
+ tenantIdx: index("schedules_tenant_id_idx").on(table.tenant_id),
1760
2033
  enabledNextRunIdx: index("schedules_enabled_next_run_idx").on(table.enabled, table.next_run_at),
1761
2034
  branchIdx: index("schedules_branch_idx").on(table.branch_id),
1762
2035
  createdByIdx: index("schedules_created_by_idx").on(table.created_by)
@@ -1765,12 +2038,13 @@ var init_schema_postgres = __esm({
1765
2038
  users = pgTable(
1766
2039
  "users",
1767
2040
  {
2041
+ tenant_id: text("tenant_id").notNull().default("default"),
1768
2042
  // Primary identity
1769
2043
  user_id: varchar("user_id", { length: 36 }).primaryKey(),
1770
2044
  created_at: t.timestamp("created_at").notNull(),
1771
2045
  updated_at: t.timestamp("updated_at"),
1772
2046
  // Materialized for auth lookups
1773
- email: text("email").unique().notNull(),
2047
+ email: text("email").notNull(),
1774
2048
  password: text("password").notNull(),
1775
2049
  // bcrypt hashed
1776
2050
  // Basic profile (materialized for display)
@@ -1786,16 +2060,22 @@ var init_schema_postgres = __esm({
1786
2060
  onboarding_completed: t.bool("onboarding_completed").notNull().default(false),
1787
2061
  // Force password change flag (admin-settable, auto-cleared on password change)
1788
2062
  must_change_password: t.bool("must_change_password").notNull().default(false),
2063
+ // Auth invalidation marker. Password changes set this timestamp so any
2064
+ // previously issued browser access or refresh token is rejected.
2065
+ tokens_valid_after: t.timestamp("tokens_valid_after"),
1789
2066
  // JSON blob for profile/preferences
1790
2067
  data: t.json("data").$type().notNull()
1791
2068
  },
1792
2069
  (table) => ({
1793
- emailIdx: index("users_email_idx").on(table.email)
2070
+ tenantIdx: index("users_tenant_id_idx").on(table.tenant_id),
2071
+ emailIdx: index("users_email_idx").on(table.email),
2072
+ emailTenantUnique: uniqueIndex("users_tenant_email_unique").on(table.tenant_id, table.email)
1794
2073
  })
1795
2074
  );
1796
2075
  groups = pgTable(
1797
2076
  "groups",
1798
2077
  {
2078
+ tenant_id: text("tenant_id").notNull().default("default"),
1799
2079
  group_id: varchar("group_id", { length: 36 }).primaryKey(),
1800
2080
  name: text("name").notNull(),
1801
2081
  slug: text("slug").notNull(),
@@ -1808,13 +2088,15 @@ var init_schema_postgres = __esm({
1808
2088
  updated_at: t.timestamp("updated_at")
1809
2089
  },
1810
2090
  (table) => ({
1811
- slugIdx: uniqueIndex("groups_slug_idx").on(table.slug),
2091
+ tenantIdx: index("groups_tenant_id_idx").on(table.tenant_id),
2092
+ slugIdx: uniqueIndex("groups_tenant_slug_unique").on(table.tenant_id, table.slug),
1812
2093
  archivedIdx: index("groups_archived_idx").on(table.archived)
1813
2094
  })
1814
2095
  );
1815
2096
  groupMemberships = pgTable(
1816
2097
  "group_memberships",
1817
2098
  {
2099
+ tenant_id: text("tenant_id").notNull().default("default"),
1818
2100
  group_id: varchar("group_id", { length: 36 }).notNull().references(() => groups.group_id, { onDelete: "cascade" }),
1819
2101
  user_id: varchar("user_id", { length: 36 }).notNull().references(() => users.user_id, { onDelete: "cascade" }),
1820
2102
  added_by: varchar("added_by", { length: 36 }).references(() => users.user_id, {
@@ -1823,6 +2105,7 @@ var init_schema_postgres = __esm({
1823
2105
  created_at: t.timestamp("created_at").notNull()
1824
2106
  },
1825
2107
  (table) => ({
2108
+ tenantIdx: index("group_memberships_tenant_id_idx").on(table.tenant_id),
1826
2109
  pk: primaryKey({ columns: [table.group_id, table.user_id] }),
1827
2110
  userIdx: index("group_memberships_user_idx").on(table.user_id)
1828
2111
  })
@@ -1830,6 +2113,7 @@ var init_schema_postgres = __esm({
1830
2113
  branchGroupGrants = pgTable(
1831
2114
  "branch_group_grants",
1832
2115
  {
2116
+ tenant_id: text("tenant_id").notNull().default("default"),
1833
2117
  branch_id: varchar("branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
1834
2118
  group_id: varchar("group_id", { length: 36 }).notNull().references(() => groups.group_id, { onDelete: "cascade" }),
1835
2119
  can: text("can", { enum: [...BRANCH_PERMISSION_LEVELS] }).notNull().default("view"),
@@ -1841,6 +2125,7 @@ var init_schema_postgres = __esm({
1841
2125
  updated_at: t.timestamp("updated_at")
1842
2126
  },
1843
2127
  (table) => ({
2128
+ tenantIdx: index("branch_group_grants_tenant_id_idx").on(table.tenant_id),
1844
2129
  pk: primaryKey({ columns: [table.branch_id, table.group_id] }),
1845
2130
  groupIdx: index("branch_group_grants_group_idx").on(table.group_id)
1846
2131
  })
@@ -1848,6 +2133,7 @@ var init_schema_postgres = __esm({
1848
2133
  boardGroupGrants = pgTable(
1849
2134
  "board_group_grants",
1850
2135
  {
2136
+ tenant_id: text("tenant_id").notNull().default("default"),
1851
2137
  board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
1852
2138
  group_id: varchar("group_id", { length: 36 }).notNull().references(() => groups.group_id, { onDelete: "cascade" }),
1853
2139
  can: text("can", { enum: [...BRANCH_PERMISSION_LEVELS] }).notNull().default("view"),
@@ -1859,6 +2145,7 @@ var init_schema_postgres = __esm({
1859
2145
  updated_at: t.timestamp("updated_at")
1860
2146
  },
1861
2147
  (table) => ({
2148
+ tenantIdx: index("board_group_grants_tenant_id_idx").on(table.tenant_id),
1862
2149
  pk: primaryKey({ columns: [table.board_id, table.group_id] }),
1863
2150
  groupIdx: index("board_group_grants_group_idx").on(table.group_id)
1864
2151
  })
@@ -1866,6 +2153,7 @@ var init_schema_postgres = __esm({
1866
2153
  appVariables = pgTable(
1867
2154
  "app_variables",
1868
2155
  {
2156
+ tenant_id: text("tenant_id").notNull().default("default"),
1869
2157
  variable_id: varchar("variable_id", { length: 36 }).primaryKey(),
1870
2158
  namespace: text("namespace").notNull(),
1871
2159
  key: text("key").notNull(),
@@ -1881,13 +2169,19 @@ var init_schema_postgres = __esm({
1881
2169
  updated_at: t.timestamp("updated_at").notNull()
1882
2170
  },
1883
2171
  (table) => ({
1884
- namespaceKeyIdx: uniqueIndex("app_variables_namespace_key_idx").on(table.namespace, table.key),
2172
+ tenantIdx: index("app_variables_tenant_id_idx").on(table.tenant_id),
2173
+ namespaceKeyIdx: uniqueIndex("app_variables_tenant_namespace_key_unique").on(
2174
+ table.tenant_id,
2175
+ table.namespace,
2176
+ table.key
2177
+ ),
1885
2178
  namespaceIdx: index("app_variables_namespace_idx").on(table.namespace)
1886
2179
  })
1887
2180
  );
1888
2181
  userApiKeys = pgTable(
1889
2182
  "user_api_keys",
1890
2183
  {
2184
+ tenant_id: text("tenant_id").notNull().default("default"),
1891
2185
  id: varchar("id", { length: 36 }).primaryKey(),
1892
2186
  user_id: varchar("user_id", { length: 36 }).notNull().references(() => users.user_id, { onDelete: "cascade" }),
1893
2187
  name: text("name").notNull(),
@@ -1899,6 +2193,7 @@ var init_schema_postgres = __esm({
1899
2193
  last_used_at: t.timestamp("last_used_at")
1900
2194
  },
1901
2195
  (table) => ({
2196
+ tenantIdx: index("user_api_keys_tenant_id_idx").on(table.tenant_id),
1902
2197
  userIdx: index("user_api_keys_user_idx").on(table.user_id),
1903
2198
  prefixIdx: index("user_api_keys_prefix_idx").on(table.prefix)
1904
2199
  })
@@ -1906,6 +2201,7 @@ var init_schema_postgres = __esm({
1906
2201
  mcpServers = pgTable(
1907
2202
  "mcp_servers",
1908
2203
  {
2204
+ tenant_id: text("tenant_id").notNull().default("default"),
1909
2205
  // Primary identity
1910
2206
  mcp_server_id: varchar("mcp_server_id", { length: 36 }).primaryKey(),
1911
2207
  created_at: t.timestamp("created_at").notNull(),
@@ -1932,6 +2228,7 @@ var init_schema_postgres = __esm({
1932
2228
  data: t.json("data").$type().notNull()
1933
2229
  },
1934
2230
  (table) => ({
2231
+ tenantIdx: index("mcp_servers_tenant_id_idx").on(table.tenant_id),
1935
2232
  nameIdx: index("mcp_servers_name_idx").on(table.name),
1936
2233
  scopeIdx: index("mcp_servers_scope_idx").on(table.scope),
1937
2234
  ownerIdx: index("mcp_servers_owner_idx").on(table.owner_user_id),
@@ -1941,6 +2238,7 @@ var init_schema_postgres = __esm({
1941
2238
  cardTypes = pgTable(
1942
2239
  "card_types",
1943
2240
  {
2241
+ tenant_id: text("tenant_id").notNull().default("default"),
1944
2242
  card_type_id: varchar("card_type_id", { length: 36 }).primaryKey(),
1945
2243
  name: text("name").notNull(),
1946
2244
  emoji: text("emoji"),
@@ -1952,12 +2250,14 @@ var init_schema_postgres = __esm({
1952
2250
  updated_at: t.timestamp("updated_at").notNull()
1953
2251
  },
1954
2252
  (table) => ({
2253
+ tenantIdx: index("card_types_tenant_id_idx").on(table.tenant_id),
1955
2254
  nameIdx: index("card_types_name_idx").on(table.name)
1956
2255
  })
1957
2256
  );
1958
2257
  cards = pgTable(
1959
2258
  "cards",
1960
2259
  {
2260
+ tenant_id: text("tenant_id").notNull().default("default"),
1961
2261
  card_id: varchar("card_id", { length: 36 }).primaryKey(),
1962
2262
  board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
1963
2263
  card_type_id: varchar("card_type_id", { length: 36 }).references(() => cardTypes.card_type_id, {
@@ -1978,6 +2278,7 @@ var init_schema_postgres = __esm({
1978
2278
  archived_at: t.timestamp("archived_at")
1979
2279
  },
1980
2280
  (table) => ({
2281
+ tenantIdx: index("cards_tenant_id_idx").on(table.tenant_id),
1981
2282
  boardIdx: index("cards_board_idx").on(table.board_id),
1982
2283
  cardTypeIdx: index("cards_card_type_idx").on(table.card_type_id),
1983
2284
  titleIdx: index("cards_title_idx").on(table.title),
@@ -1988,10 +2289,17 @@ var init_schema_postgres = __esm({
1988
2289
  artifacts = pgTable(
1989
2290
  "artifacts",
1990
2291
  {
2292
+ tenant_id: text("tenant_id").notNull().default("default"),
1991
2293
  artifact_id: varchar("artifact_id", { length: 36 }).primaryKey(),
1992
2294
  branch_id: varchar("branch_id", { length: 36 }).references(() => branches.branch_id, {
1993
2295
  onDelete: "set null"
1994
2296
  }),
2297
+ source_session_id: varchar("source_session_id", { length: 36 }).references(
2298
+ () => sessions.session_id,
2299
+ {
2300
+ onDelete: "set null"
2301
+ }
2302
+ ),
1995
2303
  board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
1996
2304
  name: text("name").notNull(),
1997
2305
  description: text("description"),
@@ -2017,7 +2325,9 @@ var init_schema_postgres = __esm({
2017
2325
  archived_at: t.timestamp("archived_at")
2018
2326
  },
2019
2327
  (table) => ({
2328
+ tenantIdx: index("artifacts_tenant_id_idx").on(table.tenant_id),
2020
2329
  branchIdx: index("artifacts_branch_idx").on(table.branch_id),
2330
+ sourceSessionIdx: index("artifacts_source_session_idx").on(table.source_session_id),
2021
2331
  boardIdx: index("artifacts_board_idx").on(table.board_id),
2022
2332
  archivedIdx: index("artifacts_archived_idx").on(table.archived),
2023
2333
  publicIdx: index("artifacts_public_idx").on(table.public)
@@ -2026,6 +2336,7 @@ var init_schema_postgres = __esm({
2026
2336
  artifactTrustGrants = pgTable(
2027
2337
  "artifact_trust_grants",
2028
2338
  {
2339
+ tenant_id: text("tenant_id").notNull().default("default"),
2029
2340
  grant_id: varchar("grant_id", { length: 36 }).primaryKey(),
2030
2341
  user_id: varchar("user_id", { length: 36 }).notNull(),
2031
2342
  scope_type: text("scope_type").notNull(),
@@ -2036,6 +2347,7 @@ var init_schema_postgres = __esm({
2036
2347
  revoked_at: t.timestamp("revoked_at")
2037
2348
  },
2038
2349
  (table) => ({
2350
+ tenantIdx: index("artifact_trust_grants_tenant_id_idx").on(table.tenant_id),
2039
2351
  userIdx: index("artifact_trust_grants_user_idx").on(table.user_id),
2040
2352
  scopeIdx: index("artifact_trust_grants_scope_idx").on(table.scope_type, table.scope_value)
2041
2353
  })
@@ -2043,6 +2355,7 @@ var init_schema_postgres = __esm({
2043
2355
  boardObjects = pgTable(
2044
2356
  "board_objects",
2045
2357
  {
2358
+ tenant_id: text("tenant_id").notNull().default("default"),
2046
2359
  // Primary identity
2047
2360
  object_id: varchar("object_id", { length: 36 }).primaryKey(),
2048
2361
  board_id: varchar("board_id", { length: 36 }).notNull().references(() => boards.board_id, { onDelete: "cascade" }),
@@ -2058,6 +2371,7 @@ var init_schema_postgres = __esm({
2058
2371
  data: t.json("data").$type().notNull()
2059
2372
  },
2060
2373
  (table) => ({
2374
+ tenantIdx: index("board_objects_tenant_id_idx").on(table.tenant_id),
2061
2375
  boardIdx: index("board_objects_board_idx").on(table.board_id),
2062
2376
  branchIdx: index("board_objects_branch_idx").on(table.branch_id),
2063
2377
  cardIdx: index("board_objects_card_idx").on(table.card_id)
@@ -2066,12 +2380,14 @@ var init_schema_postgres = __esm({
2066
2380
  sessionMcpServers = pgTable(
2067
2381
  "session_mcp_servers",
2068
2382
  {
2383
+ tenant_id: text("tenant_id").notNull().default("default"),
2069
2384
  session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
2070
2385
  mcp_server_id: varchar("mcp_server_id", { length: 36 }).notNull().references(() => mcpServers.mcp_server_id, { onDelete: "cascade" }),
2071
2386
  enabled: t.bool("enabled").notNull().default(true),
2072
2387
  added_at: t.timestamp("added_at").notNull()
2073
2388
  },
2074
2389
  (table) => ({
2390
+ tenantIdx: index("session_mcp_servers_tenant_id_idx").on(table.tenant_id),
2075
2391
  // Composite primary key
2076
2392
  pk: index("session_mcp_servers_pk").on(table.session_id, table.mcp_server_id),
2077
2393
  // Indexes for queries
@@ -2083,6 +2399,7 @@ var init_schema_postgres = __esm({
2083
2399
  userMcpOauthTokens = pgTable(
2084
2400
  "user_mcp_oauth_tokens",
2085
2401
  {
2402
+ tenant_id: text("tenant_id").notNull().default("default"),
2086
2403
  // NULL = shared-mode token (one per mcp_server_id)
2087
2404
  user_id: varchar("user_id", { length: 36 }).references(() => users.user_id, {
2088
2405
  onDelete: "cascade"
@@ -2100,6 +2417,7 @@ var init_schema_postgres = __esm({
2100
2417
  updated_at: t.timestamp("updated_at")
2101
2418
  },
2102
2419
  (table) => ({
2420
+ tenantIdx: index("user_mcp_oauth_tokens_tenant_id_idx").on(table.tenant_id),
2103
2421
  // Composite lookup indexes. Uniqueness enforced via partial unique indexes
2104
2422
  // created in the migration (one for per-user rows, one for the shared row).
2105
2423
  pk: index("user_mcp_oauth_tokens_pk").on(table.user_id, table.mcp_server_id),
@@ -2110,6 +2428,7 @@ var init_schema_postgres = __esm({
2110
2428
  boardComments = pgTable(
2111
2429
  "board_comments",
2112
2430
  {
2431
+ tenant_id: text("tenant_id").notNull().default("default"),
2113
2432
  // Primary identity
2114
2433
  comment_id: varchar("comment_id", { length: 36 }).primaryKey(),
2115
2434
  created_at: t.timestamp("created_at").notNull(),
@@ -2151,6 +2470,7 @@ var init_schema_postgres = __esm({
2151
2470
  data: t.json("data").$type().notNull()
2152
2471
  },
2153
2472
  (table) => ({
2473
+ tenantIdx: index("board_comments_tenant_id_idx").on(table.tenant_id),
2154
2474
  boardIdx: index("board_comments_board_idx").on(table.board_id),
2155
2475
  sessionIdx: index("board_comments_session_idx").on(table.session_id),
2156
2476
  taskIdx: index("board_comments_task_idx").on(table.task_id),
@@ -2165,6 +2485,7 @@ var init_schema_postgres = __esm({
2165
2485
  gatewayChannels = pgTable(
2166
2486
  "gateway_channels",
2167
2487
  {
2488
+ tenant_id: text("tenant_id").notNull().default("default"),
2168
2489
  // Primary identity
2169
2490
  id: varchar("id", { length: 36 }).primaryKey(),
2170
2491
  created_at: t.timestamp("created_at").notNull(),
@@ -2174,11 +2495,11 @@ var init_schema_postgres = __esm({
2174
2495
  // Materialized for queries
2175
2496
  name: text("name").notNull(),
2176
2497
  channel_type: text("channel_type", {
2177
- enum: ["slack", "discord", "whatsapp", "telegram", "github"]
2498
+ enum: ["slack", "discord", "whatsapp", "telegram", "github", "teams"]
2178
2499
  }).notNull(),
2179
2500
  target_branch_id: varchar("target_branch_id", { length: 36 }).notNull().references(() => branches.branch_id, { onDelete: "cascade" }),
2180
2501
  agor_user_id: varchar("agor_user_id", { length: 36 }).notNull(),
2181
- channel_key: text("channel_key").notNull().unique(),
2502
+ channel_key: text("channel_key").notNull(),
2182
2503
  enabled: t.bool("enabled").notNull().default(true),
2183
2504
  last_message_at: t.timestamp("last_message_at"),
2184
2505
  // JSON blob for platform credentials (encrypted at rest)
@@ -2187,13 +2508,19 @@ var init_schema_postgres = __esm({
2187
2508
  agentic_config: t.json("agentic_config")
2188
2509
  },
2189
2510
  (table) => ({
2511
+ tenantIdx: index("gateway_channels_tenant_id_idx").on(table.tenant_id),
2190
2512
  channelKeyIdx: index("idx_gateway_channel_key").on(table.channel_key),
2513
+ channelKeyTenantUnique: uniqueIndex("gateway_channels_tenant_channel_key_unique").on(
2514
+ table.tenant_id,
2515
+ table.channel_key
2516
+ ),
2191
2517
  enabledTypeIdx: index("idx_gateway_enabled_type").on(table.enabled, table.channel_type)
2192
2518
  })
2193
2519
  );
2194
2520
  threadSessionMap = pgTable(
2195
2521
  "thread_session_map",
2196
2522
  {
2523
+ tenant_id: text("tenant_id").notNull().default("default"),
2197
2524
  // Primary identity
2198
2525
  id: varchar("id", { length: 36 }).primaryKey(),
2199
2526
  created_at: t.timestamp("created_at").notNull(),
@@ -2211,7 +2538,9 @@ var init_schema_postgres = __esm({
2211
2538
  metadata: t.json("metadata")
2212
2539
  },
2213
2540
  (table) => ({
2214
- uniqueChannelThread: uniqueIndex("uniq_thread_map_channel_thread").on(
2541
+ tenantIdx: index("thread_session_map_tenant_id_idx").on(table.tenant_id),
2542
+ uniqueChannelThread: uniqueIndex("uniq_thread_map_tenant_channel_thread").on(
2543
+ table.tenant_id,
2215
2544
  table.channel_id,
2216
2545
  table.thread_id
2217
2546
  ),
@@ -2220,14 +2549,82 @@ var init_schema_postgres = __esm({
2220
2549
  channelStatusIdx: index("idx_thread_map_channel_status").on(table.channel_id, table.status)
2221
2550
  })
2222
2551
  );
2552
+ gatewayOutboundMessages = pgTable(
2553
+ "gateway_outbound_messages",
2554
+ {
2555
+ tenant_id: text("tenant_id").notNull().default("default"),
2556
+ id: varchar("id", { length: 36 }).primaryKey(),
2557
+ created_at: t.timestamp("created_at").notNull(),
2558
+ updated_at: t.timestamp("updated_at").notNull(),
2559
+ gateway_channel_id: varchar("gateway_channel_id", { length: 36 }).notNull().references(() => gatewayChannels.id, { onDelete: "cascade" }),
2560
+ channel_type: text("channel_type", {
2561
+ enum: ["slack", "discord", "whatsapp", "telegram", "github", "teams"]
2562
+ }).notNull(),
2563
+ platform_channel_id: text("platform_channel_id").notNull(),
2564
+ platform_message_id: text("platform_message_id").notNull(),
2565
+ platform_thread_id: text("platform_thread_id").notNull(),
2566
+ platform_permalink: text("platform_permalink"),
2567
+ target_branch_id: varchar("target_branch_id", { length: 36 }).notNull().references(() => branches.branch_id),
2568
+ emitted_by_user_id: varchar("emitted_by_user_id", { length: 36 }).notNull().references(() => users.user_id),
2569
+ emitted_by_session_id: varchar("emitted_by_session_id", { length: 36 }).references(
2570
+ () => sessions.session_id,
2571
+ {
2572
+ onDelete: "set null"
2573
+ }
2574
+ ),
2575
+ emitted_by_task_id: varchar("emitted_by_task_id", { length: 36 }).references(
2576
+ () => tasks.task_id,
2577
+ {
2578
+ onDelete: "set null"
2579
+ }
2580
+ ),
2581
+ emitted_by_schedule_id: varchar("emitted_by_schedule_id", { length: 36 }).references(
2582
+ () => schedules.schedule_id,
2583
+ {
2584
+ onDelete: "set null"
2585
+ }
2586
+ ),
2587
+ message_text: text("message_text").notNull(),
2588
+ message_preview: text("message_preview").notNull(),
2589
+ metadata: t.json("metadata"),
2590
+ consumed_by_session_id: varchar("consumed_by_session_id", { length: 36 }).references(
2591
+ () => sessions.session_id,
2592
+ {
2593
+ onDelete: "set null"
2594
+ }
2595
+ ),
2596
+ consumed_at: t.timestamp("consumed_at")
2597
+ },
2598
+ (table) => ({
2599
+ tenantIdx: index("gateway_outbound_messages_tenant_id_idx").on(table.tenant_id),
2600
+ uniqueChannelThread: uniqueIndex("uniq_gateway_outbound_tenant_channel_thread").on(
2601
+ table.tenant_id,
2602
+ table.gateway_channel_id,
2603
+ table.platform_thread_id
2604
+ ),
2605
+ emittedSessionIdx: index("idx_gateway_outbound_emitted_session").on(
2606
+ table.emitted_by_session_id
2607
+ ),
2608
+ emittedScheduleIdx: index("idx_gateway_outbound_emitted_schedule").on(
2609
+ table.emitted_by_schedule_id
2610
+ ),
2611
+ targetBranchCreatedIdx: index("idx_gateway_outbound_branch_created").on(
2612
+ table.target_branch_id,
2613
+ table.created_at
2614
+ ),
2615
+ consumedIdx: index("idx_gateway_outbound_consumed").on(table.consumed_at)
2616
+ })
2617
+ );
2223
2618
  sessionEnvSelections = pgTable(
2224
2619
  "session_env_selections",
2225
2620
  {
2621
+ tenant_id: text("tenant_id").notNull().default("default"),
2226
2622
  session_id: varchar("session_id", { length: 36 }).notNull().references(() => sessions.session_id, { onDelete: "cascade" }),
2227
2623
  env_var_name: text("env_var_name").notNull(),
2228
2624
  created_at: t.timestamp("created_at").notNull()
2229
2625
  },
2230
2626
  (table) => ({
2627
+ tenantIdx: index("session_env_selections_tenant_id_idx").on(table.tenant_id),
2231
2628
  pk: primaryKey({ columns: [table.session_id, table.env_var_name] }),
2232
2629
  sessionIdx: index("session_env_selections_session_idx").on(table.session_id)
2233
2630
  })
@@ -2235,6 +2632,7 @@ var init_schema_postgres = __esm({
2235
2632
  kbNamespaces = pgTable(
2236
2633
  "kb_namespaces",
2237
2634
  {
2635
+ tenant_id: text("tenant_id").notNull().default("default"),
2238
2636
  namespace_id: varchar("namespace_id", { length: 36 }).primaryKey(),
2239
2637
  slug: text("slug").notNull(),
2240
2638
  display_name: text("display_name").notNull(),
@@ -2261,7 +2659,8 @@ var init_schema_postgres = __esm({
2261
2659
  archived_at: t.timestamp("archived_at")
2262
2660
  },
2263
2661
  (table) => ({
2264
- slugIdx: uniqueIndex("kb_namespaces_slug_idx").on(table.slug).where(sql2`${table.archived} = false`),
2662
+ tenantIdx: index("kb_namespaces_tenant_id_idx").on(table.tenant_id),
2663
+ slugIdx: uniqueIndex("kb_namespaces_tenant_slug_unique").on(table.tenant_id, table.slug).where(sql2`${table.archived} = false`),
2265
2664
  kindIdx: index("kb_namespaces_kind_idx").on(table.kind),
2266
2665
  ownerIdx: index("kb_namespaces_owner_idx").on(table.owner_user_id),
2267
2666
  repoIdx: index("kb_namespaces_repo_idx").on(table.repo_id),
@@ -2272,6 +2671,7 @@ var init_schema_postgres = __esm({
2272
2671
  kbNamespaceAcl = pgTable(
2273
2672
  "kb_namespace_acl",
2274
2673
  {
2674
+ tenant_id: text("tenant_id").notNull().default("default"),
2275
2675
  namespace_acl_id: varchar("namespace_acl_id", { length: 36 }).primaryKey(),
2276
2676
  namespace_id: varchar("namespace_id", { length: 36 }).notNull().references(() => kbNamespaces.namespace_id, { onDelete: "cascade" }),
2277
2677
  subject_type: text("subject_type", { enum: ["user", "group"] }).notNull(),
@@ -2284,9 +2684,11 @@ var init_schema_postgres = __esm({
2284
2684
  updated_at: t.timestamp("updated_at")
2285
2685
  },
2286
2686
  (table) => ({
2687
+ tenantIdx: index("kb_namespace_acl_tenant_id_idx").on(table.tenant_id),
2287
2688
  namespaceIdx: index("kb_namespace_acl_namespace_idx").on(table.namespace_id),
2288
2689
  subjectIdx: index("kb_namespace_acl_subject_idx").on(table.subject_type, table.subject_id),
2289
- namespaceSubjectIdx: uniqueIndex("kb_namespace_acl_namespace_subject_idx").on(
2690
+ namespaceSubjectIdx: uniqueIndex("kb_namespace_acl_tenant_namespace_subject_unique").on(
2691
+ table.tenant_id,
2290
2692
  table.namespace_id,
2291
2693
  table.subject_type,
2292
2694
  table.subject_id
@@ -2296,6 +2698,7 @@ var init_schema_postgres = __esm({
2296
2698
  kbDocuments = pgTable(
2297
2699
  "kb_documents",
2298
2700
  {
2701
+ tenant_id: text("tenant_id").notNull().default("default"),
2299
2702
  document_id: varchar("document_id", { length: 36 }).primaryKey(),
2300
2703
  namespace_id: varchar("namespace_id", { length: 36 }).notNull().references(() => kbNamespaces.namespace_id, { onDelete: "cascade" }),
2301
2704
  path: text("path").notNull(),
@@ -2323,8 +2726,9 @@ var init_schema_postgres = __esm({
2323
2726
  archived_at: t.timestamp("archived_at")
2324
2727
  },
2325
2728
  (table) => ({
2326
- namespacePathIdx: uniqueIndex("kb_documents_namespace_path_idx").on(table.namespace_id, table.path).where(sql2`${table.archived} = false`),
2327
- uriIdx: uniqueIndex("kb_documents_uri_idx").on(table.uri).where(sql2`${table.archived} = false`),
2729
+ tenantIdx: index("kb_documents_tenant_id_idx").on(table.tenant_id),
2730
+ namespacePathIdx: uniqueIndex("kb_documents_tenant_namespace_path_unique").on(table.tenant_id, table.namespace_id, table.path).where(sql2`${table.archived} = false`),
2731
+ uriIdx: uniqueIndex("kb_documents_tenant_uri_unique").on(table.tenant_id, table.uri).where(sql2`${table.archived} = false`),
2328
2732
  namespaceIdx: index("kb_documents_namespace_idx").on(table.namespace_id),
2329
2733
  kindIdx: index("kb_documents_kind_idx").on(table.kind),
2330
2734
  visibilityIdx: index("kb_documents_visibility_idx").on(table.visibility),
@@ -2337,6 +2741,7 @@ var init_schema_postgres = __esm({
2337
2741
  kbDocumentVersions = pgTable(
2338
2742
  "kb_document_versions",
2339
2743
  {
2744
+ tenant_id: text("tenant_id").notNull().default("default"),
2340
2745
  version_id: varchar("version_id", { length: 36 }).primaryKey(),
2341
2746
  document_id: varchar("document_id", { length: 36 }).notNull().references(() => kbDocuments.document_id, { onDelete: "cascade" }),
2342
2747
  version_number: integer("version_number").notNull(),
@@ -2356,7 +2761,9 @@ var init_schema_postgres = __esm({
2356
2761
  created_at: t.timestamp("created_at").notNull()
2357
2762
  },
2358
2763
  (table) => ({
2359
- documentVersionIdx: uniqueIndex("kb_document_versions_document_version_idx").on(
2764
+ tenantIdx: index("kb_document_versions_tenant_id_idx").on(table.tenant_id),
2765
+ documentVersionIdx: uniqueIndex("kb_document_versions_tenant_document_version_unique").on(
2766
+ table.tenant_id,
2360
2767
  table.document_id,
2361
2768
  table.version_number
2362
2769
  ),
@@ -2368,6 +2775,7 @@ var init_schema_postgres = __esm({
2368
2775
  kbDocumentUnits = pgTable(
2369
2776
  "kb_document_units",
2370
2777
  {
2778
+ tenant_id: text("tenant_id").notNull().default("default"),
2371
2779
  unit_id: varchar("unit_id", { length: 36 }).primaryKey(),
2372
2780
  document_id: varchar("document_id", { length: 36 }).notNull().references(() => kbDocuments.document_id, { onDelete: "cascade" }),
2373
2781
  version_id: varchar("version_id", { length: 36 }).notNull().references(() => kbDocumentVersions.version_id, { onDelete: "cascade" }),
@@ -2392,6 +2800,7 @@ var init_schema_postgres = __esm({
2392
2800
  updated_at: t.timestamp("updated_at")
2393
2801
  },
2394
2802
  (table) => ({
2803
+ tenantIdx: index("kb_document_units_tenant_id_idx").on(table.tenant_id),
2395
2804
  documentIdx: index("kb_document_units_document_idx").on(table.document_id),
2396
2805
  versionIdx: index("kb_document_units_version_idx").on(table.version_id),
2397
2806
  versionOrdinalIdx: index("kb_document_units_version_ordinal_idx").on(
@@ -2405,6 +2814,7 @@ var init_schema_postgres = __esm({
2405
2814
  kbEmbeddingSpaces = pgTable(
2406
2815
  "kb_embedding_spaces",
2407
2816
  {
2817
+ tenant_id: text("tenant_id").notNull().default("default"),
2408
2818
  embedding_space_id: varchar("embedding_space_id", { length: 36 }).primaryKey(),
2409
2819
  provider: text("provider").notNull(),
2410
2820
  model: text("model").notNull(),
@@ -2417,7 +2827,9 @@ var init_schema_postgres = __esm({
2417
2827
  updated_at: t.timestamp("updated_at")
2418
2828
  },
2419
2829
  (table) => ({
2420
- providerModelIdx: uniqueIndex("kb_embedding_spaces_provider_model_idx").on(
2830
+ tenantIdx: index("kb_embedding_spaces_tenant_id_idx").on(table.tenant_id),
2831
+ providerModelIdx: uniqueIndex("kb_embedding_spaces_tenant_provider_model_unique").on(
2832
+ table.tenant_id,
2421
2833
  table.provider,
2422
2834
  table.model,
2423
2835
  table.dimensions,
@@ -2430,6 +2842,7 @@ var init_schema_postgres = __esm({
2430
2842
  kbGraphNodes = pgTable(
2431
2843
  "kb_graph_nodes",
2432
2844
  {
2845
+ tenant_id: text("tenant_id").notNull().default("default"),
2433
2846
  node_id: varchar("node_id", { length: 36 }).primaryKey(),
2434
2847
  node_type: text("node_type", {
2435
2848
  enum: [
@@ -2495,7 +2908,8 @@ var init_schema_postgres = __esm({
2495
2908
  archived_at: t.timestamp("archived_at")
2496
2909
  },
2497
2910
  (table) => ({
2498
- uriIdx: uniqueIndex("kb_graph_nodes_uri_idx").on(table.uri).where(sql2`${table.archived} = false`),
2911
+ tenantIdx: index("kb_graph_nodes_tenant_id_idx").on(table.tenant_id),
2912
+ uriIdx: uniqueIndex("kb_graph_nodes_tenant_uri_unique").on(table.tenant_id, table.uri).where(sql2`${table.archived} = false`),
2499
2913
  typeIdx: index("kb_graph_nodes_type_idx").on(table.node_type),
2500
2914
  namespaceIdx: index("kb_graph_nodes_namespace_idx").on(table.namespace_id),
2501
2915
  documentIdx: index("kb_graph_nodes_document_idx").on(table.document_id),
@@ -2515,6 +2929,7 @@ var init_schema_postgres = __esm({
2515
2929
  kbGraphEdges = pgTable(
2516
2930
  "kb_graph_edges",
2517
2931
  {
2932
+ tenant_id: text("tenant_id").notNull().default("default"),
2518
2933
  edge_id: varchar("edge_id", { length: 36 }).primaryKey(),
2519
2934
  source_node_id: varchar("source_node_id", { length: 36 }).notNull().references(() => kbGraphNodes.node_id, { onDelete: "cascade" }),
2520
2935
  target_node_id: varchar("target_node_id", { length: 36 }).notNull().references(() => kbGraphNodes.node_id, { onDelete: "cascade" }),
@@ -2543,6 +2958,7 @@ var init_schema_postgres = __esm({
2543
2958
  archived_at: t.timestamp("archived_at")
2544
2959
  },
2545
2960
  (table) => ({
2961
+ tenantIdx: index("kb_graph_edges_tenant_id_idx").on(table.tenant_id),
2546
2962
  sourceIdx: index("kb_graph_edges_source_idx").on(table.source_node_id),
2547
2963
  targetIdx: index("kb_graph_edges_target_idx").on(table.target_node_id),
2548
2964
  typeIdx: index("kb_graph_edges_type_idx").on(table.edge_type),
@@ -2554,11 +2970,11 @@ var init_schema_postgres = __esm({
2554
2970
  table.target_node_id,
2555
2971
  table.edge_type
2556
2972
  ),
2557
- sourceTargetTypeIdx: uniqueIndex("kb_graph_edges_source_target_type_idx").on(table.source_node_id, table.target_node_id, table.edge_type).where(sql2`${table.archived} = false`),
2973
+ 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`),
2558
2974
  archivedIdx: index("kb_graph_edges_archived_idx").on(table.archived)
2559
2975
  })
2560
2976
  );
2561
- sessionsRelations = relations(sessions, ({ one }) => ({
2977
+ sessionsRelations = relations(sessions, ({ one, many }) => ({
2562
2978
  branch: one(branches, {
2563
2979
  fields: [sessions.branch_id],
2564
2980
  references: [branches.branch_id]
@@ -2566,6 +2982,24 @@ var init_schema_postgres = __esm({
2566
2982
  schedule: one(schedules, {
2567
2983
  fields: [sessions.schedule_id],
2568
2984
  references: [schedules.schedule_id]
2985
+ }),
2986
+ outboundRelationships: many(sessionRelationships, { relationName: "relationshipSource" }),
2987
+ inboundRelationships: many(sessionRelationships, { relationName: "relationshipTarget" })
2988
+ }));
2989
+ sessionRelationshipsRelations = relations(sessionRelationships, ({ one }) => ({
2990
+ sourceSession: one(sessions, {
2991
+ fields: [sessionRelationships.source_session_id],
2992
+ references: [sessions.session_id],
2993
+ relationName: "relationshipSource"
2994
+ }),
2995
+ targetSession: one(sessions, {
2996
+ fields: [sessionRelationships.target_session_id],
2997
+ references: [sessions.session_id],
2998
+ relationName: "relationshipTarget"
2999
+ }),
3000
+ callbackSession: one(sessions, {
3001
+ fields: [sessionRelationships.callback_session_id],
3002
+ references: [sessions.session_id]
2569
3003
  })
2570
3004
  }));
2571
3005
  branchesRelations = relations(branches, ({ many }) => ({
@@ -2600,6 +3034,7 @@ __export(schema_sqlite_exports, {
2600
3034
  cardTypes: () => cardTypes2,
2601
3035
  cards: () => cards2,
2602
3036
  gatewayChannels: () => gatewayChannels2,
3037
+ gatewayOutboundMessages: () => gatewayOutboundMessages2,
2603
3038
  groupMemberships: () => groupMemberships2,
2604
3039
  groups: () => groups2,
2605
3040
  kbDocumentUnits: () => kbDocumentUnits2,
@@ -2618,6 +3053,8 @@ __export(schema_sqlite_exports, {
2618
3053
  serializedSessions: () => serializedSessions2,
2619
3054
  sessionEnvSelections: () => sessionEnvSelections2,
2620
3055
  sessionMcpServers: () => sessionMcpServers2,
3056
+ sessionRelationships: () => sessionRelationships2,
3057
+ sessionRelationshipsRelations: () => sessionRelationshipsRelations2,
2621
3058
  sessions: () => sessions2,
2622
3059
  sessionsRelations: () => sessionsRelations2,
2623
3060
  tasks: () => tasks2,
@@ -2636,7 +3073,7 @@ import {
2636
3073
  text as text2,
2637
3074
  uniqueIndex as uniqueIndex2
2638
3075
  } from "drizzle-orm/sqlite-core";
2639
- var t2, sessions2, tasks2, serializedSessions2, messages2, boards2, repos2, branches2, branchOwners2, boardOwners2, schedules2, users2, groups2, groupMemberships2, branchGroupGrants2, boardGroupGrants2, appVariables2, userApiKeys2, mcpServers2, cardTypes2, cards2, artifacts2, artifactTrustGrants2, boardObjects2, sessionMcpServers2, userMcpOauthTokens2, boardComments2, gatewayChannels2, threadSessionMap2, sessionEnvSelections2, kbNamespaces2, kbNamespaceAcl2, kbDocuments2, kbDocumentVersions2, kbDocumentUnits2, kbEmbeddingSpaces2, kbGraphNodes2, kbGraphEdges2, sessionsRelations2, branchesRelations2, schedulesRelations2;
3076
+ var t2, sessions2, sessionRelationships2, tasks2, serializedSessions2, messages2, boards2, repos2, branches2, branchOwners2, boardOwners2, schedules2, users2, groups2, groupMemberships2, branchGroupGrants2, boardGroupGrants2, appVariables2, userApiKeys2, mcpServers2, cardTypes2, cards2, artifacts2, artifactTrustGrants2, boardObjects2, sessionMcpServers2, userMcpOauthTokens2, boardComments2, gatewayChannels2, threadSessionMap2, gatewayOutboundMessages2, sessionEnvSelections2, kbNamespaces2, kbNamespaceAcl2, kbDocuments2, kbDocumentVersions2, kbDocumentUnits2, kbEmbeddingSpaces2, kbGraphNodes2, kbGraphEdges2, sessionsRelations2, sessionRelationshipsRelations2, branchesRelations2, schedulesRelations2;
2640
3077
  var init_schema_sqlite = __esm({
2641
3078
  "src/db/schema.sqlite.ts"() {
2642
3079
  "use strict";
@@ -2710,6 +3147,7 @@ var init_schema_sqlite = __esm({
2710
3147
  },
2711
3148
  (table) => ({
2712
3149
  statusIdx: index2("sessions_status_idx").on(table.status),
3150
+ statusReadyIdx: index2("sessions_status_ready_idx").on(table.status, table.ready_for_prompt),
2713
3151
  agenticToolIdx: index2("sessions_agentic_tool_idx").on(table.agentic_tool),
2714
3152
  boardIdx: index2("sessions_board_idx").on(table.board_id),
2715
3153
  branchIdx: index2("sessions_branch_idx").on(table.branch_id),
@@ -2726,6 +3164,39 @@ var init_schema_sqlite = __esm({
2726
3164
  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`)
2727
3165
  })
2728
3166
  );
3167
+ sessionRelationships2 = sqliteTable(
3168
+ "session_relationships",
3169
+ {
3170
+ relationship_id: text2("relationship_id", { length: 36 }).primaryKey(),
3171
+ source_session_id: text2("source_session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
3172
+ target_session_id: text2("target_session_id", { length: 36 }).notNull().references(() => sessions2.session_id, { onDelete: "cascade" }),
3173
+ relationship_type: text2("relationship_type", { enum: ["remote_create"] }).notNull(),
3174
+ created_by: text2("created_by", { length: 36 }).notNull(),
3175
+ created_at: t2.timestamp("created_at").notNull(),
3176
+ updated_at: t2.timestamp("updated_at"),
3177
+ callback_enabled: t2.bool("callback_enabled").notNull().default(false),
3178
+ callback_session_id: text2("callback_session_id", { length: 36 }).references(
3179
+ () => sessions2.session_id,
3180
+ {
3181
+ onDelete: "set null"
3182
+ }
3183
+ ),
3184
+ data: t2.json("data")
3185
+ },
3186
+ (table) => ({
3187
+ sourceIdx: index2("session_relationships_source_idx").on(table.source_session_id),
3188
+ targetIdx: index2("session_relationships_target_idx").on(table.target_session_id),
3189
+ callbackIdx: index2("session_relationships_callback_idx").on(table.callback_session_id),
3190
+ // Note: no tenant_source/tenant_target composite indexes here — SQLite schema
3191
+ // has no tenant column on this table (RLS is Postgres-only). The standalone
3192
+ // source/target indexes above are sufficient for SQLite.
3193
+ sourceTargetTypeUnique: uniqueIndex2("session_relationships_source_target_type_unique").on(
3194
+ table.source_session_id,
3195
+ table.target_session_id,
3196
+ table.relationship_type
3197
+ )
3198
+ })
3199
+ );
2729
3200
  tasks2 = sqliteTable(
2730
3201
  "tasks",
2731
3202
  {
@@ -2838,7 +3309,12 @@ var init_schema_sqlite = __esm({
2838
3309
  // Indexes for efficient lookups
2839
3310
  sessionIdx: index2("messages_session_id_idx").on(table.session_id),
2840
3311
  taskIdx: index2("messages_task_id_idx").on(table.task_id),
2841
- sessionIndexIdx: index2("messages_session_index_idx").on(table.session_id, table.index)
3312
+ sessionIndexIdx: index2("messages_session_index_idx").on(table.session_id, table.index),
3313
+ timestampIdx: index2("messages_timestamp_idx").on(table.timestamp),
3314
+ sessionTimestampIdx: index2("messages_session_timestamp_idx").on(
3315
+ table.session_id,
3316
+ table.timestamp
3317
+ )
2842
3318
  })
2843
3319
  );
2844
3320
  boards2 = sqliteTable(
@@ -3064,6 +3540,9 @@ var init_schema_sqlite = __esm({
3064
3540
  onboarding_completed: t2.bool("onboarding_completed").notNull().default(false),
3065
3541
  // Force password change flag (admin-settable, auto-cleared on password change)
3066
3542
  must_change_password: t2.bool("must_change_password").notNull().default(false),
3543
+ // Auth invalidation marker. Password changes set this timestamp so any
3544
+ // previously issued browser access or refresh token is rejected.
3545
+ tokens_valid_after: t2.timestamp("tokens_valid_after"),
3067
3546
  // JSON blob for profile/preferences
3068
3547
  data: t2.json("data").$type().notNull()
3069
3548
  },
@@ -3270,6 +3749,12 @@ var init_schema_sqlite = __esm({
3270
3749
  branch_id: text2("branch_id", { length: 36 }).references(() => branches2.branch_id, {
3271
3750
  onDelete: "set null"
3272
3751
  }),
3752
+ source_session_id: text2("source_session_id", { length: 36 }).references(
3753
+ () => sessions2.session_id,
3754
+ {
3755
+ onDelete: "set null"
3756
+ }
3757
+ ),
3273
3758
  board_id: text2("board_id", { length: 36 }).notNull().references(() => boards2.board_id, { onDelete: "cascade" }),
3274
3759
  name: text2("name").notNull(),
3275
3760
  description: text2("description"),
@@ -3296,6 +3781,7 @@ var init_schema_sqlite = __esm({
3296
3781
  },
3297
3782
  (table) => ({
3298
3783
  branchIdx: index2("artifacts_branch_idx").on(table.branch_id),
3784
+ sourceSessionIdx: index2("artifacts_source_session_idx").on(table.source_session_id),
3299
3785
  boardIdx: index2("artifacts_board_idx").on(table.board_id),
3300
3786
  archivedIdx: index2("artifacts_archived_idx").on(table.archived),
3301
3787
  publicIdx: index2("artifacts_public_idx").on(table.public)
@@ -3454,7 +3940,7 @@ var init_schema_sqlite = __esm({
3454
3940
  // Materialized for queries
3455
3941
  name: text2("name").notNull(),
3456
3942
  channel_type: text2("channel_type", {
3457
- enum: ["slack", "discord", "whatsapp", "telegram", "github"]
3943
+ enum: ["slack", "discord", "whatsapp", "telegram", "github", "teams"]
3458
3944
  }).notNull(),
3459
3945
  target_branch_id: text2("target_branch_id", { length: 36 }).notNull().references(() => branches2.branch_id, { onDelete: "cascade" }),
3460
3946
  agor_user_id: text2("agor_user_id", { length: 36 }).notNull(),
@@ -3500,6 +3986,66 @@ var init_schema_sqlite = __esm({
3500
3986
  channelStatusIdx: index2("idx_thread_map_channel_status").on(table.channel_id, table.status)
3501
3987
  })
3502
3988
  );
3989
+ gatewayOutboundMessages2 = sqliteTable(
3990
+ "gateway_outbound_messages",
3991
+ {
3992
+ id: text2("id", { length: 36 }).primaryKey(),
3993
+ created_at: t2.timestamp("created_at").notNull(),
3994
+ updated_at: t2.timestamp("updated_at").notNull(),
3995
+ gateway_channel_id: text2("gateway_channel_id", { length: 36 }).notNull().references(() => gatewayChannels2.id, { onDelete: "cascade" }),
3996
+ channel_type: text2("channel_type", {
3997
+ enum: ["slack", "discord", "whatsapp", "telegram", "github", "teams"]
3998
+ }).notNull(),
3999
+ platform_channel_id: text2("platform_channel_id").notNull(),
4000
+ platform_message_id: text2("platform_message_id").notNull(),
4001
+ platform_thread_id: text2("platform_thread_id").notNull(),
4002
+ platform_permalink: text2("platform_permalink"),
4003
+ target_branch_id: text2("target_branch_id", { length: 36 }).notNull().references(() => branches2.branch_id),
4004
+ emitted_by_user_id: text2("emitted_by_user_id", { length: 36 }).notNull().references(() => users2.user_id),
4005
+ emitted_by_session_id: text2("emitted_by_session_id", { length: 36 }).references(
4006
+ () => sessions2.session_id,
4007
+ {
4008
+ onDelete: "set null"
4009
+ }
4010
+ ),
4011
+ emitted_by_task_id: text2("emitted_by_task_id", { length: 36 }).references(() => tasks2.task_id, {
4012
+ onDelete: "set null"
4013
+ }),
4014
+ emitted_by_schedule_id: text2("emitted_by_schedule_id", { length: 36 }).references(
4015
+ () => schedules2.schedule_id,
4016
+ {
4017
+ onDelete: "set null"
4018
+ }
4019
+ ),
4020
+ message_text: text2("message_text").notNull(),
4021
+ message_preview: text2("message_preview").notNull(),
4022
+ metadata: t2.json("metadata"),
4023
+ consumed_by_session_id: text2("consumed_by_session_id", { length: 36 }).references(
4024
+ () => sessions2.session_id,
4025
+ {
4026
+ onDelete: "set null"
4027
+ }
4028
+ ),
4029
+ consumed_at: t2.timestamp("consumed_at")
4030
+ },
4031
+ (table) => ({
4032
+ uniqueChannelThread: uniqueIndex2("uniq_gateway_outbound_channel_thread").on(
4033
+ table.gateway_channel_id,
4034
+ table.platform_thread_id
4035
+ ),
4036
+ emittedSessionIdx: index2("idx_gateway_outbound_emitted_session").on(
4037
+ table.emitted_by_session_id
4038
+ ),
4039
+ emittedScheduleIdx: index2("idx_gateway_outbound_emitted_schedule").on(
4040
+ table.emitted_by_schedule_id
4041
+ ),
4042
+ targetBranchCreatedIdx: index2("idx_gateway_outbound_branch_created").on(
4043
+ table.target_branch_id,
4044
+ table.created_at
4045
+ ),
4046
+ consumedIdx: index2("idx_gateway_outbound_consumed").on(table.consumed_at)
4047
+ })
4048
+ );
3503
4049
  sessionEnvSelections2 = sqliteTable(
3504
4050
  "session_env_selections",
3505
4051
  {
@@ -3837,7 +4383,7 @@ var init_schema_sqlite = __esm({
3837
4383
  archivedIdx: index2("kb_graph_edges_archived_idx").on(table.archived)
3838
4384
  })
3839
4385
  );
3840
- sessionsRelations2 = relations2(sessions2, ({ one }) => ({
4386
+ sessionsRelations2 = relations2(sessions2, ({ one, many }) => ({
3841
4387
  branch: one(branches2, {
3842
4388
  fields: [sessions2.branch_id],
3843
4389
  references: [branches2.branch_id]
@@ -3845,6 +4391,24 @@ var init_schema_sqlite = __esm({
3845
4391
  schedule: one(schedules2, {
3846
4392
  fields: [sessions2.schedule_id],
3847
4393
  references: [schedules2.schedule_id]
4394
+ }),
4395
+ outboundRelationships: many(sessionRelationships2, { relationName: "relationshipSource" }),
4396
+ inboundRelationships: many(sessionRelationships2, { relationName: "relationshipTarget" })
4397
+ }));
4398
+ sessionRelationshipsRelations2 = relations2(sessionRelationships2, ({ one }) => ({
4399
+ sourceSession: one(sessions2, {
4400
+ fields: [sessionRelationships2.source_session_id],
4401
+ references: [sessions2.session_id],
4402
+ relationName: "relationshipSource"
4403
+ }),
4404
+ targetSession: one(sessions2, {
4405
+ fields: [sessionRelationships2.target_session_id],
4406
+ references: [sessions2.session_id],
4407
+ relationName: "relationshipTarget"
4408
+ }),
4409
+ callbackSession: one(sessions2, {
4410
+ fields: [sessionRelationships2.callback_session_id],
4411
+ references: [sessions2.session_id]
3848
4412
  })
3849
4413
  }));
3850
4414
  branchesRelations2 = relations2(branches2, ({ many }) => ({
@@ -3923,6 +4487,7 @@ __export(schema_exports, {
3923
4487
  cardTypes: () => cardTypes3,
3924
4488
  cards: () => cards3,
3925
4489
  gatewayChannels: () => gatewayChannels3,
4490
+ gatewayOutboundMessages: () => gatewayOutboundMessages3,
3926
4491
  groupMemberships: () => groupMemberships3,
3927
4492
  groups: () => groups3,
3928
4493
  kbDocumentUnits: () => kbDocumentUnits3,
@@ -3940,6 +4505,7 @@ __export(schema_exports, {
3940
4505
  serializedSessions: () => serializedSessions3,
3941
4506
  sessionEnvSelections: () => sessionEnvSelections3,
3942
4507
  sessionMcpServers: () => sessionMcpServers3,
4508
+ sessionRelationships: () => sessionRelationships3,
3943
4509
  sessions: () => sessions3,
3944
4510
  tasks: () => tasks3,
3945
4511
  threadSessionMap: () => threadSessionMap3,
@@ -3947,7 +4513,7 @@ __export(schema_exports, {
3947
4513
  userMcpOauthTokens: () => userMcpOauthTokens3,
3948
4514
  users: () => users3
3949
4515
  });
3950
- var dialect, schema, sessions3, tasks3, messages3, boards3, repos3, branches3, branchOwners3, boardOwners3, groups3, groupMemberships3, branchGroupGrants3, boardGroupGrants3, schedules3, users3, appVariables3, mcpServers3, cardTypes3, cards3, artifacts3, artifactTrustGrants3, boardObjects3, sessionMcpServers3, sessionEnvSelections3, userMcpOauthTokens3, boardComments3, gatewayChannels3, threadSessionMap3, userApiKeys3, serializedSessions3, kbNamespaces3, kbNamespaceAcl3, kbDocuments3, kbDocumentVersions3, kbDocumentUnits3, kbEmbeddingSpaces3, kbGraphNodes3, kbGraphEdges3;
4516
+ var dialect, schema, sessions3, tasks3, messages3, boards3, repos3, branches3, branchOwners3, boardOwners3, groups3, groupMemberships3, branchGroupGrants3, boardGroupGrants3, schedules3, users3, appVariables3, mcpServers3, cardTypes3, cards3, artifacts3, artifactTrustGrants3, boardObjects3, sessionMcpServers3, sessionRelationships3, sessionEnvSelections3, userMcpOauthTokens3, boardComments3, gatewayChannels3, threadSessionMap3, gatewayOutboundMessages3, userApiKeys3, serializedSessions3, kbNamespaces3, kbNamespaceAcl3, kbDocuments3, kbDocumentVersions3, kbDocumentUnits3, kbEmbeddingSpaces3, kbGraphNodes3, kbGraphEdges3;
3951
4517
  var init_schema = __esm({
3952
4518
  "src/db/schema.ts"() {
3953
4519
  "use strict";
@@ -3979,11 +4545,13 @@ var init_schema = __esm({
3979
4545
  artifactTrustGrants3 = schema.artifactTrustGrants;
3980
4546
  boardObjects3 = schema.boardObjects;
3981
4547
  sessionMcpServers3 = schema.sessionMcpServers;
4548
+ sessionRelationships3 = schema.sessionRelationships;
3982
4549
  sessionEnvSelections3 = schema.sessionEnvSelections;
3983
4550
  userMcpOauthTokens3 = schema.userMcpOauthTokens;
3984
4551
  boardComments3 = schema.boardComments;
3985
4552
  gatewayChannels3 = schema.gatewayChannels;
3986
4553
  threadSessionMap3 = schema.threadSessionMap;
4554
+ gatewayOutboundMessages3 = schema.gatewayOutboundMessages;
3987
4555
  userApiKeys3 = schema.userApiKeys;
3988
4556
  serializedSessions3 = schema.serializedSessions;
3989
4557
  kbNamespaces3 = schema.kbNamespaces;
@@ -4015,33 +4583,6 @@ var init_ids = __esm({
4015
4583
  }
4016
4584
  });
4017
4585
 
4018
- // src/db/user-utils.ts
4019
- import bcrypt from "bcryptjs";
4020
- import { eq as eq3 } from "drizzle-orm";
4021
- var init_user_utils = __esm({
4022
- "src/db/user-utils.ts"() {
4023
- "use strict";
4024
- init_esm_shims();
4025
- init_ids();
4026
- init_user();
4027
- init_database_wrapper();
4028
- init_schema();
4029
- }
4030
- });
4031
-
4032
- // src/db/first-run-bootstrap.ts
4033
- import { randomInt } from "crypto";
4034
- import { eq as eq4, inArray } from "drizzle-orm";
4035
- var init_first_run_bootstrap = __esm({
4036
- "src/db/first-run-bootstrap.ts"() {
4037
- "use strict";
4038
- init_esm_shims();
4039
- init_database_wrapper();
4040
- init_schema();
4041
- init_user_utils();
4042
- }
4043
- });
4044
-
4045
4586
  // src/unix/index.ts
4046
4587
  init_esm_shims();
4047
4588
 
@@ -4051,7 +4592,7 @@ import { exec, execSync, spawn } from "child_process";
4051
4592
  import { promisify } from "util";
4052
4593
  var execAsync = promisify(exec);
4053
4594
  function spawnWithInput(cmd, args, input) {
4054
- return new Promise((resolve2, reject) => {
4595
+ return new Promise((resolve, reject) => {
4055
4596
  const child = spawn(cmd, args, {
4056
4597
  stdio: ["pipe", "pipe", "pipe"]
4057
4598
  });
@@ -4065,7 +4606,7 @@ function spawnWithInput(cmd, args, input) {
4065
4606
  });
4066
4607
  child.on("error", reject);
4067
4608
  child.on("close", (code) => {
4068
- resolve2({
4609
+ resolve({
4069
4610
  stdout,
4070
4611
  stderr,
4071
4612
  exitCode: code ?? 1
@@ -4549,10 +5090,7 @@ import fs from "fs";
4549
5090
 
4550
5091
  // src/yaml/index.ts
4551
5092
  init_esm_shims();
4552
- import yaml from "js-yaml";
4553
- var load = yaml.load;
4554
- var dump = yaml.dump;
4555
- var YAMLException = yaml.YAMLException;
5093
+ import * as yaml from "js-yaml";
4556
5094
 
4557
5095
  // src/config/variant-resolver.ts
4558
5096
  init_esm_shims();
@@ -4744,6 +5282,7 @@ import { and, eq } from "drizzle-orm";
4744
5282
  init_esm_shims();
4745
5283
  init_ids();
4746
5284
  init_id();
5285
+ init_tenant_context();
4747
5286
  var RepositoryError = class extends Error {
4748
5287
  constructor(message, cause) {
4749
5288
  super(message);
@@ -4785,6 +5324,21 @@ async function resolveByShortIdPrefix(id, entityType, fetchMatches) {
4785
5324
  return matches[0];
4786
5325
  }
4787
5326
  var RESOLVE_SHORT_ID_FETCH_LIMIT = 11;
5327
+ function getHiddenTenantId(row) {
5328
+ const tenantId = row?.tenant_id;
5329
+ return typeof tenantId === "string" && tenantId.length > 0 ? tenantId : void 0;
5330
+ }
5331
+ function attachHiddenTenant(dto, row) {
5332
+ const tenantId = getHiddenTenantId(row);
5333
+ if (tenantId) {
5334
+ Object.defineProperty(dto, "tenant_id", {
5335
+ value: tenantId,
5336
+ enumerable: false,
5337
+ configurable: true
5338
+ });
5339
+ }
5340
+ return dto;
5341
+ }
4788
5342
 
4789
5343
  // src/db/repositories/session-env-selections.ts
4790
5344
  var SessionEnvSelectionRepository = class {
@@ -5172,83 +5726,103 @@ init_executor_heartbeat();
5172
5726
 
5173
5727
  // src/config/key-resolver.ts
5174
5728
  init_esm_shims();
5175
-
5176
- // src/db/index.ts
5177
- init_esm_shims();
5729
+ init_database_wrapper();
5730
+ import { eq as eq3 } from "drizzle-orm";
5731
+ init_schema();
5178
5732
  init_ids();
5179
- import {
5180
- and as and22,
5181
- asc as asc3,
5182
- desc as desc6,
5183
- eq as eq31,
5184
- gt,
5185
- gte,
5186
- inArray as inArray7,
5187
- like as like16,
5188
- lte as lte2,
5189
- or as or8,
5190
- sql as sql14
5191
- } from "drizzle-orm";
5192
- import bcryptjs from "bcryptjs";
5193
-
5194
- // src/lib/slugs.ts
5195
- init_esm_shims();
5196
-
5197
- // src/db/client.ts
5198
- init_esm_shims();
5199
5733
  init_config_manager();
5200
- init_schema_postgres();
5201
- init_schema_sqlite();
5202
- init_schema_factory();
5203
- import { createClient } from "@libsql/client";
5204
- import { drizzle as drizzleSQLite } from "drizzle-orm/libsql";
5205
- import { drizzle as drizzlePostgres } from "drizzle-orm/postgres-js";
5206
- import postgres from "postgres";
5207
-
5208
- // src/utils/path.ts
5209
- init_esm_shims();
5210
- import { homedir } from "os";
5211
- import { join } from "path";
5734
+ var DEBUG_KEY_RESOLUTION = process.env.AGOR_DEBUG_KEY_RESOLUTION === "1" || process.env.DEBUG?.includes("key-resolution");
5212
5735
 
5213
- // src/db/index.ts
5214
- init_database_wrapper();
5215
- init_first_run_bootstrap();
5736
+ // src/config/index.ts
5737
+ init_multitenancy();
5216
5738
 
5217
- // src/db/migrate.ts
5739
+ // src/config/proxies-resolver.ts
5218
5740
  init_esm_shims();
5219
- init_database_wrapper();
5220
- init_schema();
5221
- import { dirname, join as join2 } from "path";
5222
- import { fileURLToPath as fileURLToPath2 } from "url";
5223
- import { eq as eq5, sql as sql4 } from "drizzle-orm";
5224
- import { migrate as migrateSQLite } from "drizzle-orm/libsql/migrator";
5225
- import { migrate as migratePostgres } from "drizzle-orm/postgres-js/migrator";
5226
5741
 
5227
- // src/db/pending-migrations.ts
5742
+ // src/config/repo-list.ts
5228
5743
  init_esm_shims();
5229
5744
 
5230
- // src/db/repositories/index.ts
5745
+ // src/config/repo-reference.ts
5231
5746
  init_esm_shims();
5747
+ var REPO_SLUG_PATTERN = /^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/;
5232
5748
 
5233
- // src/db/repositories/app-variables.ts
5749
+ // src/config/resolved-config-slice.ts
5234
5750
  init_esm_shims();
5235
- init_ids();
5236
- init_database_wrapper();
5237
- import { and as and2, eq as eq6 } from "drizzle-orm";
5238
- init_schema();
5751
+ import { z } from "zod";
5752
+ var ResolvedConfigSliceSchema = z.object({
5753
+ /** From `config.execution.*` */
5754
+ execution: z.object({
5755
+ permission_timeout_ms: z.number().int().nonnegative().optional(),
5756
+ executor_heartbeat: z.object({
5757
+ enabled: z.boolean(),
5758
+ interval_ms: z.number().int().positive()
5759
+ }).optional()
5760
+ }).optional(),
5761
+ /** From `config.opencode.*` */
5762
+ opencode: z.object({
5763
+ serverUrl: z.string().optional()
5764
+ }).optional(),
5765
+ /** From `config.daemon.*` (selected fields only) */
5766
+ daemon: z.object({
5767
+ host_ip_address: z.string().optional()
5768
+ }).optional()
5769
+ });
5239
5770
 
5240
- // src/db/repositories/artifact-trust.ts
5771
+ // src/config/resource-schemas.ts
5241
5772
  init_esm_shims();
5242
- init_ids();
5243
- init_database_wrapper();
5244
- init_schema();
5245
- import { and as and3, eq as eq7, isNull } from "drizzle-orm";
5246
-
5247
- // src/db/repositories/artifacts.ts
5773
+ import { z as z2 } from "zod";
5774
+ var uuidSchema = z2.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, "Must be a valid UUID");
5775
+ var repoSlugSchema = z2.string().regex(
5776
+ REPO_SLUG_PATTERN,
5777
+ 'Must be org/name format with alphanumeric, hyphens, underscores, or dots (e.g., "my-org/my-repo")'
5778
+ );
5779
+ var enforcedAgentConfigSchema = z2.object({
5780
+ agentic_tool: z2.enum(["claude-code", "claude-code-cli", "codex", "gemini", "opencode", "copilot", "cursor"]).optional(),
5781
+ permission_mode: z2.string().optional(),
5782
+ model: z2.string().optional(),
5783
+ mcp_server_ids: z2.array(z2.string()).optional()
5784
+ });
5785
+ var resourceRepoConfigSchema = z2.object({
5786
+ repo_id: uuidSchema,
5787
+ slug: repoSlugSchema,
5788
+ remote_url: z2.string().optional(),
5789
+ repo_type: z2.enum(["remote", "local"]).default("remote"),
5790
+ default_branch: z2.string().optional(),
5791
+ shallow: z2.boolean().optional()
5792
+ }).refine((data) => data.repo_type !== "remote" || data.remote_url, {
5793
+ message: 'remote_url is required when repo_type is "remote"',
5794
+ path: ["remote_url"]
5795
+ });
5796
+ var resourceBranchConfigSchema = z2.object({
5797
+ branch_id: uuidSchema,
5798
+ name: z2.string().min(1, "Branch name is required"),
5799
+ ref: z2.string().min(1, "Git ref is required"),
5800
+ ref_type: z2.enum(["branch", "tag"]).optional(),
5801
+ others_can: z2.enum(["none", "view", "session", "prompt", "all"]).optional(),
5802
+ mcp_server_ids: z2.array(z2.string()).optional(),
5803
+ repo: repoSlugSchema,
5804
+ readonly: z2.boolean().optional(),
5805
+ agent: enforcedAgentConfigSchema.optional()
5806
+ });
5807
+ var resourceUserConfigSchema = z2.object({
5808
+ user_id: uuidSchema,
5809
+ email: z2.string().email("Must be a valid email address"),
5810
+ name: z2.string().optional(),
5811
+ role: z2.enum(["superadmin", "admin", "member", "viewer"]).default("member"),
5812
+ unix_username: z2.string().optional(),
5813
+ password: z2.string().optional()
5814
+ });
5815
+ var daemonResourcesConfigSchema = z2.object({
5816
+ repos: z2.array(resourceRepoConfigSchema).optional(),
5817
+ branches: z2.array(resourceBranchConfigSchema).optional(),
5818
+ users: z2.array(resourceUserConfigSchema).optional()
5819
+ });
5820
+
5821
+ // src/config/resource-sync.ts
5822
+ init_esm_shims();
5823
+
5824
+ // src/config/security-resolver.ts
5248
5825
  init_esm_shims();
5249
- init_config_manager();
5250
- init_ids();
5251
- import { and as and4, eq as eq8, like, or } from "drizzle-orm";
5252
5826
 
5253
5827
  // src/utils/url.ts
5254
5828
  init_esm_shims();
@@ -5300,26 +5874,40 @@ function stripHttpUrlUserinfo(rawUrl) {
5300
5874
  }
5301
5875
  }
5302
5876
 
5303
- // src/db/repositories/artifacts.ts
5304
- init_database_wrapper();
5305
- init_schema();
5877
+ // src/config/security-resolver.ts
5878
+ var DEFAULT_GIT_CONFIG_PARAMETERS = Object.freeze([
5879
+ "transfer.credentialsInUrl=die",
5880
+ "protocol.file.allow=user",
5881
+ "protocol.ext.allow=never",
5882
+ "core.protectHFS=true",
5883
+ "core.protectNTFS=true"
5884
+ ]);
5306
5885
 
5307
- // src/db/repositories/board-comments.ts
5886
+ // src/config/index.ts
5887
+ init_types();
5888
+
5889
+ // src/db/repositories/index.ts
5890
+ init_esm_shims();
5891
+
5892
+ // src/db/repositories/app-variables.ts
5308
5893
  init_esm_shims();
5309
5894
  init_ids();
5310
5895
  init_database_wrapper();
5896
+ import { and as and2, eq as eq4 } from "drizzle-orm";
5311
5897
  init_schema();
5312
- import { and as and5, eq as eq9, isNull as isNull2, like as like2 } from "drizzle-orm";
5313
5898
 
5314
- // src/db/repositories/board-objects.ts
5899
+ // src/db/repositories/artifact-trust.ts
5315
5900
  init_esm_shims();
5316
5901
  init_ids();
5317
- import { and as and7, asc, eq as eq11, getTableColumns, isNotNull as isNotNull2, isNull as isNull3, or as or3, sql as sql6 } from "drizzle-orm";
5902
+ init_database_wrapper();
5903
+ init_schema();
5904
+ import { and as and3, eq as eq5, isNull } from "drizzle-orm";
5318
5905
 
5319
- // src/utils/board-placement.ts
5906
+ // src/db/repositories/artifacts.ts
5320
5907
  init_esm_shims();
5321
-
5322
- // src/db/repositories/board-objects.ts
5908
+ init_config_manager();
5909
+ init_ids();
5910
+ import { and as and5, eq as eq7, inArray as inArray2, like, or as or2 } from "drizzle-orm";
5323
5911
  init_database_wrapper();
5324
5912
  init_schema();
5325
5913
 
@@ -5328,26 +5916,26 @@ init_esm_shims();
5328
5916
  init_types2();
5329
5917
  init_database_wrapper();
5330
5918
  init_schema();
5331
- import { and as and6, eq as eq10, exists, inArray as inArray2, isNotNull, or as or2, sql as sql5 } from "drizzle-orm";
5919
+ import { and as and4, eq as eq6, exists, inArray, isNotNull, or, sql as sql4 } from "drizzle-orm";
5332
5920
  var VISIBLE_BRANCH_PERMISSION_LEVELS = BRANCH_PERMISSION_LEVELS.filter(
5333
5921
  (level) => level !== "none"
5334
5922
  );
5335
5923
  function activeGroupGrantAccessExists(db, userId) {
5336
5924
  return exists(
5337
5925
  // biome-ignore lint/suspicious/noExplicitAny: Drizzle select has complex cross-dialect overloads
5338
- db.select({ _: sql5`1` }).from(branchGroupGrants3).innerJoin(
5926
+ db.select({ _: sql4`1` }).from(branchGroupGrants3).innerJoin(
5339
5927
  groupMemberships3,
5340
- and6(
5341
- eq10(groupMemberships3.group_id, branchGroupGrants3.group_id),
5342
- eq10(groupMemberships3.user_id, userId)
5928
+ and4(
5929
+ eq6(groupMemberships3.group_id, branchGroupGrants3.group_id),
5930
+ eq6(groupMemberships3.user_id, userId)
5343
5931
  )
5344
5932
  ).innerJoin(
5345
5933
  groups3,
5346
- and6(eq10(groups3.group_id, branchGroupGrants3.group_id), eq10(groups3.archived, false))
5934
+ and4(eq6(groups3.group_id, branchGroupGrants3.group_id), eq6(groups3.archived, false))
5347
5935
  ).where(
5348
- and6(
5349
- eq10(branchGroupGrants3.branch_id, branches3.branch_id),
5350
- inArray2(branchGroupGrants3.can, VISIBLE_BRANCH_PERMISSION_LEVELS)
5936
+ and4(
5937
+ eq6(branchGroupGrants3.branch_id, branches3.branch_id),
5938
+ inArray(branchGroupGrants3.can, VISIBLE_BRANCH_PERMISSION_LEVELS)
5351
5939
  )
5352
5940
  )
5353
5941
  );
@@ -5355,25 +5943,25 @@ function activeGroupGrantAccessExists(db, userId) {
5355
5943
  function activeBoardGroupGrantAccessExists(db, userId) {
5356
5944
  return exists(
5357
5945
  // biome-ignore lint/suspicious/noExplicitAny: Drizzle select has complex cross-dialect overloads
5358
- db.select({ _: sql5`1` }).from(boardGroupGrants3).innerJoin(
5946
+ db.select({ _: sql4`1` }).from(boardGroupGrants3).innerJoin(
5359
5947
  groupMemberships3,
5360
- and6(
5361
- eq10(groupMemberships3.group_id, boardGroupGrants3.group_id),
5362
- eq10(groupMemberships3.user_id, userId)
5948
+ and4(
5949
+ eq6(groupMemberships3.group_id, boardGroupGrants3.group_id),
5950
+ eq6(groupMemberships3.user_id, userId)
5363
5951
  )
5364
5952
  ).innerJoin(
5365
5953
  groups3,
5366
- and6(eq10(groups3.group_id, boardGroupGrants3.group_id), eq10(groups3.archived, false))
5954
+ and4(eq6(groups3.group_id, boardGroupGrants3.group_id), eq6(groups3.archived, false))
5367
5955
  ).innerJoin(
5368
5956
  boards3,
5369
- and6(
5370
- eq10(boards3.board_id, boardGroupGrants3.board_id),
5371
- eq10(sql5`coalesce(${jsonExtract(db, boards3.data, "access_mode")}, 'shared')`, "shared")
5957
+ and4(
5958
+ eq6(boards3.board_id, boardGroupGrants3.board_id),
5959
+ eq6(sql4`coalesce(${jsonExtract(db, boards3.data, "access_mode")}, 'shared')`, "shared")
5372
5960
  )
5373
5961
  ).where(
5374
- and6(
5375
- eq10(boardGroupGrants3.board_id, branches3.board_id),
5376
- inArray2(boardGroupGrants3.can, VISIBLE_BRANCH_PERMISSION_LEVELS)
5962
+ and4(
5963
+ eq6(boardGroupGrants3.board_id, branches3.board_id),
5964
+ inArray(boardGroupGrants3.can, VISIBLE_BRANCH_PERMISSION_LEVELS)
5377
5965
  )
5378
5966
  )
5379
5967
  );
@@ -5381,18 +5969,18 @@ function activeBoardGroupGrantAccessExists(db, userId) {
5381
5969
  function activeBoardOwnerAccessExists(db, userId) {
5382
5970
  return exists(
5383
5971
  // biome-ignore lint/suspicious/noExplicitAny: Drizzle select has complex cross-dialect overloads
5384
- db.select({ _: sql5`1` }).from(boardOwners3).where(and6(eq10(boardOwners3.board_id, branches3.board_id), eq10(boardOwners3.user_id, userId)))
5972
+ db.select({ _: sql4`1` }).from(boardOwners3).where(and4(eq6(boardOwners3.board_id, branches3.board_id), eq6(boardOwners3.user_id, userId)))
5385
5973
  );
5386
5974
  }
5387
5975
  function alignedBoardDefaultVisible(db) {
5388
5976
  return exists(
5389
5977
  // biome-ignore lint/suspicious/noExplicitAny: Drizzle select has complex cross-dialect overloads
5390
- db.select({ _: sql5`1` }).from(boards3).where(
5391
- and6(
5392
- eq10(boards3.board_id, branches3.board_id),
5393
- eq10(sql5`coalesce(${jsonExtract(db, boards3.data, "access_mode")}, 'shared')`, "shared"),
5394
- inArray2(
5395
- sql5`coalesce(${jsonExtract(db, boards3.data, "default_others_can")}, 'session')`,
5978
+ db.select({ _: sql4`1` }).from(boards3).where(
5979
+ and4(
5980
+ eq6(boards3.board_id, branches3.board_id),
5981
+ eq6(sql4`coalesce(${jsonExtract(db, boards3.data, "access_mode")}, 'shared')`, "shared"),
5982
+ inArray(
5983
+ sql4`coalesce(${jsonExtract(db, boards3.data, "default_others_can")}, 'session')`,
5396
5984
  VISIBLE_BRANCH_PERMISSION_LEVELS
5397
5985
  )
5398
5986
  )
@@ -5400,26 +5988,74 @@ function alignedBoardDefaultVisible(db) {
5400
5988
  );
5401
5989
  }
5402
5990
  function visibleBranchAccessCondition(db, userId) {
5403
- return or2(
5991
+ return or(
5404
5992
  isNotNull(branchOwners3.user_id),
5405
5993
  activeGroupGrantAccessExists(db, userId),
5406
- and6(eq10(branches3.permission_source, "board"), activeBoardOwnerAccessExists(db, userId)),
5407
- and6(eq10(branches3.permission_source, "board"), activeBoardGroupGrantAccessExists(db, userId)),
5408
- and6(eq10(branches3.permission_source, "board"), alignedBoardDefaultVisible(db)),
5409
- and6(
5410
- eq10(branches3.permission_source, "override"),
5411
- inArray2(branches3.others_can, VISIBLE_BRANCH_PERMISSION_LEVELS)
5994
+ and4(eq6(branches3.permission_source, "board"), activeBoardOwnerAccessExists(db, userId)),
5995
+ and4(eq6(branches3.permission_source, "board"), activeBoardGroupGrantAccessExists(db, userId)),
5996
+ and4(eq6(branches3.permission_source, "board"), alignedBoardDefaultVisible(db)),
5997
+ and4(
5998
+ eq6(branches3.permission_source, "override"),
5999
+ inArray(branches3.others_can, VISIBLE_BRANCH_PERMISSION_LEVELS)
5412
6000
  )
5413
- ) ?? sql5`false`;
6001
+ ) ?? sql4`false`;
5414
6002
  }
5415
6003
 
6004
+ // src/db/repositories/board-comments.ts
6005
+ init_esm_shims();
6006
+ init_ids();
6007
+ init_database_wrapper();
6008
+ init_schema();
6009
+ import { and as and6, eq as eq8, isNotNull as isNotNull2, isNull as isNull2, like as like2, or as or3, sql as sql5 } from "drizzle-orm";
6010
+
6011
+ // src/db/repositories/board-objects.ts
6012
+ init_esm_shims();
6013
+ init_ids();
6014
+ import { and as and7, asc, eq as eq9, getTableColumns, isNotNull as isNotNull3, isNull as isNull3, or as or4, sql as sql6 } from "drizzle-orm";
6015
+
6016
+ // src/utils/board-placement.ts
6017
+ init_esm_shims();
6018
+
6019
+ // src/db/repositories/board-objects.ts
6020
+ init_database_wrapper();
6021
+ init_schema();
6022
+
5416
6023
  // src/db/repositories/boards.ts
5417
6024
  init_esm_shims();
5418
6025
  init_types2();
5419
6026
  init_config_manager();
5420
6027
  init_ids();
5421
- import { and as and10, eq as eq14, exists as exists2, isNull as isNull4, like as like4, ne, or as or4, sql as sql8 } from "drizzle-orm";
6028
+ import { and as and10, eq as eq12, inArray as inArray4, isNull as isNull4, like as like4, ne } from "drizzle-orm";
5422
6029
  import * as yaml3 from "js-yaml";
6030
+
6031
+ // src/lib/slugs.ts
6032
+ init_esm_shims();
6033
+
6034
+ // src/utils/emoji-shortcodes.ts
6035
+ init_esm_shims();
6036
+ import { createRequire } from "module";
6037
+ var requireJson = createRequire(import.meta.url);
6038
+ var emojiData = requireJson("emojibase-data/en/compact.json");
6039
+ var shortcodes = requireJson(
6040
+ "emojibase-data/en/shortcodes/emojibase.json"
6041
+ );
6042
+ var emojiByHexcode = /* @__PURE__ */ new Map();
6043
+ for (const emoji of emojiData) {
6044
+ if (emoji.unicode) {
6045
+ emojiByHexcode.set(emoji.hexcode, emoji.unicode);
6046
+ }
6047
+ }
6048
+ var emojiByShortcode = /* @__PURE__ */ new Map();
6049
+ for (const [hexcode, codes] of Object.entries(shortcodes)) {
6050
+ const emoji = emojiByHexcode.get(hexcode);
6051
+ if (!emoji) continue;
6052
+ const codeList = Array.isArray(codes) ? codes : [codes];
6053
+ for (const code of codeList) {
6054
+ emojiByShortcode.set(code.toLowerCase(), emoji);
6055
+ }
6056
+ }
6057
+
6058
+ // src/db/repositories/boards.ts
5423
6059
  init_database_wrapper();
5424
6060
  init_schema();
5425
6061
 
@@ -5428,7 +6064,7 @@ init_esm_shims();
5428
6064
  init_types2();
5429
6065
  init_config_manager();
5430
6066
  init_ids();
5431
- import { and as and9, desc, eq as eq13, getTableColumns as getTableColumns2, inArray as inArray3, like as like3, sql as sql7 } from "drizzle-orm";
6067
+ import { and as and9, desc, eq as eq11, exists as exists2, getTableColumns as getTableColumns2, inArray as inArray3, like as like3, or as or5, sql as sql7 } from "drizzle-orm";
5432
6068
  init_database_wrapper();
5433
6069
  init_schema();
5434
6070
 
@@ -5437,7 +6073,7 @@ init_esm_shims();
5437
6073
  init_ids();
5438
6074
  init_database_wrapper();
5439
6075
  init_schema();
5440
- import { and as and8, eq as eq12 } from "drizzle-orm";
6076
+ import { and as and8, eq as eq10 } from "drizzle-orm";
5441
6077
  function slugify(value) {
5442
6078
  return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
5443
6079
  }
@@ -5498,17 +6134,17 @@ var GroupRepository = class {
5498
6134
  }
5499
6135
  async findAll(filter) {
5500
6136
  const conditions = [];
5501
- if (filter?.archived !== void 0) conditions.push(eq12(groups3.archived, filter.archived));
6137
+ if (filter?.archived !== void 0) conditions.push(eq10(groups3.archived, filter.archived));
5502
6138
  const query = select(this.db).from(groups3);
5503
6139
  const rows = conditions.length > 0 ? await query.where(and8(...conditions)).all() : await query.all();
5504
6140
  return rows.map((row) => this.rowToGroup(row));
5505
6141
  }
5506
6142
  async findById(id) {
5507
- const row = await select(this.db).from(groups3).where(eq12(groups3.group_id, id)).one();
6143
+ const row = await select(this.db).from(groups3).where(eq10(groups3.group_id, id)).one();
5508
6144
  return row ? this.rowToGroup(row) : null;
5509
6145
  }
5510
6146
  async findBySlug(slug) {
5511
- const row = await select(this.db).from(groups3).where(eq12(groups3.slug, slug)).one();
6147
+ const row = await select(this.db).from(groups3).where(eq10(groups3.slug, slug)).one();
5512
6148
  return row ? this.rowToGroup(row) : null;
5513
6149
  }
5514
6150
  async create(data) {
@@ -5542,7 +6178,7 @@ var GroupRepository = class {
5542
6178
  if (updates.slug !== void 0) patch.slug = normalizeSlug(updates.slug);
5543
6179
  if (updates.description !== void 0) patch.description = updates.description;
5544
6180
  if (updates.archived !== void 0) patch.archived = updates.archived;
5545
- await update(this.db, groups3).set(patch).where(eq12(groups3.group_id, existing.group_id)).run();
6181
+ await update(this.db, groups3).set(patch).where(eq10(groups3.group_id, existing.group_id)).run();
5546
6182
  const updatedGroup = await this.findById(existing.group_id);
5547
6183
  if (!updatedGroup) throw new RepositoryError("Failed to retrieve updated group");
5548
6184
  return updatedGroup;
@@ -5550,19 +6186,19 @@ var GroupRepository = class {
5550
6186
  async delete(id) {
5551
6187
  const existing = await this.findById(id);
5552
6188
  if (!existing) throw new EntityNotFoundError("Group", id);
5553
- await deleteFrom(this.db, groups3).where(eq12(groups3.group_id, existing.group_id)).run();
6189
+ await deleteFrom(this.db, groups3).where(eq10(groups3.group_id, existing.group_id)).run();
5554
6190
  return existing;
5555
6191
  }
5556
6192
  async listMemberships(filter) {
5557
6193
  const conditions = [];
5558
- if (filter?.group_id) conditions.push(eq12(groupMemberships3.group_id, filter.group_id));
5559
- if (filter?.user_id) conditions.push(eq12(groupMemberships3.user_id, filter.user_id));
6194
+ if (filter?.group_id) conditions.push(eq10(groupMemberships3.group_id, filter.group_id));
6195
+ if (filter?.user_id) conditions.push(eq10(groupMemberships3.user_id, filter.user_id));
5560
6196
  const query = select(this.db).from(groupMemberships3);
5561
6197
  const rows = conditions.length > 0 ? await query.where(and8(...conditions)).all() : await query.all();
5562
6198
  return rows.map((row) => this.rowToMembership(row));
5563
6199
  }
5564
6200
  async addMember(groupId, userId, addedBy) {
5565
- const existing = await select(this.db).from(groupMemberships3).where(and8(eq12(groupMemberships3.group_id, groupId), eq12(groupMemberships3.user_id, userId))).one();
6201
+ const existing = await select(this.db).from(groupMemberships3).where(and8(eq10(groupMemberships3.group_id, groupId), eq10(groupMemberships3.user_id, userId))).one();
5566
6202
  if (existing) return this.rowToMembership(existing);
5567
6203
  const row = {
5568
6204
  group_id: groupId,
@@ -5574,17 +6210,17 @@ var GroupRepository = class {
5574
6210
  return this.rowToMembership(row);
5575
6211
  }
5576
6212
  async removeMember(groupId, userId) {
5577
- const existing = await select(this.db).from(groupMemberships3).where(and8(eq12(groupMemberships3.group_id, groupId), eq12(groupMemberships3.user_id, userId))).one();
6213
+ const existing = await select(this.db).from(groupMemberships3).where(and8(eq10(groupMemberships3.group_id, groupId), eq10(groupMemberships3.user_id, userId))).one();
5578
6214
  if (!existing) return null;
5579
- await deleteFrom(this.db, groupMemberships3).where(and8(eq12(groupMemberships3.group_id, groupId), eq12(groupMemberships3.user_id, userId))).run();
6215
+ await deleteFrom(this.db, groupMemberships3).where(and8(eq10(groupMemberships3.group_id, groupId), eq10(groupMemberships3.user_id, userId))).run();
5580
6216
  return this.rowToMembership(existing);
5581
6217
  }
5582
6218
  async getGroupIdsForUser(userId) {
5583
- const rows = await select(this.db, { group_id: groupMemberships3.group_id }).from(groupMemberships3).where(eq12(groupMemberships3.user_id, userId)).all();
6219
+ const rows = await select(this.db, { group_id: groupMemberships3.group_id }).from(groupMemberships3).where(eq10(groupMemberships3.user_id, userId)).all();
5584
6220
  return rows.map((r) => r.group_id);
5585
6221
  }
5586
6222
  async listBranchGrants(branchId) {
5587
- const rows = await select(this.db).from(branchGroupGrants3).leftJoin(groups3, eq12(branchGroupGrants3.group_id, groups3.group_id)).where(eq12(branchGroupGrants3.branch_id, branchId)).all();
6223
+ const rows = await select(this.db).from(branchGroupGrants3).leftJoin(groups3, eq10(branchGroupGrants3.group_id, groups3.group_id)).where(eq10(branchGroupGrants3.branch_id, branchId)).all();
5588
6224
  return rows.map(
5589
6225
  (r) => this.rowToGrant(r.branch_group_grants, r.groups ? this.rowToGroup(r.groups) : void 0)
5590
6226
  );
@@ -5593,15 +6229,15 @@ var GroupRepository = class {
5593
6229
  const now = /* @__PURE__ */ new Date();
5594
6230
  const existing = await select(this.db).from(branchGroupGrants3).where(
5595
6231
  and8(
5596
- eq12(branchGroupGrants3.branch_id, data.branch_id),
5597
- eq12(branchGroupGrants3.group_id, data.group_id)
6232
+ eq10(branchGroupGrants3.branch_id, data.branch_id),
6233
+ eq10(branchGroupGrants3.group_id, data.group_id)
5598
6234
  )
5599
6235
  ).one();
5600
6236
  if (existing) {
5601
6237
  await update(this.db, branchGroupGrants3).set({ can: data.can, fs_access: data.fs_access ?? null, updated_at: now }).where(
5602
6238
  and8(
5603
- eq12(branchGroupGrants3.branch_id, data.branch_id),
5604
- eq12(branchGroupGrants3.group_id, data.group_id)
6239
+ eq10(branchGroupGrants3.branch_id, data.branch_id),
6240
+ eq10(branchGroupGrants3.group_id, data.group_id)
5605
6241
  )
5606
6242
  ).run();
5607
6243
  } else {
@@ -5624,16 +6260,16 @@ var GroupRepository = class {
5624
6260
  const existing = (await this.listBranchGrants(branchId)).find((g) => g.group_id === groupId) ?? null;
5625
6261
  if (!existing) return null;
5626
6262
  await deleteFrom(this.db, branchGroupGrants3).where(
5627
- and8(eq12(branchGroupGrants3.branch_id, branchId), eq12(branchGroupGrants3.group_id, groupId))
6263
+ and8(eq10(branchGroupGrants3.branch_id, branchId), eq10(branchGroupGrants3.group_id, groupId))
5628
6264
  ).run();
5629
6265
  return existing;
5630
6266
  }
5631
6267
  async getBranchGrantsForUser(branchId, userId) {
5632
- const rows = await select(this.db).from(branchGroupGrants3).innerJoin(groupMemberships3, eq12(branchGroupGrants3.group_id, groupMemberships3.group_id)).innerJoin(groups3, eq12(groupMemberships3.group_id, groups3.group_id)).where(
6268
+ const rows = await select(this.db).from(branchGroupGrants3).innerJoin(groupMemberships3, eq10(branchGroupGrants3.group_id, groupMemberships3.group_id)).innerJoin(groups3, eq10(groupMemberships3.group_id, groups3.group_id)).where(
5633
6269
  and8(
5634
- eq12(branchGroupGrants3.branch_id, branchId),
5635
- eq12(groupMemberships3.user_id, userId),
5636
- eq12(groups3.archived, false)
6270
+ eq10(branchGroupGrants3.branch_id, branchId),
6271
+ eq10(groupMemberships3.user_id, userId),
6272
+ eq10(groups3.archived, false)
5637
6273
  )
5638
6274
  ).all();
5639
6275
  return rows.map(
@@ -5641,7 +6277,7 @@ var GroupRepository = class {
5641
6277
  );
5642
6278
  }
5643
6279
  async listBoardGrants(boardId) {
5644
- const rows = await select(this.db).from(boardGroupGrants3).leftJoin(groups3, eq12(boardGroupGrants3.group_id, groups3.group_id)).where(eq12(boardGroupGrants3.board_id, boardId)).all();
6280
+ const rows = await select(this.db).from(boardGroupGrants3).leftJoin(groups3, eq10(boardGroupGrants3.group_id, groups3.group_id)).where(eq10(boardGroupGrants3.board_id, boardId)).all();
5645
6281
  return rows.map(
5646
6282
  (r) => this.rowToBoardGrant(r.board_group_grants, r.groups ? this.rowToGroup(r.groups) : void 0)
5647
6283
  );
@@ -5650,15 +6286,15 @@ var GroupRepository = class {
5650
6286
  const now = /* @__PURE__ */ new Date();
5651
6287
  const existing = await select(this.db).from(boardGroupGrants3).where(
5652
6288
  and8(
5653
- eq12(boardGroupGrants3.board_id, data.board_id),
5654
- eq12(boardGroupGrants3.group_id, data.group_id)
6289
+ eq10(boardGroupGrants3.board_id, data.board_id),
6290
+ eq10(boardGroupGrants3.group_id, data.group_id)
5655
6291
  )
5656
6292
  ).one();
5657
6293
  if (existing) {
5658
6294
  await update(this.db, boardGroupGrants3).set({ can: data.can, fs_access: data.fs_access ?? null, updated_at: now }).where(
5659
6295
  and8(
5660
- eq12(boardGroupGrants3.board_id, data.board_id),
5661
- eq12(boardGroupGrants3.group_id, data.group_id)
6296
+ eq10(boardGroupGrants3.board_id, data.board_id),
6297
+ eq10(boardGroupGrants3.group_id, data.group_id)
5662
6298
  )
5663
6299
  ).run();
5664
6300
  } else {
@@ -5680,15 +6316,15 @@ var GroupRepository = class {
5680
6316
  async removeBoardGrant(boardId, groupId) {
5681
6317
  const existing = (await this.listBoardGrants(boardId)).find((g) => g.group_id === groupId) ?? null;
5682
6318
  if (!existing) return null;
5683
- await deleteFrom(this.db, boardGroupGrants3).where(and8(eq12(boardGroupGrants3.board_id, boardId), eq12(boardGroupGrants3.group_id, groupId))).run();
6319
+ await deleteFrom(this.db, boardGroupGrants3).where(and8(eq10(boardGroupGrants3.board_id, boardId), eq10(boardGroupGrants3.group_id, groupId))).run();
5684
6320
  return existing;
5685
6321
  }
5686
6322
  async getBoardGrantsForUser(boardId, userId) {
5687
- const rows = await select(this.db).from(boardGroupGrants3).innerJoin(groupMemberships3, eq12(boardGroupGrants3.group_id, groupMemberships3.group_id)).innerJoin(groups3, eq12(groupMemberships3.group_id, groups3.group_id)).where(
6323
+ const rows = await select(this.db).from(boardGroupGrants3).innerJoin(groupMemberships3, eq10(boardGroupGrants3.group_id, groupMemberships3.group_id)).innerJoin(groups3, eq10(groupMemberships3.group_id, groups3.group_id)).where(
5688
6324
  and8(
5689
- eq12(boardGroupGrants3.board_id, boardId),
5690
- eq12(groupMemberships3.user_id, userId),
5691
- eq12(groups3.archived, false)
6325
+ eq10(boardGroupGrants3.board_id, boardId),
6326
+ eq10(groupMemberships3.user_id, userId),
6327
+ eq10(groups3.archived, false)
5692
6328
  )
5693
6329
  ).all();
5694
6330
  return rows.map(
@@ -5748,6 +6384,7 @@ var FS_ACCESS_RANK = {
5748
6384
  };
5749
6385
  var VIEW_OR_BETTER_BRANCH_PERMISSIONS = ["view", "session", "prompt", "all"];
5750
6386
  var BRANCH_PERMISSION_SOURCES = ["board", "override"];
6387
+ var FS_ACCESS_BRANCH_PERMISSIONS = ["read", "write"];
5751
6388
  var BranchRepository = class {
5752
6389
  constructor(db) {
5753
6390
  this.db = db;
@@ -5764,44 +6401,47 @@ var BranchRepository = class {
5764
6401
  rowToBranch(row, baseUrl) {
5765
6402
  const branchId = row.branch_id;
5766
6403
  const url = baseUrl && row.board_id ? getBranchUrl(branchId, baseUrl) : null;
5767
- return {
5768
- branch_id: branchId,
5769
- repo_id: row.repo_id,
5770
- created_at: new Date(row.created_at).toISOString(),
5771
- updated_at: row.updated_at ? new Date(row.updated_at).toISOString() : new Date(row.created_at).toISOString(),
5772
- created_by: row.created_by,
5773
- name: row.name,
5774
- ref: row.ref,
5775
- ref_type: row.ref_type ?? "branch",
5776
- branch_unique_id: row.branch_unique_id,
5777
- start_command: row.start_command ?? void 0,
5778
- // Static environment fields
5779
- stop_command: row.stop_command ?? void 0,
5780
- nuke_command: row.nuke_command ?? void 0,
5781
- health_check_url: row.health_check_url ?? void 0,
5782
- app_url: row.app_url ?? void 0,
5783
- logs_command: row.logs_command ?? void 0,
5784
- environment_variant: row.environment_variant ?? void 0,
5785
- board_id: row.board_id ?? void 0,
5786
- // Top-level column
5787
- needs_attention: Boolean(row.needs_attention),
5788
- // Convert SQLite integer (0/1) to boolean
5789
- archived: Boolean(row.archived),
5790
- // Convert SQLite integer (0/1) to boolean
5791
- archived_at: row.archived_at ? new Date(row.archived_at).toISOString() : void 0,
5792
- archived_by: row.archived_by ?? void 0,
5793
- filesystem_status: row.filesystem_status ?? void 0,
5794
- // RBAC fields
5795
- permission_source: row.permission_source ?? "override",
5796
- others_can: row.others_can ?? void 0,
5797
- others_fs_access: row.others_fs_access ?? void 0,
5798
- unix_group: row.unix_group ?? void 0,
5799
- // Branch storage mode
5800
- storage_mode: row.storage_mode ?? "worktree",
5801
- clone_depth: row.clone_depth ?? void 0,
5802
- ...row.data,
5803
- url
5804
- };
6404
+ return attachHiddenTenant(
6405
+ {
6406
+ branch_id: branchId,
6407
+ repo_id: row.repo_id,
6408
+ created_at: new Date(row.created_at).toISOString(),
6409
+ updated_at: row.updated_at ? new Date(row.updated_at).toISOString() : new Date(row.created_at).toISOString(),
6410
+ created_by: row.created_by,
6411
+ name: row.name,
6412
+ ref: row.ref,
6413
+ ref_type: row.ref_type ?? "branch",
6414
+ branch_unique_id: row.branch_unique_id,
6415
+ start_command: row.start_command ?? void 0,
6416
+ // Static environment fields
6417
+ stop_command: row.stop_command ?? void 0,
6418
+ nuke_command: row.nuke_command ?? void 0,
6419
+ health_check_url: row.health_check_url ?? void 0,
6420
+ app_url: row.app_url ?? void 0,
6421
+ logs_command: row.logs_command ?? void 0,
6422
+ environment_variant: row.environment_variant ?? void 0,
6423
+ board_id: row.board_id ?? void 0,
6424
+ // Top-level column
6425
+ needs_attention: Boolean(row.needs_attention),
6426
+ // Convert SQLite integer (0/1) to boolean
6427
+ archived: Boolean(row.archived),
6428
+ // Convert SQLite integer (0/1) to boolean
6429
+ archived_at: row.archived_at ? new Date(row.archived_at).toISOString() : void 0,
6430
+ archived_by: row.archived_by ?? void 0,
6431
+ filesystem_status: row.filesystem_status ?? void 0,
6432
+ // RBAC fields
6433
+ permission_source: row.permission_source ?? "override",
6434
+ others_can: row.others_can ?? void 0,
6435
+ others_fs_access: row.others_fs_access ?? void 0,
6436
+ unix_group: row.unix_group ?? void 0,
6437
+ // Branch storage mode
6438
+ storage_mode: row.storage_mode ?? "worktree",
6439
+ clone_depth: row.clone_depth ?? void 0,
6440
+ ...row.data,
6441
+ url
6442
+ },
6443
+ row
6444
+ );
5805
6445
  }
5806
6446
  /**
5807
6447
  * Convert Branch to database insert format
@@ -5911,7 +6551,7 @@ var BranchRepository = class {
5911
6551
  const rows = await select(this.db).from(branches3).where(like3(branches3.branch_id, pattern)).limit(RESOLVE_SHORT_ID_FETCH_LIMIT).all();
5912
6552
  return rows.map((r) => r.branch_id);
5913
6553
  });
5914
- const row = await select(this.db).from(branches3).where(eq13(branches3.branch_id, fullId)).one();
6554
+ const row = await select(this.db).from(branches3).where(eq11(branches3.branch_id, fullId)).one();
5915
6555
  if (!row) return null;
5916
6556
  const baseUrl = await getBaseUrl();
5917
6557
  return this.rowToBranch(row, baseUrl);
@@ -5934,11 +6574,11 @@ var BranchRepository = class {
5934
6574
  others_can: branches3.others_can,
5935
6575
  board_id: branches3.board_id,
5936
6576
  permission_source: branches3.permission_source
5937
- }).from(branches3).where(eq13(branches3.branch_id, fullId)).one();
6577
+ }).from(branches3).where(eq11(branches3.branch_id, fullId)).one();
5938
6578
  if (!row) return null;
5939
6579
  let othersCan = row.others_can;
5940
6580
  if (row.permission_source === "board" && row.board_id) {
5941
- const board = await select(this.db, { data: boards3.data }).from(boards3).where(eq13(boards3.board_id, row.board_id)).one();
6581
+ const board = await select(this.db, { data: boards3.data }).from(boards3).where(eq11(boards3.board_id, row.board_id)).one();
5942
6582
  const boardData = board?.data;
5943
6583
  othersCan = (boardData?.access_mode ?? "shared") === "private" ? "none" : boardData?.default_others_can ?? row.others_can;
5944
6584
  }
@@ -5958,21 +6598,109 @@ var BranchRepository = class {
5958
6598
  * Callers that explicitly want to exclude archived branches should pass
5959
6599
  * `{ includeArchived: false }`.
5960
6600
  *
5961
- * @param filter - Optional filters (repo_id, includeArchived)
6601
+ * The `board_id`, `archived`, and `branchIds` filters let the list read path
6602
+ * (`BranchesService.find`) push its high-selectivity predicates into SQL so it
6603
+ * no longer materializes the whole table before filtering in memory.
6604
+ *
6605
+ * @param filter - Optional filters
5962
6606
  * @param filter.repo_id - Filter by repository ID
5963
6607
  * @param filter.includeArchived - Include archived branches (default: true)
6608
+ * @param filter.board_id - Filter to a single board
6609
+ * @param filter.archived - Filter to an exact archived state (takes precedence
6610
+ * over `includeArchived`)
6611
+ * @param filter.branchIds - Restrict to a set of branch IDs (empty set yields
6612
+ * no rows, matching an `{ $in: [] }` filter)
6613
+ * @param filter.visibleToUserId - Restrict to branches visible to this user
6614
+ * under branch RBAC, pushed down as a SQL predicate instead of a preloaded
6615
+ * `branch_id IN (...)` list.
5964
6616
  */
5965
6617
  async findAll(filter) {
6618
+ if (filter?.branchIds !== void 0 && filter.branchIds.length === 0) {
6619
+ return [];
6620
+ }
5966
6621
  const includeArchived = filter?.includeArchived ?? true;
5967
6622
  const conditions = [];
5968
6623
  if (filter?.repo_id) {
5969
- conditions.push(eq13(branches3.repo_id, filter.repo_id));
6624
+ conditions.push(eq11(branches3.repo_id, filter.repo_id));
6625
+ }
6626
+ if (filter?.board_id) {
6627
+ conditions.push(eq11(branches3.board_id, filter.board_id));
6628
+ }
6629
+ if (filter?.archived !== void 0) {
6630
+ conditions.push(eq11(branches3.archived, filter.archived));
6631
+ } else if (!includeArchived) {
6632
+ conditions.push(eq11(branches3.archived, false));
5970
6633
  }
5971
- if (!includeArchived) {
5972
- conditions.push(eq13(branches3.archived, false));
6634
+ if (filter?.branchIds !== void 0) {
6635
+ conditions.push(inArray3(branches3.branch_id, filter.branchIds));
5973
6636
  }
5974
- const query = select(this.db).from(branches3);
5975
- const rows = conditions.length > 0 ? await query.where(and9(...conditions)).all() : await query.all();
6637
+ if (filter?.visibleToUserId) {
6638
+ conditions.push(visibleBranchAccessCondition(this.db, filter.visibleToUserId));
6639
+ }
6640
+ const baseQuery = filter?.visibleToUserId ? select(this.db, getTableColumns2(branches3)).from(branches3).leftJoin(
6641
+ branchOwners3,
6642
+ and9(
6643
+ eq11(branchOwners3.branch_id, branches3.branch_id),
6644
+ eq11(branchOwners3.user_id, filter.visibleToUserId)
6645
+ )
6646
+ ) : select(this.db).from(branches3);
6647
+ const rows = conditions.length > 0 ? await baseQuery.where(and9(...conditions)).all() : await baseQuery.all();
6648
+ const baseUrl = await getBaseUrl();
6649
+ return rows.map((row) => this.rowToBranch(row, baseUrl));
6650
+ }
6651
+ /**
6652
+ * Health-monitor discovery query. Returns only routing metadata so the
6653
+ * background monitor can enter the correct tenant DB scope before loading
6654
+ * branch contents or patching health state.
6655
+ */
6656
+ async findActiveEnvironmentRefs() {
6657
+ const tenantColumn = branches3.tenant_id;
6658
+ const columns = isPostgresDatabase(this.db) && tenantColumn ? { branch_id: branches3.branch_id, tenant_id: tenantColumn } : { branch_id: branches3.branch_id };
6659
+ const statusExpr = sql7`${jsonExtract(this.db, branches3.data, "environment_instance.status")}`;
6660
+ const rows = await select(this.db, columns).from(branches3).where(or5(eq11(statusExpr, "running"), eq11(statusExpr, "starting"))).all();
6661
+ return rows.map((row) => ({
6662
+ branch_id: row.branch_id,
6663
+ ...typeof row.tenant_id === "string" && row.tenant_id.length > 0 ? { tenant_id: row.tenant_id } : {}
6664
+ }));
6665
+ }
6666
+ /**
6667
+ * Find active assistant branches without paginating the whole branch list first.
6668
+ *
6669
+ * A branch is discoverable as an assistant when it has the canonical assistant
6670
+ * marker in custom_context (new or legacy key), or as a read-time backfill for
6671
+ * older hand-bootstrapped assistants, when it has at least one enabled
6672
+ * first-class schedule.
6673
+ */
6674
+ async findAssistantBranches(filter) {
6675
+ const assistantKindConditions = [
6676
+ eq11(sql7`${jsonExtract(this.db, branches3.data, "custom_context.assistant.kind")}`, "assistant"),
6677
+ eq11(
6678
+ sql7`${jsonExtract(this.db, branches3.data, "custom_context.assistant.kind")}`,
6679
+ "persisted-agent"
6680
+ ),
6681
+ eq11(sql7`${jsonExtract(this.db, branches3.data, "custom_context.agent.kind")}`, "assistant"),
6682
+ eq11(
6683
+ sql7`${jsonExtract(this.db, branches3.data, "custom_context.agent.kind")}`,
6684
+ "persisted-agent"
6685
+ )
6686
+ ];
6687
+ const hasEnabledSchedule = exists2(
6688
+ // biome-ignore lint/suspicious/noExplicitAny: Drizzle select has complex cross-dialect overloads
6689
+ this.db.select({ _: sql7`1` }).from(schedules3).where(and9(eq11(schedules3.branch_id, branches3.branch_id), eq11(schedules3.enabled, true)))
6690
+ );
6691
+ const conditions = [or5(...assistantKindConditions, hasEnabledSchedule) ?? sql7`false`];
6692
+ if (filter?.repo_id) conditions.push(eq11(branches3.repo_id, filter.repo_id));
6693
+ if (filter?.archived !== void 0) conditions.push(eq11(branches3.archived, filter.archived));
6694
+ if (filter?.userId) conditions.push(visibleBranchAccessCondition(this.db, filter.userId));
6695
+ const baseQuery = select(this.db, getTableColumns2(branches3)).from(branches3);
6696
+ const query = filter?.userId ? baseQuery.leftJoin(
6697
+ branchOwners3,
6698
+ and9(
6699
+ eq11(branchOwners3.branch_id, branches3.branch_id),
6700
+ eq11(branchOwners3.user_id, filter.userId)
6701
+ )
6702
+ ) : baseQuery;
6703
+ const rows = await query.where(and9(...conditions)).limit(filter?.limit ?? 200).all();
5976
6704
  const baseUrl = await getBaseUrl();
5977
6705
  return rows.map((row) => this.rowToBranch(row, baseUrl));
5978
6706
  }
@@ -5993,9 +6721,9 @@ var BranchRepository = class {
5993
6721
  txAsDb(tx),
5994
6722
  this.db,
5995
6723
  branches3,
5996
- eq13(branches3.branch_id, existing.branch_id)
6724
+ eq11(branches3.branch_id, existing.branch_id)
5997
6725
  );
5998
- const currentRow = await select(txAsDb(tx)).from(branches3).where(eq13(branches3.branch_id, existing.branch_id)).one();
6726
+ const currentRow = await select(txAsDb(tx)).from(branches3).where(eq11(branches3.branch_id, existing.branch_id)).one();
5999
6727
  if (!currentRow) {
6000
6728
  throw new EntityNotFoundError("Branch", id);
6001
6729
  }
@@ -6012,7 +6740,7 @@ var BranchRepository = class {
6012
6740
  // Always update timestamp
6013
6741
  });
6014
6742
  const insertData = this.branchToInsert(merged);
6015
- const row = await update(txAsDb(tx), branches3).set(insertData).where(eq13(branches3.branch_id, current.branch_id)).returning().one();
6743
+ const row = await update(txAsDb(tx), branches3).set(insertData).where(eq11(branches3.branch_id, current.branch_id)).returning().one();
6016
6744
  return this.rowToBranch(row, baseUrl);
6017
6745
  });
6018
6746
  }
@@ -6024,13 +6752,13 @@ var BranchRepository = class {
6024
6752
  if (!existing) {
6025
6753
  throw new EntityNotFoundError("Branch", id);
6026
6754
  }
6027
- await deleteFrom(this.db, branches3).where(eq13(branches3.branch_id, existing.branch_id)).run();
6755
+ await deleteFrom(this.db, branches3).where(eq11(branches3.branch_id, existing.branch_id)).run();
6028
6756
  }
6029
6757
  /**
6030
6758
  * Find branch by repo_id and name
6031
6759
  */
6032
6760
  async findByRepoAndName(repoId, name) {
6033
- const row = await select(this.db).from(branches3).where(and9(eq13(branches3.repo_id, repoId), eq13(branches3.name, name))).one();
6761
+ const row = await select(this.db).from(branches3).where(and9(eq11(branches3.repo_id, repoId), eq11(branches3.name, name))).one();
6034
6762
  if (!row) return null;
6035
6763
  const baseUrl = await getBaseUrl();
6036
6764
  return this.rowToBranch(row, baseUrl);
@@ -6040,7 +6768,7 @@ var BranchRepository = class {
6040
6768
  */
6041
6769
  async findActiveByRepoAndName(repoId, name) {
6042
6770
  const row = await select(this.db).from(branches3).where(
6043
- and9(eq13(branches3.repo_id, repoId), eq13(branches3.name, name), eq13(branches3.archived, false))
6771
+ and9(eq11(branches3.repo_id, repoId), eq11(branches3.name, name), eq11(branches3.archived, false))
6044
6772
  ).one();
6045
6773
  if (!row) return null;
6046
6774
  const baseUrl = await getBaseUrl();
@@ -6059,7 +6787,7 @@ var BranchRepository = class {
6059
6787
  * Used for auto-suffix name conflict resolution — bypasses Feathers pagination.
6060
6788
  */
6061
6789
  async getActiveNamesByRepo(repoId) {
6062
- const rows = await select(this.db, { name: branches3.name }).from(branches3).where(and9(eq13(branches3.repo_id, repoId), eq13(branches3.archived, false))).all();
6790
+ const rows = await select(this.db, { name: branches3.name }).from(branches3).where(and9(eq11(branches3.repo_id, repoId), eq11(branches3.archived, false))).all();
6063
6791
  return rows.map((row) => row.name);
6064
6792
  }
6065
6793
  // ===== RBAC: Ownership Management =====
@@ -6071,7 +6799,7 @@ var BranchRepository = class {
6071
6799
  * @returns true if user is an owner
6072
6800
  */
6073
6801
  async isOwner(branchId, userId) {
6074
- const row = await select(this.db).from(branchOwners3).where(and9(eq13(branchOwners3.branch_id, branchId), eq13(branchOwners3.user_id, userId))).one();
6802
+ const row = await select(this.db).from(branchOwners3).where(and9(eq11(branchOwners3.branch_id, branchId), eq11(branchOwners3.user_id, userId))).one();
6075
6803
  return row != null;
6076
6804
  }
6077
6805
  /**
@@ -6084,15 +6812,15 @@ var BranchRepository = class {
6084
6812
  const rows = await select(this.db).from(branchGroupGrants3).innerJoin(
6085
6813
  groupMemberships3,
6086
6814
  and9(
6087
- eq13(groupMemberships3.group_id, branchGroupGrants3.group_id),
6088
- eq13(groupMemberships3.user_id, userId)
6815
+ eq11(groupMemberships3.group_id, branchGroupGrants3.group_id),
6816
+ eq11(groupMemberships3.user_id, userId)
6089
6817
  )
6090
6818
  ).innerJoin(
6091
6819
  groups3,
6092
- and9(eq13(groups3.group_id, branchGroupGrants3.group_id), eq13(groups3.archived, false))
6820
+ and9(eq11(groups3.group_id, branchGroupGrants3.group_id), eq11(groups3.archived, false))
6093
6821
  ).where(
6094
6822
  and9(
6095
- eq13(branchGroupGrants3.branch_id, branchId),
6823
+ eq11(branchGroupGrants3.branch_id, branchId),
6096
6824
  inArray3(branchGroupGrants3.can, BRANCH_PERMISSION_LEVELS)
6097
6825
  )
6098
6826
  ).all();
@@ -6123,7 +6851,7 @@ var BranchRepository = class {
6123
6851
  * this method.
6124
6852
  */
6125
6853
  async resolveUserAccess(branch, userId) {
6126
- const board = branch.permission_source === "board" && branch.board_id ? await select(this.db, { data: boards3.data, board_id: boards3.board_id }).from(boards3).where(eq13(boards3.board_id, branch.board_id)).one() : null;
6854
+ const board = branch.permission_source === "board" && branch.board_id ? await select(this.db, { data: boards3.data, board_id: boards3.board_id }).from(boards3).where(eq11(boards3.board_id, branch.board_id)).one() : null;
6127
6855
  const boardData = board?.data;
6128
6856
  const boardIsShared = (boardData?.access_mode ?? "shared") === "shared";
6129
6857
  const sharing = branch.permission_source === "board" && boardIsShared ? boardData?.default_dangerously_allow_session_sharing ?? false : branch.dangerously_allow_session_sharing ?? false;
@@ -6139,7 +6867,7 @@ var BranchRepository = class {
6139
6867
  const groupRepo = new GroupRepository(this.db);
6140
6868
  const branchGroupGrants4 = await groupRepo.getBranchGrantsForUser(branch.branch_id, userId);
6141
6869
  if (branch.permission_source === "board" && branch.board_id) {
6142
- const boardOwner = await select(this.db).from(boardOwners3).where(and9(eq13(boardOwners3.board_id, branch.board_id), eq13(boardOwners3.user_id, userId))).one();
6870
+ const boardOwner = await select(this.db).from(boardOwners3).where(and9(eq11(boardOwners3.board_id, branch.board_id), eq11(boardOwners3.user_id, userId))).one();
6143
6871
  if (boardOwner) {
6144
6872
  return {
6145
6873
  can: "all",
@@ -6196,33 +6924,33 @@ var BranchRepository = class {
6196
6924
  const branchRow = await select(this.db, {
6197
6925
  board_id: branches3.board_id,
6198
6926
  permission_source: branches3.permission_source
6199
- }).from(branches3).where(eq13(branches3.branch_id, branchId)).one();
6200
- const ownerRows = await select(this.db, { user_id: branchOwners3.user_id }).from(branchOwners3).where(eq13(branchOwners3.branch_id, branchId)).all();
6201
- const groupRows = await select(this.db, { user_id: groupMemberships3.user_id }).from(branchGroupGrants3).innerJoin(groupMemberships3, eq13(groupMemberships3.group_id, branchGroupGrants3.group_id)).innerJoin(
6927
+ }).from(branches3).where(eq11(branches3.branch_id, branchId)).one();
6928
+ const ownerRows = await select(this.db, { user_id: branchOwners3.user_id }).from(branchOwners3).where(eq11(branchOwners3.branch_id, branchId)).all();
6929
+ const groupRows = await select(this.db, { user_id: groupMemberships3.user_id }).from(branchGroupGrants3).innerJoin(groupMemberships3, eq11(groupMemberships3.group_id, branchGroupGrants3.group_id)).innerJoin(
6202
6930
  groups3,
6203
- and9(eq13(groups3.group_id, branchGroupGrants3.group_id), eq13(groups3.archived, false))
6931
+ and9(eq11(groups3.group_id, branchGroupGrants3.group_id), eq11(groups3.archived, false))
6204
6932
  ).where(
6205
6933
  and9(
6206
- eq13(branchGroupGrants3.branch_id, branchId),
6934
+ eq11(branchGroupGrants3.branch_id, branchId),
6207
6935
  inArray3(branchGroupGrants3.can, VIEW_OR_BETTER_BRANCH_PERMISSIONS)
6208
6936
  )
6209
6937
  ).all();
6210
- const boardOwnerRows = branchRow?.permission_source === "board" && branchRow.board_id ? await select(this.db, { user_id: boardOwners3.user_id }).from(boardOwners3).where(eq13(boardOwners3.board_id, branchRow.board_id)).all() : [];
6211
- const boardGroupRows = branchRow?.permission_source === "board" && branchRow.board_id ? await select(this.db, { user_id: groupMemberships3.user_id }).from(boardGroupGrants3).innerJoin(groupMemberships3, eq13(groupMemberships3.group_id, boardGroupGrants3.group_id)).innerJoin(
6938
+ const boardOwnerRows = branchRow?.permission_source === "board" && branchRow.board_id ? await select(this.db, { user_id: boardOwners3.user_id }).from(boardOwners3).where(eq11(boardOwners3.board_id, branchRow.board_id)).all() : [];
6939
+ const boardGroupRows = branchRow?.permission_source === "board" && branchRow.board_id ? await select(this.db, { user_id: groupMemberships3.user_id }).from(boardGroupGrants3).innerJoin(groupMemberships3, eq11(groupMemberships3.group_id, boardGroupGrants3.group_id)).innerJoin(
6212
6940
  groups3,
6213
- and9(eq13(groups3.group_id, boardGroupGrants3.group_id), eq13(groups3.archived, false))
6941
+ and9(eq11(groups3.group_id, boardGroupGrants3.group_id), eq11(groups3.archived, false))
6214
6942
  ).innerJoin(
6215
6943
  boards3,
6216
6944
  and9(
6217
- eq13(boards3.board_id, boardGroupGrants3.board_id),
6218
- eq13(
6945
+ eq11(boards3.board_id, boardGroupGrants3.board_id),
6946
+ eq11(
6219
6947
  sql7`coalesce(${jsonExtract(this.db, boards3.data, "access_mode")}, 'shared')`,
6220
6948
  "shared"
6221
6949
  )
6222
6950
  )
6223
6951
  ).where(
6224
6952
  and9(
6225
- eq13(boardGroupGrants3.board_id, branchRow.board_id),
6953
+ eq11(boardGroupGrants3.board_id, branchRow.board_id),
6226
6954
  inArray3(boardGroupGrants3.can, VIEW_OR_BETTER_BRANCH_PERMISSIONS)
6227
6955
  )
6228
6956
  ).all() : [];
@@ -6241,6 +6969,83 @@ var BranchRepository = class {
6241
6969
  }
6242
6970
  return Array.from(userIds);
6243
6971
  }
6972
+ /**
6973
+ * Find users whose explicit branch or aligned-board grants should materialize
6974
+ * into filesystem access for the branch.
6975
+ *
6976
+ * This intentionally excludes ambient "others" access because there is no
6977
+ * bounded user set to expand. Board owners apply whenever the branch is
6978
+ * explicitly aligned to board permissions (`permission_source = 'board'`);
6979
+ * board group grants additionally require a shared board. Override branches
6980
+ * must not inherit board grants.
6981
+ */
6982
+ async findExplicitFsAccessUserIds(branchId) {
6983
+ const branchRow = await select(this.db, {
6984
+ board_id: branches3.board_id,
6985
+ permission_source: branches3.permission_source
6986
+ }).from(branches3).where(eq11(branches3.branch_id, branchId)).one();
6987
+ const ownerRows = await select(this.db, { user_id: branchOwners3.user_id }).from(branchOwners3).where(eq11(branchOwners3.branch_id, branchId)).all();
6988
+ const groupRows = await select(this.db, { user_id: groupMemberships3.user_id }).from(branchGroupGrants3).innerJoin(groupMemberships3, eq11(groupMemberships3.group_id, branchGroupGrants3.group_id)).innerJoin(
6989
+ groups3,
6990
+ and9(eq11(groups3.group_id, branchGroupGrants3.group_id), eq11(groups3.archived, false))
6991
+ ).where(
6992
+ and9(
6993
+ eq11(branchGroupGrants3.branch_id, branchId),
6994
+ inArray3(
6995
+ sql7`coalesce(${branchGroupGrants3.fs_access}, 'read')`,
6996
+ FS_ACCESS_BRANCH_PERMISSIONS
6997
+ )
6998
+ )
6999
+ ).all();
7000
+ const isBoardAligned = branchRow?.permission_source === "board" && branchRow.board_id;
7001
+ const boardOwnerRows = isBoardAligned ? await select(this.db, { user_id: boardOwners3.user_id }).from(boardOwners3).where(eq11(boardOwners3.board_id, branchRow.board_id)).all() : [];
7002
+ const boardGroupRows = isBoardAligned ? await select(this.db, { user_id: groupMemberships3.user_id }).from(boardGroupGrants3).innerJoin(groupMemberships3, eq11(groupMemberships3.group_id, boardGroupGrants3.group_id)).innerJoin(
7003
+ groups3,
7004
+ and9(eq11(groups3.group_id, boardGroupGrants3.group_id), eq11(groups3.archived, false))
7005
+ ).innerJoin(
7006
+ boards3,
7007
+ and9(
7008
+ eq11(boards3.board_id, boardGroupGrants3.board_id),
7009
+ eq11(
7010
+ sql7`coalesce(${jsonExtract(this.db, boards3.data, "access_mode")}, 'shared')`,
7011
+ "shared"
7012
+ )
7013
+ )
7014
+ ).where(
7015
+ and9(
7016
+ eq11(boardGroupGrants3.board_id, branchRow.board_id),
7017
+ inArray3(
7018
+ sql7`coalesce(${boardGroupGrants3.fs_access}, 'read')`,
7019
+ FS_ACCESS_BRANCH_PERMISSIONS
7020
+ )
7021
+ )
7022
+ ).all() : [];
7023
+ const userIds = /* @__PURE__ */ new Set();
7024
+ for (const row of ownerRows) {
7025
+ userIds.add(row.user_id);
7026
+ }
7027
+ for (const row of groupRows) {
7028
+ userIds.add(row.user_id);
7029
+ }
7030
+ for (const row of boardOwnerRows) {
7031
+ userIds.add(row.user_id);
7032
+ }
7033
+ for (const row of boardGroupRows) {
7034
+ userIds.add(row.user_id);
7035
+ }
7036
+ return Array.from(userIds);
7037
+ }
7038
+ async findBoardAlignedBranches(boardId) {
7039
+ const rows = await select(this.db).from(branches3).where(
7040
+ and9(
7041
+ eq11(branches3.board_id, boardId),
7042
+ eq11(branches3.permission_source, "board"),
7043
+ eq11(branches3.archived, false)
7044
+ )
7045
+ ).all();
7046
+ const baseUrl = await getBaseUrl();
7047
+ return rows.map((row) => this.rowToBranch(row, baseUrl));
7048
+ }
6244
7049
  /**
6245
7050
  * Get all owners of a branch
6246
7051
  *
@@ -6252,7 +7057,7 @@ var BranchRepository = class {
6252
7057
  if (!branch) {
6253
7058
  throw new EntityNotFoundError("Branch", branchId);
6254
7059
  }
6255
- const rows = await select(this.db).from(branchOwners3).where(eq13(branchOwners3.branch_id, branch.branch_id)).all();
7060
+ const rows = await select(this.db).from(branchOwners3).where(eq11(branchOwners3.branch_id, branch.branch_id)).all();
6256
7061
  return rows.map((row) => row.user_id);
6257
7062
  }
6258
7063
  /**
@@ -6292,7 +7097,7 @@ var BranchRepository = class {
6292
7097
  if (!branch) {
6293
7098
  throw new EntityNotFoundError("Branch", branchId);
6294
7099
  }
6295
- await deleteFrom(this.db, branchOwners3).where(and9(eq13(branchOwners3.branch_id, branch.branch_id), eq13(branchOwners3.user_id, userId))).run();
7100
+ await deleteFrom(this.db, branchOwners3).where(and9(eq11(branchOwners3.branch_id, branch.branch_id), eq11(branchOwners3.user_id, userId))).run();
6296
7101
  }
6297
7102
  /**
6298
7103
  * Bulk-load ownership for multiple branches
@@ -6338,13 +7143,13 @@ var BranchRepository = class {
6338
7143
  async findAccessibleBranches(userId, filter) {
6339
7144
  const conditions = [visibleBranchAccessCondition(this.db, userId)];
6340
7145
  if (filter?.archived === true) {
6341
- conditions.push(eq13(branches3.archived, true));
7146
+ conditions.push(eq11(branches3.archived, true));
6342
7147
  } else if (filter?.archived === false) {
6343
- conditions.push(eq13(branches3.archived, false));
7148
+ conditions.push(eq11(branches3.archived, false));
6344
7149
  }
6345
7150
  const rows = await select(this.db, getTableColumns2(branches3)).from(branches3).leftJoin(
6346
7151
  branchOwners3,
6347
- and9(eq13(branchOwners3.branch_id, branches3.branch_id), eq13(branchOwners3.user_id, userId))
7152
+ and9(eq11(branchOwners3.branch_id, branches3.branch_id), eq11(branchOwners3.user_id, userId))
6348
7153
  ).where(and9(...conditions)).all();
6349
7154
  const baseUrl = await getBaseUrl();
6350
7155
  const seen = /* @__PURE__ */ new Set();
@@ -6420,7 +7225,7 @@ var BranchRepository = class {
6420
7225
  zone_id: jsonExtract2(this.db, boardObjectsTable.data, "zone_id"),
6421
7226
  position: jsonExtract2(this.db, boardObjectsTable.data, "position"),
6422
7227
  board_data: boardsTable.data
6423
- }).from(boardObjectsTable).leftJoin(boardsTable, eq13(boardObjectsTable.board_id, boardsTable.board_id)).where(inArray3(boardObjectsTable.branch_id, branchIds)).all();
7228
+ }).from(boardObjectsTable).leftJoin(boardsTable, eq11(boardObjectsTable.board_id, boardsTable.board_id)).where(inArray3(boardObjectsTable.branch_id, branchIds)).all();
6424
7229
  const boardObjectInfoByBranch = /* @__PURE__ */ new Map();
6425
7230
  for (const row of rows) {
6426
7231
  const info = {
@@ -6508,7 +7313,7 @@ var BranchRepository = class {
6508
7313
  for (const sessionId of sessionIds) {
6509
7314
  const query = select(this.db, {
6510
7315
  data: messagesTable.data
6511
- }).from(messagesTable).where(and9(eq13(messagesTable.session_id, sessionId), eq13(messagesTable.role, "assistant")));
7316
+ }).from(messagesTable).where(and9(eq11(messagesTable.session_id, sessionId), eq11(messagesTable.role, "assistant")));
6512
7317
  const lastMessage = await query.orderBy(desc(messagesTable.index)).limit(1).one();
6513
7318
  if (lastMessage) {
6514
7319
  const messageData = lastMessage.data;
@@ -6580,22 +7385,30 @@ init_esm_shims();
6580
7385
  init_ids();
6581
7386
  init_database_wrapper();
6582
7387
  init_schema();
6583
- import { eq as eq15, like as like5 } from "drizzle-orm";
7388
+ import { eq as eq13, like as like5 } from "drizzle-orm";
6584
7389
 
6585
7390
  // src/db/repositories/cards.ts
6586
7391
  init_esm_shims();
6587
7392
  init_ids();
6588
7393
  init_database_wrapper();
6589
7394
  init_schema();
6590
- import { and as and11, eq as eq16, like as like6 } from "drizzle-orm";
7395
+ import { and as and11, eq as eq14, like as like6 } from "drizzle-orm";
6591
7396
 
6592
7397
  // src/db/repositories/gateway-channels.ts
6593
7398
  init_esm_shims();
6594
7399
  init_types2();
6595
7400
  init_ids();
6596
7401
  init_database_wrapper();
6597
- import { eq as eq17, like as like7 } from "drizzle-orm";
7402
+ import { eq as eq15, like as like7 } from "drizzle-orm";
7403
+ init_schema();
7404
+
7405
+ // src/db/repositories/gateway-outbound-messages.ts
7406
+ init_esm_shims();
7407
+ init_types2();
7408
+ init_ids();
7409
+ init_database_wrapper();
6598
7410
  init_schema();
7411
+ import { and as and12, eq as eq16, isNull as isNull5, like as like8 } from "drizzle-orm";
6599
7412
 
6600
7413
  // src/db/repositories/knowledge.ts
6601
7414
  init_esm_shims();
@@ -6603,14 +7416,14 @@ init_types2();
6603
7416
  init_config_manager();
6604
7417
  init_ids();
6605
7418
  import { createHash } from "crypto";
6606
- import { and as and12, desc as desc2, eq as eq18, inArray as inArray4, like as like8, or as or5, sql as sql9 } from "drizzle-orm";
7419
+ import { and as and13, desc as desc2, eq as eq17, inArray as inArray5, like as like9, or as or6, sql as sql8 } from "drizzle-orm";
6607
7420
  init_database_wrapper();
6608
7421
  init_schema();
6609
7422
 
6610
7423
  // src/db/repositories/mcp-servers.ts
6611
7424
  init_esm_shims();
6612
7425
  init_ids();
6613
- import { and as and13, eq as eq19, like as like9 } from "drizzle-orm";
7426
+ import { and as and14, eq as eq18, like as like10 } from "drizzle-orm";
6614
7427
 
6615
7428
  // src/tools/mcp/auth-secrets.ts
6616
7429
  init_esm_shims();
@@ -6626,11 +7439,11 @@ init_schema();
6626
7439
  init_esm_shims();
6627
7440
  init_database_wrapper();
6628
7441
  init_schema();
6629
- import { and as and14, eq as eq20 } from "drizzle-orm";
7442
+ import { and as and15, eq as eq19, inArray as inArray6 } from "drizzle-orm";
6630
7443
 
6631
7444
  // src/db/repositories/repos.ts
6632
7445
  init_esm_shims();
6633
- import { eq as eq21, like as like10, sql as sql10 } from "drizzle-orm";
7446
+ import { eq as eq20, like as like11, sql as sql9 } from "drizzle-orm";
6634
7447
  init_ids();
6635
7448
  init_database_wrapper();
6636
7449
  init_schema();
@@ -6666,20 +7479,23 @@ var RepoRepository = class {
6666
7479
  const environment = data.environment ?? wrapV1AsV2(data.environment_config);
6667
7480
  const environment_config = data.environment_config ?? deriveV1FromV2(environment);
6668
7481
  const remote_url = typeof data.remote_url === "string" ? stripHttpUrlUserinfo(data.remote_url) : data.remote_url;
6669
- return {
6670
- repo_id: row.repo_id,
6671
- slug: row.slug,
6672
- repo_type: row.repo_type ?? "remote",
6673
- unix_group: row.unix_group ?? void 0,
6674
- created_at: new Date(row.created_at).toISOString(),
6675
- last_updated: row.updated_at ? new Date(row.updated_at).toISOString() : new Date(row.created_at).toISOString(),
6676
- ...data,
6677
- remote_url,
6678
- environment,
6679
- environment_config,
6680
- clone_status: data.clone_status,
6681
- clone_error: data.clone_error
6682
- };
7482
+ return attachHiddenTenant(
7483
+ {
7484
+ repo_id: row.repo_id,
7485
+ slug: row.slug,
7486
+ repo_type: row.repo_type ?? "remote",
7487
+ unix_group: row.unix_group ?? void 0,
7488
+ created_at: new Date(row.created_at).toISOString(),
7489
+ last_updated: row.updated_at ? new Date(row.updated_at).toISOString() : new Date(row.created_at).toISOString(),
7490
+ ...data,
7491
+ remote_url,
7492
+ environment,
7493
+ environment_config,
7494
+ clone_status: data.clone_status,
7495
+ clone_error: data.clone_error
7496
+ },
7497
+ row
7498
+ );
6683
7499
  }
6684
7500
  /**
6685
7501
  * Convert Repo to database insert format
@@ -6729,7 +7545,7 @@ var RepoRepository = class {
6729
7545
  */
6730
7546
  async resolveId(id) {
6731
7547
  return resolveByShortIdPrefix(id, "Repo", async (pattern) => {
6732
- const rows = await select(this.db).from(repos3).where(like10(repos3.repo_id, pattern)).limit(RESOLVE_SHORT_ID_FETCH_LIMIT).all();
7548
+ const rows = await select(this.db).from(repos3).where(like11(repos3.repo_id, pattern)).limit(RESOLVE_SHORT_ID_FETCH_LIMIT).all();
6733
7549
  return rows.map((r) => r.repo_id);
6734
7550
  });
6735
7551
  }
@@ -6740,7 +7556,7 @@ var RepoRepository = class {
6740
7556
  try {
6741
7557
  const insertData = this.repoToInsert(data);
6742
7558
  await insert(this.db, repos3).values(insertData).run();
6743
- const row = await select(this.db).from(repos3).where(eq21(repos3.repo_id, insertData.repo_id)).one();
7559
+ const row = await select(this.db).from(repos3).where(eq20(repos3.repo_id, insertData.repo_id)).one();
6744
7560
  if (!row) {
6745
7561
  throw new RepositoryError("Failed to retrieve created repo");
6746
7562
  }
@@ -6759,7 +7575,7 @@ var RepoRepository = class {
6759
7575
  async findById(id) {
6760
7576
  try {
6761
7577
  const fullId = await this.resolveId(id);
6762
- const row = await select(this.db).from(repos3).where(eq21(repos3.repo_id, fullId)).one();
7578
+ const row = await select(this.db).from(repos3).where(eq20(repos3.repo_id, fullId)).one();
6763
7579
  return row ? this.rowToRepo(row) : null;
6764
7580
  } catch (error) {
6765
7581
  if (error instanceof EntityNotFoundError) return null;
@@ -6775,7 +7591,7 @@ var RepoRepository = class {
6775
7591
  */
6776
7592
  async findBySlug(slug) {
6777
7593
  try {
6778
- const row = await select(this.db).from(repos3).where(eq21(repos3.slug, slug)).one();
7594
+ const row = await select(this.db).from(repos3).where(eq20(repos3.slug, slug)).one();
6779
7595
  return row ? this.rowToRepo(row) : null;
6780
7596
  } catch (error) {
6781
7597
  throw new RepositoryError(
@@ -6843,8 +7659,8 @@ var RepoRepository = class {
6843
7659
  let changed = 0;
6844
7660
  for (const finding of scan.findings) {
6845
7661
  await this.db.transaction(async (tx) => {
6846
- await lockRowForUpdate(txAsDb(tx), this.db, repos3, eq21(repos3.repo_id, finding.repo_id));
6847
- const currentRow = await select(txAsDb(tx)).from(repos3).where(eq21(repos3.repo_id, finding.repo_id)).one();
7662
+ await lockRowForUpdate(txAsDb(tx), this.db, repos3, eq20(repos3.repo_id, finding.repo_id));
7663
+ const currentRow = await select(txAsDb(tx)).from(repos3).where(eq20(repos3.repo_id, finding.repo_id)).one();
6848
7664
  if (!currentRow) return;
6849
7665
  const data = currentRow.data;
6850
7666
  if (typeof data.remote_url !== "string" || !httpUrlHasUserinfo(data.remote_url)) {
@@ -6856,7 +7672,7 @@ var RepoRepository = class {
6856
7672
  ...data,
6857
7673
  remote_url: stripHttpUrlUserinfo(data.remote_url)
6858
7674
  }
6859
- }).where(eq21(repos3.repo_id, finding.repo_id)).run();
7675
+ }).where(eq20(repos3.repo_id, finding.repo_id)).run();
6860
7676
  changed += 1;
6861
7677
  });
6862
7678
  }
@@ -6878,8 +7694,8 @@ var RepoRepository = class {
6878
7694
  try {
6879
7695
  const fullId = await this.resolveId(id);
6880
7696
  return await this.db.transaction(async (tx) => {
6881
- await lockRowForUpdate(txAsDb(tx), this.db, repos3, eq21(repos3.repo_id, fullId));
6882
- const currentRow = await select(txAsDb(tx)).from(repos3).where(eq21(repos3.repo_id, fullId)).one();
7697
+ await lockRowForUpdate(txAsDb(tx), this.db, repos3, eq20(repos3.repo_id, fullId));
7698
+ const currentRow = await select(txAsDb(tx)).from(repos3).where(eq20(repos3.repo_id, fullId)).one();
6883
7699
  if (!currentRow) {
6884
7700
  throw new EntityNotFoundError("Repo", id);
6885
7701
  }
@@ -6893,7 +7709,7 @@ var RepoRepository = class {
6893
7709
  repo_type: insertData.repo_type,
6894
7710
  unix_group: merged.unix_group ?? null,
6895
7711
  data: insertData.data
6896
- }).where(eq21(repos3.repo_id, fullId)).run();
7712
+ }).where(eq20(repos3.repo_id, fullId)).run();
6897
7713
  merged.clone_error = insertData.data.clone_error;
6898
7714
  merged.remote_url = insertData.data.remote_url;
6899
7715
  merged.last_updated = newUpdatedAt.toISOString();
@@ -6927,8 +7743,8 @@ var RepoRepository = class {
6927
7743
  try {
6928
7744
  const fullId = await this.resolveId(id);
6929
7745
  return await this.db.transaction(async (tx) => {
6930
- await lockRowForUpdate(txAsDb(tx), this.db, repos3, eq21(repos3.repo_id, fullId));
6931
- const currentRow = await select(txAsDb(tx)).from(repos3).where(eq21(repos3.repo_id, fullId)).one();
7746
+ await lockRowForUpdate(txAsDb(tx), this.db, repos3, eq20(repos3.repo_id, fullId));
7747
+ const currentRow = await select(txAsDb(tx)).from(repos3).where(eq20(repos3.repo_id, fullId)).one();
6932
7748
  if (!currentRow) {
6933
7749
  throw new EntityNotFoundError("Repo", id);
6934
7750
  }
@@ -6942,7 +7758,7 @@ var RepoRepository = class {
6942
7758
  repo_type: insertData.repo_type,
6943
7759
  unix_group: next.unix_group ?? null,
6944
7760
  data: insertData.data
6945
- }).where(eq21(repos3.repo_id, fullId)).run();
7761
+ }).where(eq20(repos3.repo_id, fullId)).run();
6946
7762
  next.environment = insertData.data.environment;
6947
7763
  next.environment_config = insertData.data.environment_config;
6948
7764
  next.remote_url = insertData.data.remote_url;
@@ -6982,7 +7798,7 @@ var RepoRepository = class {
6982
7798
  async delete(id) {
6983
7799
  try {
6984
7800
  const fullId = await this.resolveId(id);
6985
- const result = await deleteFrom(this.db, repos3).where(eq21(repos3.repo_id, fullId)).run();
7801
+ const result = await deleteFrom(this.db, repos3).where(eq20(repos3.repo_id, fullId)).run();
6986
7802
  if (result.rowsAffected === 0) {
6987
7803
  throw new EntityNotFoundError("Repo", id);
6988
7804
  }
@@ -7013,7 +7829,7 @@ var RepoRepository = class {
7013
7829
  */
7014
7830
  async count() {
7015
7831
  try {
7016
- const result = await select(this.db, { count: sql10`count(*)` }).from(repos3).one();
7832
+ const result = await select(this.db, { count: sql9`count(*)` }).from(repos3).one();
7017
7833
  return result?.count ?? 0;
7018
7834
  } catch (error) {
7019
7835
  throw new RepositoryError(
@@ -7029,29 +7845,36 @@ init_esm_shims();
7029
7845
  init_ids();
7030
7846
  init_database_wrapper();
7031
7847
  init_schema();
7032
- import { and as and15, asc as asc2, desc as desc3, eq as eq22, isNull as isNull5, like as like11, lte, or as or6, sql as sql11 } from "drizzle-orm";
7848
+ import { and as and16, asc as asc2, desc as desc3, eq as eq21, isNull as isNull6, like as like12, lte, or as or7, sql as sql10 } from "drizzle-orm";
7033
7849
 
7034
7850
  // src/db/repositories/serialized-sessions.ts
7035
7851
  init_esm_shims();
7036
7852
  init_ids();
7037
7853
  init_database_wrapper();
7038
7854
  init_schema();
7039
- import { and as and16, desc as desc4, eq as eq23, lt } from "drizzle-orm";
7855
+ import { and as and17, desc as desc4, eq as eq22, lt } from "drizzle-orm";
7040
7856
 
7041
7857
  // src/db/repositories/session-mcp-servers.ts
7042
7858
  init_esm_shims();
7043
7859
  init_database_wrapper();
7044
7860
  init_schema();
7045
- import { and as and18, eq as eq25 } from "drizzle-orm";
7861
+ import { and as and19, eq as eq24 } from "drizzle-orm";
7046
7862
 
7047
7863
  // src/db/repositories/sessions.ts
7048
7864
  init_esm_shims();
7049
7865
  init_types2();
7050
7866
  init_config_manager();
7051
7867
  init_ids();
7052
- import { and as and17, desc as desc5, eq as eq24, inArray as inArray5, like as like12, or as or7, sql as sql12 } from "drizzle-orm";
7868
+ import { and as and18, desc as desc5, eq as eq23, inArray as inArray7, like as like13, or as or8, sql as sql11 } from "drizzle-orm";
7869
+ init_database_wrapper();
7870
+ init_schema();
7871
+
7872
+ // src/db/repositories/session-relationships.ts
7873
+ init_esm_shims();
7874
+ init_ids();
7053
7875
  init_database_wrapper();
7054
7876
  init_schema();
7877
+ import { and as and20, eq as eq25, inArray as inArray8, or as or9 } from "drizzle-orm";
7055
7878
 
7056
7879
  // src/db/repositories/tasks.ts
7057
7880
  init_esm_shims();
@@ -7059,7 +7882,7 @@ init_types2();
7059
7882
  init_ids();
7060
7883
  init_database_wrapper();
7061
7884
  init_schema();
7062
- import { eq as eq26, inArray as inArray6, like as like13, sql as sql13 } from "drizzle-orm";
7885
+ import { and as and21, eq as eq26, inArray as inArray9, like as like14, sql as sql12 } from "drizzle-orm";
7063
7886
 
7064
7887
  // src/db/repositories/thread-session-map.ts
7065
7888
  init_esm_shims();
@@ -7067,27 +7890,28 @@ init_types2();
7067
7890
  init_ids();
7068
7891
  init_database_wrapper();
7069
7892
  init_schema();
7070
- import { and as and19, eq as eq27, like as like14, lt as lt2 } from "drizzle-orm";
7893
+ import { and as and22, eq as eq27, like as like15, lt as lt2 } from "drizzle-orm";
7071
7894
 
7072
7895
  // src/db/repositories/user-api-keys.ts
7073
7896
  init_esm_shims();
7074
7897
  init_ids();
7075
7898
  init_database_wrapper();
7076
7899
  init_schema();
7900
+ init_tenant_context();
7077
7901
  import { randomBytes as randomBytes3 } from "crypto";
7078
- import bcrypt2 from "bcryptjs";
7079
- import { and as and20, eq as eq28 } from "drizzle-orm";
7902
+ import bcrypt from "bcryptjs";
7903
+ import { and as and23, eq as eq28 } from "drizzle-orm";
7080
7904
 
7081
7905
  // src/db/repositories/user-mcp-oauth-tokens.ts
7082
7906
  init_esm_shims();
7083
7907
  init_database_wrapper();
7084
7908
  init_schema();
7085
- import { and as and21, eq as eq29, isNull as isNull6 } from "drizzle-orm";
7909
+ import { and as and24, eq as eq29, isNull as isNull7 } from "drizzle-orm";
7086
7910
 
7087
7911
  // src/db/repositories/users.ts
7088
7912
  init_esm_shims();
7089
7913
  init_types2();
7090
- import { eq as eq30, like as like15 } from "drizzle-orm";
7914
+ import { eq as eq30, like as like16, sql as sql13 } from "drizzle-orm";
7091
7915
  init_ids();
7092
7916
  init_database_wrapper();
7093
7917
  init_schema();
@@ -7112,7 +7936,12 @@ var UsersRepository = class {
7112
7936
  unix_username: row.unix_username ?? void 0,
7113
7937
  onboarding_completed: row.onboarding_completed,
7114
7938
  must_change_password: row.must_change_password,
7939
+ tokens_valid_after: row.tokens_valid_after ? new Date(row.tokens_valid_after) : void 0,
7940
+ avatar_url: row.data.avatar_url ?? row.data.avatar,
7115
7941
  avatar: row.data.avatar,
7942
+ avatar_source: row.data.avatar_source,
7943
+ avatar_source_id: row.data.avatar_source_id,
7944
+ avatar_synced_at: row.data.avatar_synced_at,
7116
7945
  preferences: row.data.preferences,
7117
7946
  // Convert encrypted per-tool credential blobs into boolean presence flags.
7118
7947
  agentic_tools: toAgenticToolsStatus(row.data.agentic_tools),
@@ -7156,8 +7985,14 @@ var UsersRepository = class {
7156
7985
  role: user.role ?? "member",
7157
7986
  unix_username: user.unix_username ?? null,
7158
7987
  onboarding_completed: user.onboarding_completed ?? false,
7988
+ must_change_password: user.must_change_password ?? false,
7989
+ tokens_valid_after: user.tokens_valid_after ? new Date(user.tokens_valid_after) : null,
7159
7990
  data: {
7991
+ avatar_url: user.avatar_url,
7160
7992
  avatar: user.avatar,
7993
+ avatar_source: user.avatar_source,
7994
+ avatar_source_id: user.avatar_source_id,
7995
+ avatar_synced_at: user.avatar_synced_at,
7161
7996
  preferences: user.preferences,
7162
7997
  // Encrypted per-tool credentials. Only forwarded when caller passes the
7163
7998
  // raw shape (internal credential mutators); regular updates leave it undefined,
@@ -7179,7 +8014,7 @@ var UsersRepository = class {
7179
8014
  */
7180
8015
  async resolveId(id) {
7181
8016
  return resolveByShortIdPrefix(id, "User", async (pattern) => {
7182
- const rows = await select(this.db).from(users3).where(like15(users3.user_id, pattern)).limit(RESOLVE_SHORT_ID_FETCH_LIMIT).all();
8017
+ const rows = await select(this.db).from(users3).where(like16(users3.user_id, pattern)).limit(RESOLVE_SHORT_ID_FETCH_LIMIT).all();
7183
8018
  return rows.map((r) => r.user_id);
7184
8019
  });
7185
8020
  }
@@ -7244,6 +8079,35 @@ var UsersRepository = class {
7244
8079
  }
7245
8080
  return this.rowToUser(result);
7246
8081
  }
8082
+ /**
8083
+ * Find user by email for external identity providers.
8084
+ *
8085
+ * Agor intentionally keeps exact/case-sensitive email lookup semantics for
8086
+ * auth paths because the schema historically allowed case-distinct emails.
8087
+ * External providers such as Slack and GitHub treat email addresses as a
8088
+ * canonical identity hint, so their alignment path needs a case-insensitive
8089
+ * match. Prefer an exact match when present; otherwise return a
8090
+ * case-insensitive match only when it is unambiguous.
8091
+ */
8092
+ async findByEmailForAlignment(email) {
8093
+ const normalizedEmail = email.trim().toLowerCase();
8094
+ if (!normalizedEmail) return null;
8095
+ const exact = await this.findByEmail(normalizedEmail);
8096
+ if (exact) return exact;
8097
+ const results = await select(this.db).from(users3).where(sql13`LOWER(${users3.email}) = ${normalizedEmail}`).all();
8098
+ if (results.length !== 1) {
8099
+ if (results.length > 1) {
8100
+ console.warn(
8101
+ `[users] Ambiguous case-insensitive email alignment for ${normalizedEmail}: ${results.map((row) => {
8102
+ const userRow = row;
8103
+ return `${shortId(userRow.user_id)}:${userRow.email}`;
8104
+ }).join(", ")}`
8105
+ );
8106
+ }
8107
+ return null;
8108
+ }
8109
+ return this.rowToUser(results[0]);
8110
+ }
7247
8111
  /**
7248
8112
  * Find all users
7249
8113
  */
@@ -7412,130 +8276,11 @@ var UsersRepository = class {
7412
8276
  }
7413
8277
  };
7414
8278
 
7415
- // src/db/index.ts
7416
- init_schema();
7417
-
7418
- // src/db/session-guard.ts
7419
- init_esm_shims();
7420
- init_ids();
7421
-
7422
- // src/db/index.ts
7423
- init_user_utils();
7424
- var compare = bcryptjs.compare;
7425
- var hash = bcryptjs.hash;
7426
-
7427
- // src/config/key-resolver.ts
7428
- init_database_wrapper();
7429
- init_schema();
7430
- init_ids();
7431
- init_config_manager();
7432
- var DEBUG_KEY_RESOLUTION = process.env.AGOR_DEBUG_KEY_RESOLUTION === "1" || process.env.DEBUG?.includes("key-resolution");
7433
-
7434
- // src/config/proxies-resolver.ts
7435
- init_esm_shims();
7436
-
7437
- // src/config/repo-list.ts
7438
- init_esm_shims();
7439
-
7440
- // src/config/repo-reference.ts
7441
- init_esm_shims();
7442
- var REPO_SLUG_PATTERN = /^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/;
7443
-
7444
- // src/config/resolved-config-slice.ts
7445
- init_esm_shims();
7446
- import { z } from "zod";
7447
- var ResolvedConfigSliceSchema = z.object({
7448
- /** From `config.execution.*` */
7449
- execution: z.object({
7450
- permission_timeout_ms: z.number().int().nonnegative().optional(),
7451
- executor_heartbeat: z.object({
7452
- enabled: z.boolean(),
7453
- interval_ms: z.number().int().positive()
7454
- }).optional()
7455
- }).optional(),
7456
- /** From `config.opencode.*` */
7457
- opencode: z.object({
7458
- serverUrl: z.string().optional()
7459
- }).optional(),
7460
- /** From `config.daemon.*` (selected fields only) */
7461
- daemon: z.object({
7462
- host_ip_address: z.string().optional()
7463
- }).optional()
7464
- });
7465
-
7466
- // src/config/resource-schemas.ts
7467
- init_esm_shims();
7468
- import { z as z2 } from "zod";
7469
- var uuidSchema = z2.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, "Must be a valid UUID");
7470
- var repoSlugSchema = z2.string().regex(
7471
- REPO_SLUG_PATTERN,
7472
- 'Must be org/name format with alphanumeric, hyphens, underscores, or dots (e.g., "my-org/my-repo")'
7473
- );
7474
- var enforcedAgentConfigSchema = z2.object({
7475
- agentic_tool: z2.enum(["claude-code", "claude-code-cli", "codex", "gemini", "opencode", "copilot", "cursor"]).optional(),
7476
- permission_mode: z2.string().optional(),
7477
- model: z2.string().optional(),
7478
- mcp_server_ids: z2.array(z2.string()).optional()
7479
- });
7480
- var resourceRepoConfigSchema = z2.object({
7481
- repo_id: uuidSchema,
7482
- slug: repoSlugSchema,
7483
- remote_url: z2.string().optional(),
7484
- repo_type: z2.enum(["remote", "local"]).default("remote"),
7485
- default_branch: z2.string().optional(),
7486
- shallow: z2.boolean().optional()
7487
- }).refine((data) => data.repo_type !== "remote" || data.remote_url, {
7488
- message: 'remote_url is required when repo_type is "remote"',
7489
- path: ["remote_url"]
7490
- });
7491
- var resourceBranchConfigSchema = z2.object({
7492
- branch_id: uuidSchema,
7493
- name: z2.string().min(1, "Branch name is required"),
7494
- ref: z2.string().min(1, "Git ref is required"),
7495
- ref_type: z2.enum(["branch", "tag"]).optional(),
7496
- others_can: z2.enum(["none", "view", "session", "prompt", "all"]).optional(),
7497
- mcp_server_ids: z2.array(z2.string()).optional(),
7498
- repo: repoSlugSchema,
7499
- readonly: z2.boolean().optional(),
7500
- agent: enforcedAgentConfigSchema.optional()
7501
- });
7502
- var resourceUserConfigSchema = z2.object({
7503
- user_id: uuidSchema,
7504
- email: z2.string().email("Must be a valid email address"),
7505
- name: z2.string().optional(),
7506
- role: z2.enum(["superadmin", "admin", "member", "viewer"]).default("member"),
7507
- unix_username: z2.string().optional(),
7508
- password: z2.string().optional()
7509
- });
7510
- var daemonResourcesConfigSchema = z2.object({
7511
- repos: z2.array(resourceRepoConfigSchema).optional(),
7512
- branches: z2.array(resourceBranchConfigSchema).optional(),
7513
- users: z2.array(resourceUserConfigSchema).optional()
7514
- });
7515
-
7516
- // src/config/resource-sync.ts
7517
- init_esm_shims();
7518
-
7519
- // src/config/security-resolver.ts
7520
- init_esm_shims();
7521
- var DEFAULT_GIT_CONFIG_PARAMETERS = Object.freeze([
7522
- "transfer.credentialsInUrl=die",
7523
- "protocol.file.allow=user",
7524
- "protocol.ext.allow=never",
7525
- "core.protectHFS=true",
7526
- "core.protectNTFS=true"
7527
- ]);
7528
-
7529
- // src/config/index.ts
7530
- init_types();
7531
-
7532
8279
  // src/git/index.ts
8280
+ var git_exports = {};
7533
8281
  init_esm_shims();
7534
- init_config_manager();
7535
- import { existsSync } from "fs";
7536
- import { mkdir, readFile, stat, writeFile } from "fs/promises";
7537
- import { basename, dirname as dirname2, isAbsolute, join as join3, resolve } from "path";
7538
- import { simpleGit } from "simple-git";
8282
+ __reExport(git_exports, git_star);
8283
+ import * as git_star from "@agor/git";
7539
8284
 
7540
8285
  // src/unix/run-as-user.ts
7541
8286
  init_esm_shims();
@@ -7891,116 +8636,13 @@ function buildSpawnArgs(command, args = [], options) {
7891
8636
  };
7892
8637
  }
7893
8638
 
7894
- // src/git/index.ts
7895
- init_config_manager();
7896
- var cachedGitBinary;
7897
- function getGitBinary() {
7898
- if (cachedGitBinary !== void 0) return cachedGitBinary;
7899
- const commonPaths = [
7900
- "/opt/homebrew/bin/git",
7901
- // Homebrew on Apple Silicon
7902
- "/usr/local/bin/git",
7903
- // Homebrew on Intel
7904
- "/usr/bin/git"
7905
- // System git (Docker and Linux)
7906
- ];
7907
- for (const path3 of commonPaths) {
7908
- if (existsSync(path3)) {
7909
- cachedGitBinary = path3;
7910
- return path3;
7911
- }
7912
- }
7913
- cachedGitBinary = "git";
7914
- return cachedGitBinary;
7915
- }
7916
- function isLikelyGitToken(token) {
7917
- return /^[A-Za-z0-9_-]{20,255}$/.test(token);
7918
- }
7919
- var DEFAULT_AUTH_HEADER_HOST = "github.com";
7920
- function buildGitConfigEnv(entries) {
7921
- if (entries.length === 0) return {};
7922
- const out = {
7923
- GIT_CONFIG_COUNT: String(entries.length)
7924
- };
7925
- for (let i = 0; i < entries.length; i++) {
7926
- const [key, value] = entries[i];
7927
- out[`GIT_CONFIG_KEY_${i}`] = key;
7928
- out[`GIT_CONFIG_VALUE_${i}`] = value;
7929
- }
7930
- return out;
7931
- }
7932
- function buildAuthHeaderEnv(token, host = DEFAULT_AUTH_HEADER_HOST) {
7933
- if (!token) return [];
7934
- if (!isLikelyGitToken(token)) {
7935
- console.warn(
7936
- "\u{1F511} Skipping http.extraheader: token does not match expected shape. Tokens must match /^[A-Za-z0-9_-]{20,255}$/. Re-save the token to enable the auth header."
7937
- );
7938
- return [];
7939
- }
7940
- const credential = Buffer.from(`x-access-token:${token}`, "utf8").toString("base64");
7941
- const key = `http.https://${host}/.extraheader`;
7942
- return [[key, `Authorization: Basic ${credential}`]];
7943
- }
7944
- function createGit(baseDir, env, authHost) {
7945
- const gitBinary = getGitBinary();
7946
- const config = [];
7947
- const rawToken = env?.GITHUB_TOKEN ?? env?.GH_TOKEN;
7948
- const authConfigEntries = buildAuthHeaderEnv(rawToken, authHost ?? DEFAULT_AUTH_HEADER_HOST);
7949
- let spawnEnv;
7950
- if (env || authConfigEntries.length > 0) {
7951
- spawnEnv = {
7952
- ...process.env,
7953
- ...env ?? {},
7954
- // Inheritance kill (GLOBAL only): ignore the daemon user's
7955
- // ~/.gitconfig. /etc/gitconfig is intentionally NOT killed — it is
7956
- // admin-policy territory (CA bundles, proxies). See block comment.
7957
- GIT_CONFIG_GLOBAL: "/dev/null",
7958
- // Fail fast instead of blocking on an interactive credential prompt
7959
- // (which would hang the daemon).
7960
- GIT_TERMINAL_PROMPT: "0",
7961
- // Inject http.extraheader (and any future server-constructed config)
7962
- // via the env-var protocol so it never lands on argv.
7963
- ...buildGitConfigEnv(authConfigEntries)
7964
- };
7965
- }
7966
- const git = simpleGit({
7967
- baseDir,
7968
- binary: gitBinary,
7969
- config,
7970
- unsafe: {
7971
- // simple-git's scanner blocks spawning when these env vars / config keys
7972
- // are present. We own the daemon env (in strict mode it's the user's own
7973
- // env) and inject GIT_CONFIG_* ourselves — opting in here mirrors what a
7974
- // direct `git` invocation on the same machine does.
7975
- allowUnsafeSshCommand: true,
7976
- allowUnsafeConfigPaths: true,
7977
- allowUnsafeConfigEnvCount: true,
7978
- allowUnsafeEditor: true,
7979
- allowUnsafeAskPass: true,
7980
- allowUnsafePager: true,
7981
- allowUnsafeGitProxy: true,
7982
- allowUnsafeTemplateDir: true,
7983
- allowUnsafeDiffExternal: true
7984
- }
7985
- });
7986
- if (spawnEnv) {
7987
- git.env(spawnEnv);
7988
- }
7989
- return { git };
7990
- }
7991
- async function getCurrentSha(repoPath) {
7992
- const { git } = createGit(repoPath);
7993
- const log = await git.log({ maxCount: 1 });
7994
- return log.latest?.hash || "";
7995
- }
7996
-
7997
8639
  // src/unix/user-env-file.ts
7998
8640
  init_esm_shims();
7999
8641
  import { execFileSync } from "child_process";
8000
8642
  import { randomBytes as randomBytes4 } from "crypto";
8001
8643
  import { unlinkSync } from "fs";
8002
8644
  import { tmpdir } from "os";
8003
- import { join as join4 } from "path";
8645
+ import { join } from "path";
8004
8646
 
8005
8647
  // src/unix/secret-env.ts
8006
8648
  init_esm_shims();
@@ -8043,7 +8685,7 @@ function writeUserEnvFile(asUser, env) {
8043
8685
  throw new Error(`writeUserEnvFile: invalid Unix username: ${JSON.stringify(asUser)}`);
8044
8686
  }
8045
8687
  const nonce = randomBytes4(16).toString("hex");
8046
- const envFilePath = join4(tmpdir(), `${ENV_FILE_PREFIX}${nonce}`);
8688
+ const envFilePath = join(tmpdir(), `${ENV_FILE_PREFIX}${nonce}`);
8047
8689
  const lines = [];
8048
8690
  for (const [key, value] of Object.entries(env)) {
8049
8691
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
@@ -8109,7 +8751,7 @@ function prepareImpersonationEnv(options) {
8109
8751
  // src/unix/environment-command-spawn.ts
8110
8752
  async function captureBranchBuildSha(branchPath2) {
8111
8753
  try {
8112
- const sha = await getCurrentSha(branchPath2);
8754
+ const sha = await (0, git_exports.getCurrentSha)(branchPath2);
8113
8755
  return sha ? sha.slice(0, 7) : void 0;
8114
8756
  } catch {
8115
8757
  return void 0;
@@ -8776,6 +9418,30 @@ var UnixIntegrationService = class {
8776
9418
  this.usersRepo = new UsersRepository(db);
8777
9419
  this.repoRepo = new RepoRepository(db);
8778
9420
  }
9421
+ async getUnixUsernamesForUsers(userIds) {
9422
+ const unixUsernames = /* @__PURE__ */ new Set();
9423
+ for (const userId of userIds) {
9424
+ const user = await this.usersRepo.findById(userId);
9425
+ if (user?.unix_username) {
9426
+ unixUsernames.add(user.unix_username);
9427
+ }
9428
+ }
9429
+ return unixUsernames;
9430
+ }
9431
+ async reconcileUnixGroupMembers(groupName, allowedUnixUsernames, options) {
9432
+ if (this.config.daemonUser) {
9433
+ allowedUnixUsernames.add(this.config.daemonUser);
9434
+ }
9435
+ const result = await this.executor.exec(UnixGroupCommands.listGroupMembers(groupName));
9436
+ const currentMembers = result.stdout.trim().split(",").filter(Boolean);
9437
+ for (const unixUsername of currentMembers) {
9438
+ if (allowedUnixUsernames.has(unixUsername)) continue;
9439
+ console.log(
9440
+ `[UnixIntegration] Removing stale ${options.label} group member ${unixUsername} from ${groupName}`
9441
+ );
9442
+ await this.executor.exec(UnixGroupCommands.removeUserFromGroup(unixUsername, groupName));
9443
+ }
9444
+ }
8779
9445
  /**
8780
9446
  * Get the configured daemon user
8781
9447
  *
@@ -9019,19 +9685,26 @@ var UnixIntegrationService = class {
9019
9685
  /**
9020
9686
  * Initialize Unix group for an existing branch
9021
9687
  *
9022
- * Creates group and adds all current owners.
9688
+ * Creates group and adds all users with explicit filesystem access.
9023
9689
  *
9024
9690
  * @param branchId - Branch ID
9025
9691
  */
9026
9692
  async initializeBranchGroup(branchId) {
9027
9693
  const groupName = await this.createBranchGroup(branchId);
9028
- const ownerIds = await this.branchRepo.getOwners(branchId);
9029
- for (const ownerId of ownerIds) {
9030
- await this.addUserToBranchGroup(branchId, ownerId);
9694
+ const userIds = await this.branchRepo.findExplicitFsAccessUserIds(branchId);
9695
+ for (const userId of userIds) {
9696
+ await this.addUserToBranchGroup(branchId, userId);
9031
9697
  }
9698
+ await this.reconcileUnixGroupMembers(groupName, await this.getUnixUsernamesForUsers(userIds), {
9699
+ label: "branch"
9700
+ });
9032
9701
  console.log(
9033
- `[UnixIntegration] Initialized group ${groupName} with ${ownerIds.length} owner(s)`
9702
+ `[UnixIntegration] Initialized group ${groupName} with ${userIds.length} explicit filesystem user(s)`
9034
9703
  );
9704
+ const branch = await this.branchRepo.findById(branchId);
9705
+ if (branch?.repo_id) {
9706
+ await this.syncRepo(branch.repo_id);
9707
+ }
9035
9708
  }
9036
9709
  // ============================================================
9037
9710
  // REPO GROUP MANAGEMENT
@@ -9263,8 +9936,8 @@ var UnixIntegrationService = class {
9263
9936
  /**
9264
9937
  * Check if a user should be in a repo's Unix group
9265
9938
  *
9266
- * A user should be in the repo group if they have ownership
9267
- * of ANY branch in that repo.
9939
+ * A user should be in the repo group if they have explicit filesystem access
9940
+ * to ANY branch in that repo.
9268
9941
  *
9269
9942
  * @param repoId - Repo ID
9270
9943
  * @param userId - User ID to check
@@ -9273,8 +9946,8 @@ var UnixIntegrationService = class {
9273
9946
  async shouldUserBeInRepoGroup(repoId, userId) {
9274
9947
  const branches4 = await this.branchRepo.findAll({ repo_id: repoId });
9275
9948
  for (const wt of branches4) {
9276
- const isOwner = await this.branchRepo.isOwner(wt.branch_id, userId);
9277
- if (isOwner) {
9949
+ const userIds = await this.branchRepo.findExplicitFsAccessUserIds(wt.branch_id);
9950
+ if (userIds.includes(userId)) {
9278
9951
  return true;
9279
9952
  }
9280
9953
  }
@@ -9283,33 +9956,36 @@ var UnixIntegrationService = class {
9283
9956
  /**
9284
9957
  * Initialize Unix group for an existing repo
9285
9958
  *
9286
- * Creates group, sets .git permissions, and adds all users who
9287
- * own any branch in the repo.
9959
+ * Creates group, sets .git permissions, and adds all users who have explicit
9960
+ * filesystem access to any branch in the repo.
9288
9961
  *
9289
9962
  * @param repoId - Repo ID
9290
9963
  */
9291
9964
  async initializeRepoGroup(repoId) {
9292
9965
  const groupName = await this.createRepoGroup(repoId);
9293
9966
  const branches4 = await this.branchRepo.findAll({ repo_id: repoId });
9294
- const ownerIds = /* @__PURE__ */ new Set();
9967
+ const userIds = /* @__PURE__ */ new Set();
9295
9968
  for (const wt of branches4) {
9296
- const wtOwners = await this.branchRepo.getOwners(wt.branch_id);
9297
- for (const ownerId of wtOwners) {
9298
- ownerIds.add(ownerId);
9969
+ const branchUserIds = await this.branchRepo.findExplicitFsAccessUserIds(wt.branch_id);
9970
+ for (const userId of branchUserIds) {
9971
+ userIds.add(userId);
9299
9972
  }
9300
9973
  }
9301
- for (const ownerId of ownerIds) {
9302
- await this.addUserToRepoGroup(repoId, ownerId);
9974
+ for (const userId of userIds) {
9975
+ await this.addUserToRepoGroup(repoId, userId);
9303
9976
  }
9977
+ await this.reconcileUnixGroupMembers(groupName, await this.getUnixUsernamesForUsers(userIds), {
9978
+ label: "repo"
9979
+ });
9304
9980
  console.log(
9305
- `[UnixIntegration] Initialized repo group ${groupName} with ${ownerIds.size} unique owner(s)`
9981
+ `[UnixIntegration] Initialized repo group ${groupName} with ${userIds.size} unique filesystem user(s)`
9306
9982
  );
9307
9983
  }
9308
9984
  /**
9309
9985
  * Full sync for a repo
9310
9986
  *
9311
9987
  * Ensures repo group exists, .git permissions are set, and all
9312
- * branch owners are in the repo group.
9988
+ * branch filesystem-access users are in the repo group.
9313
9989
  *
9314
9990
  * @param repoId - Repo ID
9315
9991
  */
@@ -9317,15 +9993,23 @@ var UnixIntegrationService = class {
9317
9993
  console.log(`[UnixIntegration] Full sync for repo ${shortId(repoId)}`);
9318
9994
  await this.createRepoGroup(repoId);
9319
9995
  const branches4 = await this.branchRepo.findAll({ repo_id: repoId });
9320
- const ownerIds = /* @__PURE__ */ new Set();
9996
+ const userIds = /* @__PURE__ */ new Set();
9321
9997
  for (const wt of branches4) {
9322
- const wtOwners = await this.branchRepo.getOwners(wt.branch_id);
9323
- for (const ownerId of wtOwners) {
9324
- ownerIds.add(ownerId);
9998
+ const branchUserIds = await this.branchRepo.findExplicitFsAccessUserIds(wt.branch_id);
9999
+ for (const userId of branchUserIds) {
10000
+ userIds.add(userId);
9325
10001
  }
9326
10002
  }
9327
- for (const ownerId of ownerIds) {
9328
- await this.addUserToRepoGroup(repoId, ownerId);
10003
+ for (const userId of userIds) {
10004
+ await this.addUserToRepoGroup(repoId, userId);
10005
+ }
10006
+ const repo = await this.repoRepo.findById(repoId);
10007
+ if (repo?.unix_group) {
10008
+ await this.reconcileUnixGroupMembers(
10009
+ repo.unix_group,
10010
+ await this.getUnixUsernamesForUsers(userIds),
10011
+ { label: "repo" }
10012
+ );
9329
10013
  }
9330
10014
  }
9331
10015
  // ============================================================
@@ -9602,16 +10286,28 @@ var UnixIntegrationService = class {
9602
10286
  /**
9603
10287
  * Full sync for a branch
9604
10288
  *
9605
- * Ensures group exists, all owners are in group, and symlinks are created.
10289
+ * Ensures group exists, all explicit filesystem-access users are in group,
10290
+ * and symlinks are created.
9606
10291
  *
9607
10292
  * @param branchId - Branch ID
9608
10293
  */
9609
10294
  async syncBranch(branchId) {
9610
10295
  console.log(`[UnixIntegration] Full sync for branch ${shortId(branchId)}`);
9611
10296
  await this.createBranchGroup(branchId);
9612
- const ownerIds = await this.branchRepo.getOwners(branchId);
9613
- for (const ownerId of ownerIds) {
9614
- await this.addUserToBranchGroup(branchId, ownerId);
10297
+ const userIds = await this.branchRepo.findExplicitFsAccessUserIds(branchId);
10298
+ for (const userId of userIds) {
10299
+ await this.addUserToBranchGroup(branchId, userId);
10300
+ }
10301
+ const branch = await this.branchRepo.findById(branchId);
10302
+ if (branch?.unix_group) {
10303
+ await this.reconcileUnixGroupMembers(
10304
+ branch.unix_group,
10305
+ await this.getUnixUsernamesForUsers(userIds),
10306
+ { label: "branch" }
10307
+ );
10308
+ }
10309
+ if (branch?.repo_id) {
10310
+ await this.syncRepo(branch.repo_id);
9615
10311
  }
9616
10312
  }
9617
10313
  /**